@rancher/shell 2.0.1 → 2.0.2-rc.1
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 +51 -26
- package/assets/translations/zh-hans.yaml +1 -0
- package/components/AssignTo.vue +2 -0
- package/components/Questions/index.vue +2 -2
- package/components/auth/RoleDetailEdit.vue +5 -4
- package/components/form/Members/ClusterPermissionsEditor.vue +1 -1
- package/components/form/ProjectMemberEditor.vue +1 -1
- package/components/form/ResourceLabeledSelect.vue +11 -3
- package/components/form/labeled-select-utils/labeled-select.utils.ts +1 -1
- package/config/pagination-table-headers.js +5 -4
- package/config/roles.ts +34 -19
- package/config/router/navigation-guards/attempt-first-login.js +1 -1
- package/config/router/navigation-guards/authentication.js +1 -1
- package/config/router/navigation-guards/i18n.js +1 -1
- package/config/router/navigation-guards/index.js +2 -1
- package/config/router/navigation-guards/load-initial-settings.js +1 -1
- package/config/router/navigation-guards/runtime-extension-route.js +31 -0
- package/config/router/routes.js +10 -1
- package/config/uiplugins.js +130 -61
- package/core/plugin.ts +5 -0
- package/core/plugins.js +7 -1
- package/edit/provisioning.cattle.io.cluster/__tests__/Basics.test.ts +86 -13
- package/edit/provisioning.cattle.io.cluster/__tests__/DirectoryConfig.test.ts +3 -134
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +209 -0
- package/edit/provisioning.cattle.io.cluster/index.vue +8 -4
- package/edit/provisioning.cattle.io.cluster/rke2.vue +115 -17
- package/edit/provisioning.cattle.io.cluster/tabs/AddOnAdditionalManifest.vue +50 -0
- package/edit/provisioning.cattle.io.cluster/tabs/AddOnConfig.vue +29 -64
- package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +42 -3
- package/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue +22 -86
- package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +8 -2
- package/edit/provisioning.cattle.io.cluster/tabs/registries/__tests__/RegistryConfigs.test.ts +61 -0
- package/initialize/entry-helpers.js +4 -21
- package/mixins/__tests__/chart.test.ts +4 -1
- package/mixins/chart.js +30 -14
- package/models/__tests__/apps.deployment.test.ts +93 -0
- package/models/apps.deployment.js +18 -4
- package/models/management.cattle.io.cluster.js +2 -2
- package/models/management.cattle.io.user.js +3 -3
- package/models/nodedriver.js +5 -0
- package/models/provisioning.cattle.io.cluster.js +4 -0
- package/package.json +1 -1
- package/pages/404.vue +15 -0
- package/pages/auth/login.vue +4 -1
- package/pages/auth/setup.vue +4 -1
- package/pages/c/_cluster/explorer/index.vue +5 -0
- package/pages/c/_cluster/manager/jwt.authentication/index.vue +10 -4
- package/pages/c/_cluster/settings/performance.vue +2 -2
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +7 -10
- package/pages/c/_cluster/uiplugins/index.vue +24 -16
- package/pages/home.vue +1 -13
- package/plugins/dashboard-store/actions.js +1 -1
- package/plugins/dashboard-store/getters.js +1 -1
- package/plugins/steve/__tests__/getters.test.ts +5 -5
- package/plugins/steve/getters.js +6 -4
- package/plugins/steve/hybrid-class.js +1 -5
- package/scripts/extension/helm/charts/ui-plugin-server/Chart.yaml +1 -1
- package/scripts/publish-shell.sh +53 -55
- package/scripts/test-plugins-build.sh +45 -39
- package/shell/types/shell/index.d.ts +2 -0
- package/store/type-map.js +4 -2
- package/types/store/pagination.types.ts +1 -1
- package/utils/cluster.js +9 -0
- package/utils/settings.ts +3 -1
- package/creators/app/app.package.json +0 -14
- package/creators/app/files/.eslintignore +0 -16
- package/creators/app/files/.eslintrc.js +0 -173
- package/creators/app/files/.gitignore +0 -70
- package/creators/app/files/.gitlab-ci.yml +0 -14
- package/creators/app/files/.vscode/settings.json +0 -21
- package/creators/app/files/babel.config.js +0 -1
- package/creators/app/files/tsconfig.json +0 -42
- package/creators/app/files/vue.config.js +0 -6
- package/creators/app/init +0 -120
- package/creators/app/package.json +0 -25
- package/creators/pkg/files/.github/workflows/build-extension-catalog.yml +0 -24
- package/creators/pkg/files/.github/workflows/build-extension-charts.yml +0 -22
- package/creators/pkg/files/babel.config.js +0 -1
- package/creators/pkg/files/index.ts +0 -14
- package/creators/pkg/files/tsconfig.json +0 -53
- package/creators/pkg/files/vue.config.js +0 -1
- package/creators/pkg/init +0 -286
- package/creators/pkg/package.json +0 -19
- package/creators/pkg/pkg.package.json +0 -21
- package/creators/pkg/vue-shim.ts +0 -4
- package/creators/update/init +0 -56
- package/creators/update/package.json +0 -20
- package/creators/update/upgrade +0 -56
- package/types/shell/index.d.ts +0 -4585
|
@@ -3,7 +3,7 @@ import { Banner } from '@components/Banner';
|
|
|
3
3
|
|
|
4
4
|
import Questions from '@shell/components/Questions';
|
|
5
5
|
import YamlEditor from '@shell/components/YamlEditor';
|
|
6
|
-
import {
|
|
6
|
+
import { labelForAddon } from '@shell/utils/cluster';
|
|
7
7
|
import { _EDIT } from '@shell/config/query-params';
|
|
8
8
|
|
|
9
9
|
export default {
|
|
@@ -29,8 +29,8 @@ export default {
|
|
|
29
29
|
required: true,
|
|
30
30
|
},
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
type:
|
|
32
|
+
addonVersion: {
|
|
33
|
+
type: Object,
|
|
34
34
|
required: false,
|
|
35
35
|
default: null
|
|
36
36
|
},
|
|
@@ -50,28 +50,15 @@ export default {
|
|
|
50
50
|
|
|
51
51
|
},
|
|
52
52
|
|
|
53
|
+
data() {
|
|
54
|
+
return { labelForAddon };
|
|
55
|
+
},
|
|
56
|
+
|
|
53
57
|
computed: {
|
|
54
|
-
additionalManifest: {
|
|
55
|
-
get() {
|
|
56
|
-
return this.value.spec.rkeConfig.additionalManifest;
|
|
57
|
-
},
|
|
58
|
-
set(neu) {
|
|
59
|
-
this.$emit('additional-manifest-changed', neu);
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
58
|
isEdit() {
|
|
63
59
|
return this.mode === _EDIT;
|
|
64
60
|
},
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
methods: {
|
|
68
|
-
|
|
69
|
-
labelForAddon(name) {
|
|
70
|
-
const fallback = `${ camelToTitle(name.replace(/^(rke|rke2|rancher)-/, '')) } Configuration`;
|
|
71
|
-
|
|
72
|
-
return this.$store.getters['i18n/withFallback'](`cluster.addonChart."${ name }"`, null, fallback);
|
|
73
|
-
},
|
|
74
|
-
},
|
|
61
|
+
}
|
|
75
62
|
};
|
|
76
63
|
</script>
|
|
77
64
|
|
|
@@ -84,54 +71,32 @@ export default {
|
|
|
84
71
|
{{ t('cluster.addOns.dependencyBanner') }}
|
|
85
72
|
</Banner>
|
|
86
73
|
<div
|
|
87
|
-
v-if="versionInfo &&
|
|
74
|
+
v-if="versionInfo && addonVersion"
|
|
88
75
|
:key="addonsRev"
|
|
89
76
|
>
|
|
90
|
-
<
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
:source="versionInfo[v.name]"
|
|
103
|
-
:target-namespace="value.metadata.namespace"
|
|
104
|
-
@updated="$emit('update-questions', v.name)"
|
|
105
|
-
/>
|
|
106
|
-
<YamlEditor
|
|
107
|
-
v-else
|
|
108
|
-
ref="yaml-values"
|
|
109
|
-
:value="initYamlEditor(v.name)"
|
|
110
|
-
:scrolling="true"
|
|
111
|
-
:as-object="true"
|
|
112
|
-
:editor-mode="mode === 'view' ? 'VIEW_CODE' : 'EDIT_CODE'"
|
|
113
|
-
:hide-preview-buttons="true"
|
|
114
|
-
@input="data => $emit('update-values', v.name, data)"
|
|
115
|
-
/>
|
|
116
|
-
<div class="spacer" />
|
|
117
|
-
</div>
|
|
118
|
-
</div>
|
|
119
|
-
|
|
120
|
-
<div>
|
|
121
|
-
<h3>
|
|
122
|
-
{{ t('cluster.addOns.additionalManifest.title') }}
|
|
123
|
-
<i
|
|
124
|
-
v-clean-tooltip="t('cluster.addOns.additionalManifest.tooltip')"
|
|
125
|
-
class="icon icon-info"
|
|
126
|
-
/>
|
|
127
|
-
</h3>
|
|
77
|
+
<h3>{{ labelForAddon(addonVersion.name) }}</h3>
|
|
78
|
+
<Questions
|
|
79
|
+
v-if="versionInfo[addonVersion.name] && versionInfo[addonVersion.name].questions && addonVersion.name && userChartValuesTemp[addonVersion.name]"
|
|
80
|
+
v-model="userChartValuesTemp[addonVersion.name]"
|
|
81
|
+
:emit="true"
|
|
82
|
+
in-store="management"
|
|
83
|
+
:mode="mode"
|
|
84
|
+
:tabbed="false"
|
|
85
|
+
:source="versionInfo[addonVersion.name]"
|
|
86
|
+
:target-namespace="value.metadata.namespace"
|
|
87
|
+
@updated="$emit('update-questions', addonVersion.name)"
|
|
88
|
+
/>
|
|
128
89
|
<YamlEditor
|
|
129
|
-
|
|
130
|
-
|
|
90
|
+
v-else
|
|
91
|
+
ref="yaml-values"
|
|
92
|
+
:value="initYamlEditor(addonVersion.name)"
|
|
93
|
+
:scrolling="true"
|
|
94
|
+
:as-object="true"
|
|
131
95
|
:editor-mode="mode === 'view' ? 'VIEW_CODE' : 'EDIT_CODE'"
|
|
132
|
-
|
|
133
|
-
|
|
96
|
+
:hide-preview-buttons="true"
|
|
97
|
+
@input="data => $emit('update-values', addonVersion.name, data)"
|
|
134
98
|
/>
|
|
99
|
+
<div class="spacer" />
|
|
135
100
|
</div>
|
|
136
101
|
</div>
|
|
137
102
|
</template>
|
|
@@ -11,7 +11,7 @@ import LabeledSelect from '@shell/components/form/LabeledSelect';
|
|
|
11
11
|
import YamlEditor from '@shell/components/YamlEditor';
|
|
12
12
|
import { LEGACY } from '@shell/store/features';
|
|
13
13
|
import semver from 'semver';
|
|
14
|
-
import { _EDIT } from '@shell/config/query-params';
|
|
14
|
+
import { _CREATE, _EDIT } from '@shell/config/query-params';
|
|
15
15
|
|
|
16
16
|
const HARVESTER = 'harvester';
|
|
17
17
|
|
|
@@ -106,6 +106,14 @@ export default {
|
|
|
106
106
|
cloudProviderOptions: {
|
|
107
107
|
type: Array,
|
|
108
108
|
required: true
|
|
109
|
+
},
|
|
110
|
+
isAzureProviderUnsupported: {
|
|
111
|
+
type: Boolean,
|
|
112
|
+
required: true
|
|
113
|
+
},
|
|
114
|
+
canAzureMigrateOnEdit: {
|
|
115
|
+
type: Boolean,
|
|
116
|
+
required: true
|
|
109
117
|
}
|
|
110
118
|
},
|
|
111
119
|
|
|
@@ -377,9 +385,11 @@ export default {
|
|
|
377
385
|
},
|
|
378
386
|
|
|
379
387
|
canNotEditCloudProvider() {
|
|
380
|
-
|
|
388
|
+
if (!this.isEdit) {
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
381
391
|
|
|
382
|
-
return
|
|
392
|
+
return !this.canAzureMigrateOnEdit;
|
|
383
393
|
},
|
|
384
394
|
|
|
385
395
|
/**
|
|
@@ -387,6 +397,20 @@ export default {
|
|
|
387
397
|
*/
|
|
388
398
|
showCloudProviderAmazonAdditionalConfigWarning() {
|
|
389
399
|
return !!semver.gte(this.value.spec.kubernetesVersion, 'v1.27.0') && this.agentConfig?.['cloud-provider-name'] === 'aws';
|
|
400
|
+
},
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Display warning about unsupported Azure provider if k8s >= 1.30
|
|
404
|
+
*/
|
|
405
|
+
showCloudProviderUnsupportedAzureWarning() {
|
|
406
|
+
return this.showCloudProvider && this.mode === _CREATE && this.isAzureProviderUnsupported;
|
|
407
|
+
},
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Display warning about Azure provider migration from k8s versions >= 1.27 to External provider
|
|
411
|
+
*/
|
|
412
|
+
showCloudProviderMigrateAzureWarning() {
|
|
413
|
+
return this.showCloudProvider && this.mode === _EDIT && this.canAzureMigrateOnEdit;
|
|
390
414
|
}
|
|
391
415
|
},
|
|
392
416
|
|
|
@@ -423,6 +447,20 @@ export default {
|
|
|
423
447
|
v-clean-html="t('cluster.harvester.warning.cloudProvider.incompatible', null, true)"
|
|
424
448
|
/>
|
|
425
449
|
</Banner>
|
|
450
|
+
<Banner
|
|
451
|
+
v-if="showCloudProviderUnsupportedAzureWarning"
|
|
452
|
+
color="warning"
|
|
453
|
+
data-testid="clusterBasics__showCloudProviderUnsupportedAzureWarning"
|
|
454
|
+
>
|
|
455
|
+
<span v-clean-html="t('cluster.banner.cloudProviderUnsupportedAzure', {}, true)" />
|
|
456
|
+
</Banner>
|
|
457
|
+
<Banner
|
|
458
|
+
v-if="showCloudProviderMigrateAzureWarning"
|
|
459
|
+
color="warning"
|
|
460
|
+
data-testid="clusterBasics__showCloudProviderMigrateAzureWarning"
|
|
461
|
+
>
|
|
462
|
+
<span v-clean-html="t('cluster.banner.cloudProviderMigrateAzure', {}, true)" />
|
|
463
|
+
</Banner>
|
|
426
464
|
<Banner
|
|
427
465
|
v-if="showCloudProviderAmazonAdditionalConfigWarning"
|
|
428
466
|
color="warning"
|
|
@@ -461,6 +499,7 @@ export default {
|
|
|
461
499
|
<LabeledSelect
|
|
462
500
|
v-if="agentConfig"
|
|
463
501
|
v-model="agentConfig['cloud-provider-name']"
|
|
502
|
+
data-testid="clusterBasics__cloudProvider"
|
|
464
503
|
:mode="mode"
|
|
465
504
|
:disabled="canNotEditCloudProvider"
|
|
466
505
|
:options="cloudProviderOptions"
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
|
|
2
2
|
<script>
|
|
3
|
-
import { Checkbox } from '@components/Form/Checkbox';
|
|
4
3
|
import { LabeledInput } from '@components/Form/LabeledInput';
|
|
5
4
|
import { _CREATE } from '@shell/config/query-params';
|
|
6
5
|
|
|
7
6
|
export default {
|
|
8
7
|
name: 'DirectoryConfig',
|
|
9
|
-
components: {
|
|
10
|
-
|
|
11
|
-
LabeledInput,
|
|
12
|
-
},
|
|
13
|
-
props: {
|
|
8
|
+
components: { LabeledInput },
|
|
9
|
+
props: {
|
|
14
10
|
mode: {
|
|
15
11
|
type: String,
|
|
16
12
|
required: true,
|
|
@@ -21,50 +17,11 @@ export default {
|
|
|
21
17
|
required: true,
|
|
22
18
|
},
|
|
23
19
|
},
|
|
24
|
-
data() {
|
|
25
|
-
let atLeastOneDirWithAnIdentifier = false;
|
|
26
|
-
let allDirsWithSameIdentifier = false;
|
|
27
|
-
|
|
28
|
-
if (this.value.systemAgent.length || this.value.provisioning.length || this.value.k8sDistro.length) {
|
|
29
|
-
atLeastOneDirWithAnIdentifier = true;
|
|
30
|
-
if (this.value.systemAgent === this.value.provisioning && this.value.provisioning === this.value.k8sDistro &&
|
|
31
|
-
this.value.systemAgent === this.value.k8sDistro) {
|
|
32
|
-
allDirsWithSameIdentifier = true;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return {
|
|
37
|
-
isSettingCommonConfig: !(atLeastOneDirWithAnIdentifier && !allDirsWithSameIdentifier),
|
|
38
|
-
commonConfig: allDirsWithSameIdentifier ? this.value.systemAgent : '',
|
|
39
|
-
};
|
|
40
|
-
},
|
|
41
|
-
watch: {
|
|
42
|
-
commonConfig(neu) {
|
|
43
|
-
if (neu && neu.length && this.isSettingCommonConfig) {
|
|
44
|
-
this.value.systemAgent = neu;
|
|
45
|
-
this.value.provisioning = neu;
|
|
46
|
-
this.value.k8sDistro = neu;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
},
|
|
50
20
|
computed: {
|
|
51
21
|
disableEditInput() {
|
|
52
22
|
return this.mode !== _CREATE;
|
|
53
23
|
}
|
|
54
|
-
}
|
|
55
|
-
methods: {
|
|
56
|
-
handleCommonConfig(val) {
|
|
57
|
-
this.isSettingCommonConfig = val;
|
|
58
|
-
|
|
59
|
-
if (val) {
|
|
60
|
-
this.value.systemAgent = '';
|
|
61
|
-
this.value.provisioning = '';
|
|
62
|
-
this.value.k8sDistro = '';
|
|
63
|
-
} else {
|
|
64
|
-
this.commonConfig = '';
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
},
|
|
24
|
+
}
|
|
68
25
|
};
|
|
69
26
|
</script>
|
|
70
27
|
|
|
@@ -74,54 +31,33 @@ export default {
|
|
|
74
31
|
<h3 class="mb-20">
|
|
75
32
|
{{ t('cluster.directoryConfig.title') }}
|
|
76
33
|
</h3>
|
|
77
|
-
<
|
|
78
|
-
|
|
79
|
-
|
|
34
|
+
<LabeledInput
|
|
35
|
+
v-model="value.systemAgent"
|
|
36
|
+
class="mb-20"
|
|
37
|
+
:mode="mode"
|
|
38
|
+
:label="t('cluster.directoryConfig.systemAgent.label')"
|
|
39
|
+
:tooltip="t('cluster.directoryConfig.systemAgent.tooltip')"
|
|
40
|
+
:disabled="disableEditInput"
|
|
41
|
+
data-testid="rke2-directory-config-systemAgent-data-dir"
|
|
42
|
+
/>
|
|
43
|
+
<LabeledInput
|
|
44
|
+
v-model="value.provisioning"
|
|
45
|
+
class="mb-20"
|
|
80
46
|
:mode="mode"
|
|
81
|
-
:label="t('cluster.directoryConfig.
|
|
47
|
+
:label="t('cluster.directoryConfig.provisioning.label')"
|
|
48
|
+
:tooltip="t('cluster.directoryConfig.provisioning.tooltip')"
|
|
82
49
|
:disabled="disableEditInput"
|
|
83
|
-
data-testid="rke2-directory-config-
|
|
84
|
-
@input="handleCommonConfig"
|
|
50
|
+
data-testid="rke2-directory-config-provisioning-data-dir"
|
|
85
51
|
/>
|
|
86
52
|
<LabeledInput
|
|
87
|
-
v-
|
|
88
|
-
v-model="commonConfig"
|
|
53
|
+
v-model="value.k8sDistro"
|
|
89
54
|
class="mb-20"
|
|
90
55
|
:mode="mode"
|
|
91
|
-
:label="t('cluster.directoryConfig.
|
|
92
|
-
:tooltip="t('cluster.directoryConfig.
|
|
56
|
+
:label="t('cluster.directoryConfig.k8sDistro.label')"
|
|
57
|
+
:tooltip="t('cluster.directoryConfig.k8sDistro.tooltip')"
|
|
93
58
|
:disabled="disableEditInput"
|
|
94
|
-
data-testid="rke2-directory-config-
|
|
59
|
+
data-testid="rke2-directory-config-k8sDistro-data-dir"
|
|
95
60
|
/>
|
|
96
|
-
<div v-if="!isSettingCommonConfig">
|
|
97
|
-
<LabeledInput
|
|
98
|
-
v-model="value.systemAgent"
|
|
99
|
-
class="mb-20"
|
|
100
|
-
:mode="mode"
|
|
101
|
-
:label="t('cluster.directoryConfig.systemAgent.label')"
|
|
102
|
-
:tooltip="t('cluster.directoryConfig.systemAgent.tooltip')"
|
|
103
|
-
:disabled="disableEditInput"
|
|
104
|
-
data-testid="rke2-directory-config-systemAgent-data-dir"
|
|
105
|
-
/>
|
|
106
|
-
<LabeledInput
|
|
107
|
-
v-model="value.provisioning"
|
|
108
|
-
class="mb-20"
|
|
109
|
-
:mode="mode"
|
|
110
|
-
:label="t('cluster.directoryConfig.provisioning.label')"
|
|
111
|
-
:tooltip="t('cluster.directoryConfig.provisioning.tooltip')"
|
|
112
|
-
:disabled="disableEditInput"
|
|
113
|
-
data-testid="rke2-directory-config-provisioning-data-dir"
|
|
114
|
-
/>
|
|
115
|
-
<LabeledInput
|
|
116
|
-
v-model="value.k8sDistro"
|
|
117
|
-
class="mb-20"
|
|
118
|
-
:mode="mode"
|
|
119
|
-
:label="t('cluster.directoryConfig.k8sDistro.label')"
|
|
120
|
-
:tooltip="t('cluster.directoryConfig.k8sDistro.tooltip')"
|
|
121
|
-
:disabled="disableEditInput"
|
|
122
|
-
data-testid="rke2-directory-config-k8sDistro-data-dir"
|
|
123
|
-
/>
|
|
124
|
-
</div>
|
|
125
61
|
<div class="mb-40" />
|
|
126
62
|
</div>
|
|
127
63
|
</div>
|
|
@@ -7,6 +7,7 @@ import SelectOrCreateAuthSecret from '@shell/components/form/SelectOrCreateAuthS
|
|
|
7
7
|
import CreateEditView from '@shell/mixins/create-edit-view';
|
|
8
8
|
import SecretSelector from '@shell/components/form/SecretSelector';
|
|
9
9
|
import { SECRET_TYPES as TYPES } from '@shell/config/secret';
|
|
10
|
+
import { base64Decode, base64Encode } from '@shell/utils/crypto';
|
|
10
11
|
|
|
11
12
|
export default {
|
|
12
13
|
components: {
|
|
@@ -55,7 +56,7 @@ export default {
|
|
|
55
56
|
if (configMap[hostname]) {
|
|
56
57
|
configMap[hostname].insecureSkipVerify = configMap[hostname].insecureSkipVerify ?? defaultAddValue.insecureSkipVerify;
|
|
57
58
|
configMap[hostname].authConfigSecretName = configMap[hostname].authConfigSecretName ?? defaultAddValue.authConfigSecretName;
|
|
58
|
-
configMap[hostname].caBundle = configMap[hostname].caBundle ?? defaultAddValue.caBundle;
|
|
59
|
+
configMap[hostname].caBundle = base64Decode(configMap[hostname].caBundle ?? defaultAddValue.caBundle);
|
|
59
60
|
configMap[hostname].tlsSecretName = configMap[hostname].tlsSecretName ?? defaultAddValue.tlsSecretName;
|
|
60
61
|
}
|
|
61
62
|
entries.push({
|
|
@@ -94,7 +95,11 @@ export default {
|
|
|
94
95
|
continue;
|
|
95
96
|
}
|
|
96
97
|
|
|
97
|
-
configs[h] = {
|
|
98
|
+
configs[h] = {
|
|
99
|
+
...entry,
|
|
100
|
+
caBundle: base64Encode(entry.caBundle)
|
|
101
|
+
};
|
|
102
|
+
|
|
98
103
|
delete configs[h].hostname;
|
|
99
104
|
}
|
|
100
105
|
|
|
@@ -177,6 +182,7 @@ export default {
|
|
|
177
182
|
|
|
178
183
|
<LabeledInput
|
|
179
184
|
v-model="row.value.caBundle"
|
|
185
|
+
:data-testid="`registry-caBundle-${i}`"
|
|
180
186
|
class="mt-20"
|
|
181
187
|
type="multiline"
|
|
182
188
|
label="CA Cert Bundle"
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { mount, Wrapper } from '@vue/test-utils';
|
|
2
|
+
import { clone } from '@shell/utils/object';
|
|
3
|
+
import { _EDIT } from '@shell/config/query-params';
|
|
4
|
+
import { PROV_CLUSTER } from '@shell/edit/provisioning.cattle.io.cluster/__tests__/utils/cluster';
|
|
5
|
+
import RegistryConfigs from '@shell/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue';
|
|
6
|
+
|
|
7
|
+
describe('component: RegistryConfigs', () => {
|
|
8
|
+
let wrapper: Wrapper<InstanceType<typeof RegistryConfigs> & { [key: string]: any }>;
|
|
9
|
+
|
|
10
|
+
const mountOptions = {
|
|
11
|
+
propsData: {
|
|
12
|
+
value: {},
|
|
13
|
+
mode: _EDIT,
|
|
14
|
+
clusterRegisterBeforeHook: () => {}
|
|
15
|
+
},
|
|
16
|
+
stubs: {
|
|
17
|
+
SelectOrCreateAuthSecret: true,
|
|
18
|
+
SecretSelector: true,
|
|
19
|
+
},
|
|
20
|
+
mocks: { $store: { getters: { 'i18n/t': jest.fn() } } }
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
describe('key CA Cert Bundle', () => {
|
|
24
|
+
it('should display default key', () => {
|
|
25
|
+
const value = clone(PROV_CLUSTER);
|
|
26
|
+
|
|
27
|
+
value.spec.rkeConfig.registries.configs = { foo: { caBundle: 'Zm9vYmFy' } };
|
|
28
|
+
|
|
29
|
+
mountOptions.propsData.value = value;
|
|
30
|
+
|
|
31
|
+
wrapper = mount(
|
|
32
|
+
RegistryConfigs,
|
|
33
|
+
mountOptions
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const registry = wrapper.find('[data-testid^="registry-caBundle"]').element as HTMLTextAreaElement;
|
|
37
|
+
|
|
38
|
+
expect(registry.value).toBe('foobar');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should update key in base64 format', async() => {
|
|
42
|
+
const value = clone(PROV_CLUSTER);
|
|
43
|
+
|
|
44
|
+
value.spec.rkeConfig.registries.configs = { foo: { caBundle: 'Zm9vYmFy' } };
|
|
45
|
+
|
|
46
|
+
mountOptions.propsData.value = value;
|
|
47
|
+
|
|
48
|
+
wrapper = mount(
|
|
49
|
+
RegistryConfigs,
|
|
50
|
+
mountOptions
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const registry = wrapper.find('[data-testid^="registry-caBundle"]');
|
|
54
|
+
|
|
55
|
+
await registry.setValue('ssh key');
|
|
56
|
+
wrapper.vm.update();
|
|
57
|
+
|
|
58
|
+
expect(wrapper.emitted('updateConfigs')![0][0]['foo']['caBundle']).toBe('c3NoIGtleQ==');
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -3,7 +3,6 @@ import { updatePageTitle } from '@shell/utils/title';
|
|
|
3
3
|
import { getVendor } from '@shell/config/private-label';
|
|
4
4
|
import middleware from '@shell/config/middleware.js';
|
|
5
5
|
import { withQuery } from 'ufo';
|
|
6
|
-
import dynamicPluginLoader from '@shell/pkg/dynamic-plugin-loader';
|
|
7
6
|
|
|
8
7
|
// Global variable used on mount, updated on route change and used in the render function
|
|
9
8
|
let app;
|
|
@@ -191,30 +190,14 @@ async function render(to, from, next) {
|
|
|
191
190
|
next: _next.bind(this)
|
|
192
191
|
});
|
|
193
192
|
|
|
193
|
+
if (this.$loading.start && !this.$loading.manual) {
|
|
194
|
+
this.$loading.start();
|
|
195
|
+
}
|
|
196
|
+
|
|
194
197
|
// Get route's matched components
|
|
195
198
|
const matches = [];
|
|
196
199
|
const Components = getMatchedComponents(to, matches);
|
|
197
200
|
|
|
198
|
-
// If no Components matched, generate 404
|
|
199
|
-
if (!Components.length) {
|
|
200
|
-
// Handle the loading of dynamic plugins (Harvester) because we only want to attempt to load those plugins and routes if we first couldn't find a page.
|
|
201
|
-
// We should probably get rid of this concept entirely and just load plugins at the start.
|
|
202
|
-
await app.context.store.dispatch('loadManagement');
|
|
203
|
-
const newLocation = await dynamicPluginLoader.check({ route: { path: window.location.pathname }, store: app.context.store });
|
|
204
|
-
|
|
205
|
-
// If we have a new location, double check that it's actually valid
|
|
206
|
-
const resolvedRoute = newLocation?.path ? app.context.store.app.router.resolve({ path: newLocation.path.replace(/^\/{0,1}dashboard/, '') }) : null;
|
|
207
|
-
|
|
208
|
-
if (resolvedRoute?.route.matched.length) {
|
|
209
|
-
// Note - don't use `redirect` or `store.app.route` (breaks feature by failing to run middleware in default layout)
|
|
210
|
-
return next(resolvedRoute.resolved.path);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
errorRedirect(this, new Error('404: This page could not be found'));
|
|
214
|
-
|
|
215
|
-
return next();
|
|
216
|
-
}
|
|
217
|
-
|
|
218
201
|
try {
|
|
219
202
|
// Call middleware
|
|
220
203
|
await callMiddleware.call(this, Components, app.context);
|
|
@@ -24,8 +24,9 @@ describe('chartMixin', () => {
|
|
|
24
24
|
localVue.mixin(ChartMixin);
|
|
25
25
|
|
|
26
26
|
it.each(testCases.opa)(
|
|
27
|
-
'should add OPA deprecation warning properly', (chartId, expected) => {
|
|
27
|
+
'should add OPA deprecation warning properly', async(chartId, expected) => {
|
|
28
28
|
const store = new Vuex.Store({
|
|
29
|
+
actions: { 'catalog/load': () => {} },
|
|
29
30
|
getters: {
|
|
30
31
|
currentCluster: () => {},
|
|
31
32
|
isRancher: () => true,
|
|
@@ -44,6 +45,8 @@ describe('chartMixin', () => {
|
|
|
44
45
|
|
|
45
46
|
instance.$route = { query: { chart: 'chart_name' } };
|
|
46
47
|
|
|
48
|
+
await instance.fetchChart();
|
|
49
|
+
|
|
47
50
|
const warnings = instance.warnings;
|
|
48
51
|
|
|
49
52
|
expect(warnings).toHaveLength(expected);
|
package/mixins/chart.js
CHANGED
|
@@ -27,6 +27,8 @@ export default {
|
|
|
27
27
|
existing: null,
|
|
28
28
|
|
|
29
29
|
ignoreWarning: false,
|
|
30
|
+
|
|
31
|
+
chart: null,
|
|
30
32
|
};
|
|
31
33
|
},
|
|
32
34
|
|
|
@@ -35,20 +37,6 @@ export default {
|
|
|
35
37
|
|
|
36
38
|
showPreRelease: mapPref(SHOW_PRE_RELEASE),
|
|
37
39
|
|
|
38
|
-
chart() {
|
|
39
|
-
if ( this.repo && this.query.chartName ) {
|
|
40
|
-
return this.$store.getters['catalog/chart']({
|
|
41
|
-
repoType: this.query.repoType,
|
|
42
|
-
repoName: this.query.repoName,
|
|
43
|
-
chartName: this.query.chartName,
|
|
44
|
-
includeHidden: true,
|
|
45
|
-
showDeprecated: this.showDeprecated
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return null;
|
|
50
|
-
},
|
|
51
|
-
|
|
52
40
|
repo() {
|
|
53
41
|
return this.$store.getters['catalog/repo']({
|
|
54
42
|
repoType: this.query.repoType,
|
|
@@ -258,11 +246,39 @@ export default {
|
|
|
258
246
|
},
|
|
259
247
|
|
|
260
248
|
methods: {
|
|
249
|
+
/**
|
|
250
|
+
* Populate `this.chart`
|
|
251
|
+
*
|
|
252
|
+
* `chart` used to be a computed property pointing at getter catalog/chart
|
|
253
|
+
*
|
|
254
|
+
* this however stopped recalculating given changes to the store
|
|
255
|
+
*
|
|
256
|
+
* (the store would populate a charts collection, which the getter uses to find the chart,
|
|
257
|
+
* however this did not kick off the computed property, so this.charts was not populated)
|
|
258
|
+
*
|
|
259
|
+
* Now we find and cache the chart
|
|
260
|
+
*/
|
|
261
|
+
fetchStoreChart() {
|
|
262
|
+
if (!this.chart && this.repo && this.query.chartName) {
|
|
263
|
+
this.chart = this.$store.getters['catalog/chart']({
|
|
264
|
+
repoType: this.query.repoType,
|
|
265
|
+
repoName: this.query.repoName,
|
|
266
|
+
chartName: this.query.chartName,
|
|
267
|
+
includeHidden: true,
|
|
268
|
+
showDeprecated: this.showDeprecated
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return this.chart;
|
|
273
|
+
},
|
|
274
|
+
|
|
261
275
|
async fetchChart() {
|
|
262
276
|
this.versionInfoError = null;
|
|
263
277
|
|
|
264
278
|
await this.$store.dispatch('catalog/load'); // not the problem
|
|
265
279
|
|
|
280
|
+
this.fetchStoreChart();
|
|
281
|
+
|
|
266
282
|
if ( this.query.appNamespace && this.query.appName ) {
|
|
267
283
|
// First check the URL query for an app name and namespace.
|
|
268
284
|
// Use those values to check for a catalog app resource.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import Deployment from '@shell/models/apps.deployment';
|
|
2
|
+
import { WORKLOAD_TYPES } from '@shell/config/types';
|
|
3
|
+
|
|
4
|
+
describe('class Deployment', () => {
|
|
5
|
+
describe('replicaSetId', () => {
|
|
6
|
+
it.each([{
|
|
7
|
+
relationships: [],
|
|
8
|
+
expected: undefined,
|
|
9
|
+
}, {
|
|
10
|
+
relationships: [{
|
|
11
|
+
rel: 'owner',
|
|
12
|
+
toType: WORKLOAD_TYPES.REPLICA_SET,
|
|
13
|
+
toId: 'rel-id'
|
|
14
|
+
}],
|
|
15
|
+
expected: 'rel-id',
|
|
16
|
+
}, {
|
|
17
|
+
relationships: [{
|
|
18
|
+
rel: 'owner',
|
|
19
|
+
toType: WORKLOAD_TYPES.REPLICA_SET,
|
|
20
|
+
toId: 'rel-id-1',
|
|
21
|
+
message: 'ReplicaSet is available. Replicas: 1'
|
|
22
|
+
}],
|
|
23
|
+
expected: 'rel-id-1',
|
|
24
|
+
}, {
|
|
25
|
+
relationships: [{
|
|
26
|
+
rel: 'owner',
|
|
27
|
+
toType: WORKLOAD_TYPES.REPLICA_SET,
|
|
28
|
+
toId: 'rel-id-1',
|
|
29
|
+
message: 'ReplicaSet is available. Replicas: 0'
|
|
30
|
+
}, {
|
|
31
|
+
rel: 'owner',
|
|
32
|
+
toType: WORKLOAD_TYPES.REPLICA_SET,
|
|
33
|
+
toId: 'rel-id-2',
|
|
34
|
+
message: 'ReplicaSet is available. Replicas: 1'
|
|
35
|
+
}],
|
|
36
|
+
expected: 'rel-id-2',
|
|
37
|
+
}, {
|
|
38
|
+
relationships: [{
|
|
39
|
+
rel: 'owner',
|
|
40
|
+
toType: WORKLOAD_TYPES.REPLICA_SET,
|
|
41
|
+
toId: 'rel-id-1',
|
|
42
|
+
message: 'Message without replicas count'
|
|
43
|
+
}, {
|
|
44
|
+
rel: 'owner',
|
|
45
|
+
toType: WORKLOAD_TYPES.REPLICA_SET,
|
|
46
|
+
toId: 'rel-id-2',
|
|
47
|
+
message: 'Another message without replicas count'
|
|
48
|
+
}],
|
|
49
|
+
expected: 'rel-id-1',
|
|
50
|
+
}, {
|
|
51
|
+
relationships: [{
|
|
52
|
+
rel: 'owner',
|
|
53
|
+
toType: WORKLOAD_TYPES.REPLICA_SET,
|
|
54
|
+
toId: 'rel-id-1',
|
|
55
|
+
message: 'ReplicaSet is available. Replicas: 0'
|
|
56
|
+
}, {
|
|
57
|
+
rel: 'owner',
|
|
58
|
+
toType: WORKLOAD_TYPES.REPLICA_SET,
|
|
59
|
+
toId: 'rel-id-2',
|
|
60
|
+
message: 'ReplicaSet is available. Replicas: 0'
|
|
61
|
+
}],
|
|
62
|
+
expected: 'rel-id-1',
|
|
63
|
+
}, {
|
|
64
|
+
relationships: [{
|
|
65
|
+
rel: 'owner',
|
|
66
|
+
toType: WORKLOAD_TYPES.REPLICA_SET,
|
|
67
|
+
toId: 'rel-id-1',
|
|
68
|
+
message: 'Message without replicas count'
|
|
69
|
+
}, {
|
|
70
|
+
rel: 'owner',
|
|
71
|
+
toType: WORKLOAD_TYPES.REPLICA_SET,
|
|
72
|
+
toId: 'rel-id-2',
|
|
73
|
+
message: 'ReplicaSet is available. Replicas: 0'
|
|
74
|
+
}],
|
|
75
|
+
expected: 'rel-id-1',
|
|
76
|
+
}])('replicaSetId', ({ relationships, expected }) => {
|
|
77
|
+
const deploymentData = {
|
|
78
|
+
id: 'any-id',
|
|
79
|
+
type: WORKLOAD_TYPES.DEPLOYMENT,
|
|
80
|
+
metadata: {
|
|
81
|
+
name: 'any-name',
|
|
82
|
+
namespace: 'any-namespace',
|
|
83
|
+
uid: 'any-uid',
|
|
84
|
+
relationships,
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const deployment = new Deployment(deploymentData);
|
|
89
|
+
|
|
90
|
+
expect(deployment.replicaSetId).toStrictEqual(expected);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
});
|