@rancher/shell 3.0.0-rc.9 → 3.0.0
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 +12 -11
- package/assets/translations/zh-hans.yaml +1 -4
- package/components/EmberPage.vue +0 -8
- package/components/ResourceTable.vue +26 -1
- package/components/SortableTable/actions.js +1 -1
- package/components/SortableTable/index.vue +17 -1
- package/components/SortableTable/selection.js +1 -1
- package/components/SortableTable/sorting.js +11 -3
- package/components/fleet/FleetClusters.vue +0 -3
- package/components/form/HookOption.vue +31 -29
- package/components/form/LabeledSelect.vue +0 -1
- package/components/form/LifecycleHooks.vue +2 -2
- package/components/formatter/SecretData.vue +1 -1
- package/components/nav/Header.vue +10 -13
- package/components/nav/TopLevelMenu.vue +0 -40
- package/components/nav/WorkspaceSwitcher.vue +0 -1
- package/config/private-label.js +2 -1
- package/config/router/routes.js +2 -26
- package/config/settings.ts +5 -0
- package/config/version.js +2 -0
- package/detail/catalog.cattle.io.app.vue +17 -4
- package/detail/fleet.cattle.io.cluster.vue +11 -9
- package/detail/fleet.cattle.io.gitrepo.vue +1 -1
- package/edit/cis.cattle.io.clusterscan.vue +4 -3
- package/edit/fleet.cattle.io.gitrepo.vue +11 -8
- package/edit/management.cattle.io.project.vue +2 -1
- package/edit/monitoring.coreos.com.prometheusrule/AlertingRule.vue +5 -5
- package/edit/monitoring.coreos.com.prometheusrule/index.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/__tests__/Advanced.test.ts +26 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/DirectoryConfig.test.ts +63 -149
- package/edit/provisioning.cattle.io.cluster/rke2.vue +3 -1
- package/edit/provisioning.cattle.io.cluster/tabs/Advanced.vue +7 -2
- package/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue +108 -35
- package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +1 -1
- package/edit/workload/mixins/workload.js +1 -1
- package/mixins/browser-tab-visibility.js +1 -1
- package/mixins/chart.js +6 -2
- package/mixins/metric-poller.js +1 -1
- package/mixins/resource-fetch.js +1 -1
- package/models/catalog.cattle.io.app.js +108 -21
- package/models/cloudcredential.js +4 -4
- package/models/fleet.cattle.io.gitrepo.js +8 -13
- package/models/management.cattle.io.cluster.js +13 -2
- package/models/management.cattle.io.project.js +4 -0
- package/models/provisioning.cattle.io.cluster.js +1 -2
- package/models/workload.js +1 -1
- package/package.json +3 -3
- package/pages/auth/logout.vue +7 -9
- package/pages/auth/setup.vue +3 -0
- package/pages/c/_cluster/apps/charts/install.vue +11 -3
- package/pages/c/_cluster/explorer/__tests__/index.test.ts +1 -1
- package/pages/c/_cluster/explorer/index.vue +1 -2
- package/pages/c/_cluster/fleet/index.vue +11 -5
- package/pages/c/_cluster/uiplugins/index.vue +4 -2
- package/pages/diagnostic.vue +1 -0
- package/plugins/steve/mutations.js +4 -1
- package/plugins/steve/subscribe.js +3 -4
- package/types/shell/index.d.ts +13 -0
- package/utils/__tests__/object.test.ts +152 -1
- package/utils/object.js +37 -0
- package/utils/string.js +9 -0
- package/utils/validators/formRules/index.ts +1 -1
- package/config/product/multi-cluster-apps.js +0 -61
|
@@ -9,7 +9,8 @@ import RelatedResources from '@shell/components/RelatedResources';
|
|
|
9
9
|
import jsyaml from 'js-yaml';
|
|
10
10
|
import merge from 'lodash/merge';
|
|
11
11
|
import { CATALOG } from '@shell/config/types';
|
|
12
|
-
import { sortBy } from '
|
|
12
|
+
import { sortBy } from '@shell/utils/sort';
|
|
13
|
+
import { allHash } from '@shell/utils/promise';
|
|
13
14
|
|
|
14
15
|
export default {
|
|
15
16
|
name: 'DetailRelease',
|
|
@@ -30,9 +31,15 @@ export default {
|
|
|
30
31
|
},
|
|
31
32
|
|
|
32
33
|
async fetch() {
|
|
33
|
-
|
|
34
|
+
const promises = {
|
|
35
|
+
catalog: this.$store.dispatch('catalog/load'),
|
|
36
|
+
allOperations: this.$store.dispatch('cluster/findAll', { type: CATALOG.OPERATION }),
|
|
37
|
+
secrets: this.value.fetchValues(true),
|
|
38
|
+
};
|
|
34
39
|
|
|
35
|
-
|
|
40
|
+
const res = await allHash(promises);
|
|
41
|
+
|
|
42
|
+
this.allOperations = res.allOperations;
|
|
36
43
|
},
|
|
37
44
|
|
|
38
45
|
computed: {
|
|
@@ -45,7 +52,7 @@ export default {
|
|
|
45
52
|
},
|
|
46
53
|
|
|
47
54
|
valuesYaml() {
|
|
48
|
-
const combined = merge(merge({}, this.value?.
|
|
55
|
+
const combined = merge(merge({}, this.value?.chartValues || {}), this.value?.values || {});
|
|
49
56
|
|
|
50
57
|
return jsyaml.dump(combined);
|
|
51
58
|
},
|
|
@@ -95,6 +102,12 @@ export default {
|
|
|
95
102
|
}
|
|
96
103
|
},
|
|
97
104
|
},
|
|
105
|
+
|
|
106
|
+
watch: {
|
|
107
|
+
'value.secretId'(neu, old) {
|
|
108
|
+
this.value.fetchValues(true);
|
|
109
|
+
}
|
|
110
|
+
},
|
|
98
111
|
};
|
|
99
112
|
</script>
|
|
100
113
|
|
|
@@ -6,6 +6,7 @@ import ResourceTabs from '@shell/components/form/ResourceTabs';
|
|
|
6
6
|
import Tab from '@shell/components/Tabbed/Tab';
|
|
7
7
|
import { MANAGEMENT, FLEET } from '@shell/config/types';
|
|
8
8
|
import { FLEET as FLEET_LABELS } from '@shell/config/labels-annotations';
|
|
9
|
+
import { allHash } from 'utils/promise';
|
|
9
10
|
|
|
10
11
|
export default {
|
|
11
12
|
name: 'FleetDetailCluster',
|
|
@@ -29,17 +30,18 @@ export default {
|
|
|
29
30
|
|
|
30
31
|
async fetch() {
|
|
31
32
|
const clusterId = this.value?.metadata?.labels[FLEET_LABELS.CLUSTER_NAME];
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
const hash = await allHash({
|
|
34
|
+
rancherCluster: this.$store.dispatch('management/find', {
|
|
35
|
+
type: MANAGEMENT.CLUSTER,
|
|
36
|
+
id: clusterId
|
|
37
|
+
}),
|
|
38
|
+
repos: this.$store.dispatch('management/findAll', { type: FLEET.GIT_REPO }),
|
|
39
|
+
workspaces: this.$store.dispatch('management/findAll', { type: FLEET.WORKSPACE }),
|
|
40
|
+
bundleDeployments: this.$store.dispatch('management/findAll', { type: FLEET.BUNDLE_DEPLOYMENT })
|
|
36
41
|
});
|
|
37
42
|
|
|
38
|
-
this.
|
|
39
|
-
|
|
40
|
-
await this.$store.dispatch('management/findAll', { type: FLEET.WORKSPACE });
|
|
41
|
-
|
|
42
|
-
await this.$store.dispatch('management/findAll', { type: FLEET.BUNDLE_DEPLOYMENT });
|
|
43
|
+
this.rancherCluster = hash.rancherCluster;
|
|
44
|
+
this.allRepos = hash.repos;
|
|
43
45
|
},
|
|
44
46
|
|
|
45
47
|
data() {
|
|
@@ -42,7 +42,7 @@ export default {
|
|
|
42
42
|
},
|
|
43
43
|
computed: {
|
|
44
44
|
gitRepoHasClusters() {
|
|
45
|
-
return this.value
|
|
45
|
+
return this.value.status.desiredReadyClusters;
|
|
46
46
|
},
|
|
47
47
|
clusterSchema() {
|
|
48
48
|
return this.$store.getters['management/schemaFor'](FLEET.CLUSTER);
|
|
@@ -12,7 +12,7 @@ import { allHash } from '@shell/utils/promise';
|
|
|
12
12
|
import { Checkbox } from '@components/Form/Checkbox';
|
|
13
13
|
import { RadioGroup } from '@components/Form/Radio';
|
|
14
14
|
import { get } from '@shell/utils/object';
|
|
15
|
-
import { _VIEW, _CREATE
|
|
15
|
+
import { _VIEW, _CREATE } from '@shell/config/query-params';
|
|
16
16
|
import { isValidCron } from 'cron-validator';
|
|
17
17
|
import { fetchSpecsScheduledScanConfig } from '@shell/models/cis.cattle.io.clusterscan';
|
|
18
18
|
|
|
@@ -43,7 +43,8 @@ export default {
|
|
|
43
43
|
// in the clusterscan edit/create views the "canBeScheduled" won't run properly
|
|
44
44
|
await this.schema.fetchResourceFields();
|
|
45
45
|
|
|
46
|
-
if
|
|
46
|
+
// Only initialize on create or if we don't have a spec object (added for resilience)
|
|
47
|
+
if (this.realMode === _CREATE || !this.value.spec) {
|
|
47
48
|
const includeScheduling = this.value.canBeScheduled();
|
|
48
49
|
const spec = this.value.spec || {};
|
|
49
50
|
|
|
@@ -326,7 +327,7 @@ export default {
|
|
|
326
327
|
</div>
|
|
327
328
|
<div class="col span-6">
|
|
328
329
|
<UnitInput
|
|
329
|
-
v-model
|
|
330
|
+
v-model:value="scheduledScanConfig.retentionCount"
|
|
330
331
|
:suffix="t('cis.reports')"
|
|
331
332
|
type="number"
|
|
332
333
|
:mode="mode"
|
|
@@ -25,6 +25,7 @@ import { CAPI, CATALOG, FLEET as FLEET_LABELS } from '@shell/config/labels-annot
|
|
|
25
25
|
import { SECRET_TYPES } from '@shell/config/secret';
|
|
26
26
|
import { checkSchemasForFindAllHash } from '@shell/utils/auth';
|
|
27
27
|
import Checkbox from '@components/Form/Checkbox/Checkbox.vue';
|
|
28
|
+
import FormValidation from '@shell/mixins/form-validation';
|
|
28
29
|
|
|
29
30
|
const _VERIFY = 'verify';
|
|
30
31
|
const _SKIP = 'skip';
|
|
@@ -33,6 +34,8 @@ const _SPECIFY = 'specify';
|
|
|
33
34
|
export default {
|
|
34
35
|
name: 'CruGitRepo',
|
|
35
36
|
|
|
37
|
+
inheritAttrs: false,
|
|
38
|
+
|
|
36
39
|
emits: ['input'],
|
|
37
40
|
|
|
38
41
|
components: {
|
|
@@ -50,7 +53,7 @@ export default {
|
|
|
50
53
|
SelectOrCreateAuthSecret,
|
|
51
54
|
},
|
|
52
55
|
|
|
53
|
-
mixins: [CreateEditView],
|
|
56
|
+
mixins: [CreateEditView, FormValidation],
|
|
54
57
|
|
|
55
58
|
async fetch() {
|
|
56
59
|
const hash = await checkSchemasForFindAllHash({
|
|
@@ -153,7 +156,8 @@ export default {
|
|
|
153
156
|
stepRepoInfo,
|
|
154
157
|
stepTargetInfo,
|
|
155
158
|
addRepositorySteps,
|
|
156
|
-
displayHelmRepoURLRegex: false
|
|
159
|
+
displayHelmRepoURLRegex: false,
|
|
160
|
+
fvFormRuleSets: [{ path: 'spec.repo', rules: ['required'] }]
|
|
157
161
|
};
|
|
158
162
|
},
|
|
159
163
|
|
|
@@ -253,7 +257,7 @@ export default {
|
|
|
253
257
|
},
|
|
254
258
|
|
|
255
259
|
stepOneRequires() {
|
|
256
|
-
return !!this.value.metadata.name && !!this.refValue;
|
|
260
|
+
return !!this.value.metadata.name && !!this.refValue && !!this.fvFormIsValid;
|
|
257
261
|
},
|
|
258
262
|
},
|
|
259
263
|
|
|
@@ -265,6 +269,8 @@ export default {
|
|
|
265
269
|
targetAdvanced: 'updateTargets',
|
|
266
270
|
tlsMode: 'updateTls',
|
|
267
271
|
caBundle: 'updateTls',
|
|
272
|
+
'value.metadata.name': 'stepOneReady',
|
|
273
|
+
'value.spec.repo': 'stepOneReady',
|
|
268
274
|
|
|
269
275
|
workspace(neu) {
|
|
270
276
|
if ( this.isCreate ) {
|
|
@@ -456,10 +462,6 @@ export default {
|
|
|
456
462
|
this.tlsMode = event;
|
|
457
463
|
},
|
|
458
464
|
|
|
459
|
-
onUpdateRepoName() {
|
|
460
|
-
this.stepOneReady();
|
|
461
|
-
},
|
|
462
|
-
|
|
463
465
|
stepOneReady() {
|
|
464
466
|
this.addRepositorySteps[0]['ready'] = this.stepOneRequires;
|
|
465
467
|
},
|
|
@@ -528,7 +530,6 @@ export default {
|
|
|
528
530
|
:namespaced="false"
|
|
529
531
|
:mode="mode"
|
|
530
532
|
@update:value="$emit('input', $event)"
|
|
531
|
-
@change="onUpdateRepoName"
|
|
532
533
|
/>
|
|
533
534
|
|
|
534
535
|
<div class="row">
|
|
@@ -552,6 +553,8 @@ export default {
|
|
|
552
553
|
:mode="mode"
|
|
553
554
|
label-key="fleet.gitRepo.repo.label"
|
|
554
555
|
:placeholder="t('fleet.gitRepo.repo.placeholder', null, true)"
|
|
556
|
+
:required="true"
|
|
557
|
+
:rules="fvGetAndReportPathRules('spec.repo')"
|
|
555
558
|
/>
|
|
556
559
|
</div>
|
|
557
560
|
<div class="col span-6">
|
|
@@ -103,7 +103,8 @@ export default {
|
|
|
103
103
|
this.value.metadata['namespace'] = this.$store.getters['currentCluster'].id;
|
|
104
104
|
this.value['spec'] = this.value.spec || {};
|
|
105
105
|
this.value.spec['containerDefaultResourceLimit'] = this.value.spec.containerDefaultResourceLimit || {};
|
|
106
|
-
|
|
106
|
+
// norman (and matching steve) resources treat annotations containing `cattle.io` as immutable, so only do this for the create world
|
|
107
|
+
if (this.isCreate && !this.$store.getters['auth/principalId'].includes('local://')) {
|
|
107
108
|
this.value.metadata.annotations[CREATOR_PRINCIPAL_ID] = this.$store.getters['auth/principalId'];
|
|
108
109
|
}
|
|
109
110
|
},
|
|
@@ -102,7 +102,7 @@ export default {
|
|
|
102
102
|
if (isEmpty(this.value?.annotations)) {
|
|
103
103
|
this.value['annotations'] = { summary: '' };
|
|
104
104
|
} else {
|
|
105
|
-
this.value.annotations
|
|
105
|
+
this.value.annotations = { ...this.value.annotations, summary: '' };
|
|
106
106
|
}
|
|
107
107
|
} else {
|
|
108
108
|
this.value.annotations['summary'] = '';
|
|
@@ -124,7 +124,7 @@ export default {
|
|
|
124
124
|
if (isEmpty(this.value?.annotations)) {
|
|
125
125
|
this.value['annotations'] = { message: '' };
|
|
126
126
|
} else {
|
|
127
|
-
this.value.annotations
|
|
127
|
+
this.value.annotations = { ...this.value.annotations, message: '' };
|
|
128
128
|
}
|
|
129
129
|
} else {
|
|
130
130
|
this.value.annotations['message'] = '';
|
|
@@ -146,7 +146,7 @@ export default {
|
|
|
146
146
|
if (isEmpty(this.value?.annotations)) {
|
|
147
147
|
this.value['annotations'] = { description: '' };
|
|
148
148
|
} else {
|
|
149
|
-
this.value.annotations
|
|
149
|
+
this.value.annotations = { ...this.value.annotations, description: '' };
|
|
150
150
|
}
|
|
151
151
|
} else {
|
|
152
152
|
this.value.annotations['description'] = '';
|
|
@@ -168,7 +168,7 @@ export default {
|
|
|
168
168
|
if (isEmpty(this.value?.annotations)) {
|
|
169
169
|
this.value['annotations'] = { runbook_url: '' };
|
|
170
170
|
} else {
|
|
171
|
-
this.value.annotations
|
|
171
|
+
this.value.annotations = { ...this.value.annotations, runbook_url: '' };
|
|
172
172
|
}
|
|
173
173
|
} else {
|
|
174
174
|
this.value.annotations['runbook_url'] = '';
|
|
@@ -213,7 +213,7 @@ export default {
|
|
|
213
213
|
return undefined;
|
|
214
214
|
},
|
|
215
215
|
set(v) {
|
|
216
|
-
this.value['for'] = [null, undefined].includes(v ? undefined : `${ v }s
|
|
216
|
+
this.value['for'] = [null, undefined].includes(v) ? undefined : `${ v }s`;
|
|
217
217
|
}
|
|
218
218
|
}
|
|
219
219
|
},
|
|
@@ -113,7 +113,7 @@ export default {
|
|
|
113
113
|
},
|
|
114
114
|
|
|
115
115
|
updateGroupInterval(group, interval) {
|
|
116
|
-
group['interval'] = [null, undefined].includes(interval ? undefined : `${ interval }s
|
|
116
|
+
group['interval'] = [null, undefined].includes(interval) ? undefined : `${ interval }s`;
|
|
117
117
|
},
|
|
118
118
|
|
|
119
119
|
getGroupInterval(interval) {
|
|
@@ -128,6 +128,32 @@ describe('component: Advanced', () => {
|
|
|
128
128
|
|
|
129
129
|
expect(checkbox.value).toBe('true');
|
|
130
130
|
});
|
|
131
|
+
|
|
132
|
+
it(`should update agentConfig when 'protect-kernel-defaults' exists`, async() => {
|
|
133
|
+
const value = clone(PROV_CLUSTER);
|
|
134
|
+
|
|
135
|
+
value.spec.rkeConfig.machineGlobalConfig['protect-kernel-defaults'] = false;
|
|
136
|
+
value.spec.rkeConfig.machineSelectorConfig = [{
|
|
137
|
+
config: { 'protect-kernel-defaults': true },
|
|
138
|
+
machineLabelSelector: {}
|
|
139
|
+
}];
|
|
140
|
+
value.agentConfig = value.spec.rkeConfig.machineSelectorConfig[0].config;
|
|
141
|
+
|
|
142
|
+
mountOptions.propsData.mode = _EDIT; // Use edit mode to allow interactions
|
|
143
|
+
mountOptions.propsData.value = value;
|
|
144
|
+
|
|
145
|
+
wrapper = mount(Advanced, mountOptions);
|
|
146
|
+
|
|
147
|
+
const checkboxLabel = wrapper
|
|
148
|
+
.find(`[data-testid="protect-kernel-defaults"]`)
|
|
149
|
+
.find('label');
|
|
150
|
+
|
|
151
|
+
checkboxLabel.trigger('click');
|
|
152
|
+
await wrapper.vm.$nextTick();
|
|
153
|
+
|
|
154
|
+
// Verify that agentConfig is updated
|
|
155
|
+
expect(value.spec.rkeConfig.machineSelectorConfig[0].config['protect-kernel-defaults']).toBe(false);
|
|
156
|
+
});
|
|
131
157
|
});
|
|
132
158
|
|
|
133
159
|
describe(`'kubelet-arg'`, () => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { nextTick } from 'vue';
|
|
2
2
|
/* eslint-disable jest/no-hooks */
|
|
3
3
|
import { mount, Wrapper } from '@vue/test-utils';
|
|
4
|
-
import DirectoryConfig from '@shell/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue';
|
|
4
|
+
import DirectoryConfig, { DATA_DIR_RADIO_OPTIONS, DEFAULT_SUBDIRS } from '@shell/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig.vue';
|
|
5
5
|
import { _EDIT, _CREATE } from '@shell/config/query-params';
|
|
6
6
|
import { clone } from '@shell/utils/object';
|
|
7
7
|
|
|
@@ -15,7 +15,8 @@ describe('component: DirectoryConfig', () => {
|
|
|
15
15
|
provisioning: '',
|
|
16
16
|
k8sDistro: '',
|
|
17
17
|
},
|
|
18
|
-
|
|
18
|
+
k8sVersion: 'k3s',
|
|
19
|
+
mode: _CREATE,
|
|
19
20
|
},
|
|
20
21
|
mocks: {
|
|
21
22
|
$store: {
|
|
@@ -34,203 +35,119 @@ describe('component: DirectoryConfig', () => {
|
|
|
34
35
|
);
|
|
35
36
|
|
|
36
37
|
const title = wrapper.find('h3');
|
|
37
|
-
const
|
|
38
|
+
const radioInput = wrapper.find('[data-testid="rke2-directory-config-radio-input"]');
|
|
38
39
|
const commonInput = wrapper.find('[data-testid="rke2-directory-config-common-data-dir"]');
|
|
39
40
|
const systemAgentInput = wrapper.find('[data-testid="rke2-directory-config-systemAgent-data-dir"]');
|
|
40
41
|
const provisioningInput = wrapper.find('[data-testid="rke2-directory-config-provisioning-data-dir"]');
|
|
41
42
|
const k8sDistroInput = wrapper.find('[data-testid="rke2-directory-config-k8sDistro-data-dir"]');
|
|
42
43
|
|
|
43
44
|
expect(title.exists()).toBe(true);
|
|
44
|
-
expect(
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
expect(
|
|
45
|
+
expect(radioInput.exists()).toBe(true);
|
|
46
|
+
|
|
47
|
+
// for the default config, the default radio input should be "default"
|
|
48
|
+
expect(wrapper.vm.dataConfigRadioValue).toBe(DATA_DIR_RADIO_OPTIONS.DEFAULT);
|
|
48
49
|
|
|
49
|
-
// since we have all of the vars empty, then the
|
|
50
|
+
// since we have all of the vars empty, then the inputs should not be there
|
|
51
|
+
expect(commonInput.exists()).toBe(false);
|
|
50
52
|
expect(systemAgentInput.exists()).toBe(false);
|
|
51
53
|
expect(provisioningInput.exists()).toBe(false);
|
|
52
54
|
expect(k8sDistroInput.exists()).toBe(false);
|
|
53
55
|
});
|
|
54
56
|
|
|
55
|
-
it('should
|
|
57
|
+
it('updating common base directory should set the correct values on each data dir variable', async() => {
|
|
56
58
|
const newMountOptions = clone(mountOptions);
|
|
57
59
|
|
|
58
|
-
newMountOptions.propsData.value = {};
|
|
59
|
-
|
|
60
|
-
wrapper = mount(
|
|
61
|
-
DirectoryConfig,
|
|
62
|
-
newMountOptions
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
const title = wrapper.find('h3');
|
|
66
|
-
const checkbox = wrapper.find('[data-testid="rke2-directory-config-individual-config-checkbox"]');
|
|
67
|
-
const commonInput = wrapper.find('[data-testid="rke2-directory-config-common-data-dir"]');
|
|
68
|
-
const systemAgentInput = wrapper.find('[data-testid="rke2-directory-config-systemAgent-data-dir"]');
|
|
69
|
-
const provisioningInput = wrapper.find('[data-testid="rke2-directory-config-provisioning-data-dir"]');
|
|
70
|
-
const k8sDistroInput = wrapper.find('[data-testid="rke2-directory-config-k8sDistro-data-dir"]');
|
|
71
|
-
|
|
72
|
-
expect(title.exists()).toBe(true);
|
|
73
|
-
expect(checkbox.exists()).toBe(true);
|
|
74
|
-
// for the default config, checkbox should be checked
|
|
75
|
-
expect(wrapper.vm.isSettingCommonConfig).toBe(true);
|
|
76
|
-
expect(commonInput.exists()).toBe(true);
|
|
77
|
-
|
|
78
|
-
// since we have all of the vars empty, then the individual inputs should not be there
|
|
79
|
-
expect(systemAgentInput.exists()).toBe(false);
|
|
80
|
-
expect(provisioningInput.exists()).toBe(false);
|
|
81
|
-
expect(k8sDistroInput.exists()).toBe(false);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it('updating common config path should set the correct values on each data dir variable', async() => {
|
|
85
60
|
wrapper = mount(
|
|
86
61
|
DirectoryConfig,
|
|
87
|
-
|
|
62
|
+
{
|
|
63
|
+
...newMountOptions,
|
|
64
|
+
// couldn't use setData, so this is the next best solution
|
|
65
|
+
data() {
|
|
66
|
+
return { dataConfigRadioValue: DATA_DIR_RADIO_OPTIONS.COMMON };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
88
69
|
);
|
|
89
70
|
|
|
90
71
|
const inputPath = 'some-data-dir';
|
|
91
72
|
const commonInput = wrapper.find('[data-testid="rke2-directory-config-common-data-dir"]');
|
|
92
73
|
|
|
74
|
+
// update base dir value
|
|
75
|
+
expect(commonInput.exists()).toBe(true);
|
|
93
76
|
commonInput.setValue(inputPath);
|
|
94
77
|
await nextTick();
|
|
95
78
|
|
|
96
|
-
expect(wrapper.vm.value.systemAgent).toStrictEqual(inputPath);
|
|
97
|
-
expect(wrapper.vm.value.provisioning).toStrictEqual(inputPath);
|
|
98
|
-
expect(wrapper.vm.value.k8sDistro).toStrictEqual(inputPath);
|
|
79
|
+
expect(wrapper.vm.value.systemAgent).toStrictEqual(`${ inputPath }/${ DEFAULT_SUBDIRS.AGENT }`);
|
|
80
|
+
expect(wrapper.vm.value.provisioning).toStrictEqual(`${ inputPath }/${ DEFAULT_SUBDIRS.PROVISIONING }`);
|
|
81
|
+
expect(wrapper.vm.value.k8sDistro).toStrictEqual(`${ inputPath }/${ DEFAULT_SUBDIRS.K8S_DISTRO_K3S }`);
|
|
99
82
|
});
|
|
100
83
|
|
|
101
84
|
it('updating each individual data dir should set the correct values on each data dir variable', async() => {
|
|
102
|
-
wrapper = mount(
|
|
103
|
-
DirectoryConfig,
|
|
104
|
-
mountOptions
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
const inputPath = 'some-data-dir';
|
|
108
|
-
const checkbox = wrapper.find('[data-testid="rke2-directory-config-individual-config-checkbox"]');
|
|
109
|
-
|
|
110
|
-
await checkbox.find('label').trigger('click');
|
|
111
|
-
await nextTick();
|
|
112
|
-
await nextTick();
|
|
113
|
-
|
|
114
|
-
expect(wrapper.vm.isSettingCommonConfig).toBe(false);
|
|
115
|
-
|
|
116
|
-
const systemAgentInput = wrapper.find('[data-testid="rke2-directory-config-systemAgent-data-dir"]');
|
|
117
|
-
const provisioningInput = wrapper.find('[data-testid="rke2-directory-config-provisioning-data-dir"]');
|
|
118
|
-
const k8sDistroInput = wrapper.find('[data-testid="rke2-directory-config-k8sDistro-data-dir"]');
|
|
119
|
-
|
|
120
|
-
systemAgentInput.setValue(inputPath);
|
|
121
|
-
provisioningInput.setValue(inputPath);
|
|
122
|
-
k8sDistroInput.setValue(inputPath);
|
|
123
|
-
await nextTick();
|
|
124
|
-
|
|
125
|
-
expect(wrapper.vm.value.systemAgent).toStrictEqual(inputPath);
|
|
126
|
-
expect(wrapper.vm.value.provisioning).toStrictEqual(inputPath);
|
|
127
|
-
expect(wrapper.vm.value.k8sDistro).toStrictEqual(inputPath);
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
it('checkbox should be checked if all data dir values are the same (with all data dir values filled)', () => {
|
|
131
85
|
const newMountOptions = clone(mountOptions);
|
|
132
|
-
const inputPath = 'some-data-dir';
|
|
133
|
-
|
|
134
|
-
newMountOptions.propsData.value.systemAgent = inputPath;
|
|
135
|
-
newMountOptions.propsData.value.provisioning = inputPath;
|
|
136
|
-
newMountOptions.propsData.value.k8sDistro = inputPath;
|
|
137
86
|
|
|
138
87
|
wrapper = mount(
|
|
139
88
|
DirectoryConfig,
|
|
140
|
-
|
|
89
|
+
{
|
|
90
|
+
...newMountOptions,
|
|
91
|
+
// couldn't use setData, so this is the next best solution
|
|
92
|
+
data() {
|
|
93
|
+
return { dataConfigRadioValue: DATA_DIR_RADIO_OPTIONS.CUSTOM };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
141
96
|
);
|
|
97
|
+
const inputPath = 'some-data-dir';
|
|
98
|
+
const agentValue = `${ inputPath }/${ DEFAULT_SUBDIRS.AGENT }`;
|
|
99
|
+
const provisioningValue = `${ inputPath }/${ DEFAULT_SUBDIRS.PROVISIONING }`;
|
|
100
|
+
const k8sDistroValue = `${ inputPath }/${ DEFAULT_SUBDIRS.K8S_DISTRO_RKE2 }`;
|
|
142
101
|
|
|
143
|
-
const checkbox = wrapper.find('[data-testid="rke2-directory-config-individual-config-checkbox"]');
|
|
144
|
-
|
|
145
|
-
expect(checkbox.exists()).toBe(true);
|
|
146
|
-
expect(wrapper.vm.isSettingCommonConfig).toBe(true);
|
|
147
|
-
|
|
148
|
-
const commonInput = wrapper.find('[data-testid="rke2-directory-config-common-data-dir"]');
|
|
149
102
|
const systemAgentInput = wrapper.find('[data-testid="rke2-directory-config-systemAgent-data-dir"]');
|
|
150
103
|
const provisioningInput = wrapper.find('[data-testid="rke2-directory-config-provisioning-data-dir"]');
|
|
151
104
|
const k8sDistroInput = wrapper.find('[data-testid="rke2-directory-config-k8sDistro-data-dir"]');
|
|
152
105
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
106
|
+
systemAgentInput.setValue(agentValue);
|
|
107
|
+
provisioningInput.setValue(provisioningValue);
|
|
108
|
+
k8sDistroInput.setValue(k8sDistroValue);
|
|
109
|
+
await nextTick();
|
|
157
110
|
|
|
158
|
-
expect(wrapper.vm.value.systemAgent).toStrictEqual(
|
|
159
|
-
expect(wrapper.vm.value.provisioning).toStrictEqual(
|
|
160
|
-
expect(wrapper.vm.value.k8sDistro).toStrictEqual(
|
|
111
|
+
expect(wrapper.vm.value.systemAgent).toStrictEqual(agentValue);
|
|
112
|
+
expect(wrapper.vm.value.provisioning).toStrictEqual(provisioningValue);
|
|
113
|
+
expect(wrapper.vm.value.k8sDistro).toStrictEqual(k8sDistroValue);
|
|
161
114
|
});
|
|
162
115
|
|
|
163
|
-
it('
|
|
116
|
+
it('should render the component with configuration being an empty object, without errors and radio be of value DATA_DIR_RADIO_OPTIONS.DEFAULT (edit scenario)', () => {
|
|
164
117
|
const newMountOptions = clone(mountOptions);
|
|
165
|
-
const inputPath1 = 'some-data-dir1';
|
|
166
|
-
const inputPath2 = 'some-data-dir2';
|
|
167
|
-
const inputPath3 = 'some-data-dir3';
|
|
168
118
|
|
|
169
|
-
newMountOptions.propsData.value
|
|
170
|
-
newMountOptions.propsData.
|
|
171
|
-
newMountOptions.propsData.value.k8sDistro = inputPath3;
|
|
119
|
+
newMountOptions.propsData.value = {};
|
|
120
|
+
newMountOptions.propsData.mode = _EDIT;
|
|
172
121
|
|
|
173
122
|
wrapper = mount(
|
|
174
123
|
DirectoryConfig,
|
|
175
124
|
newMountOptions
|
|
176
125
|
);
|
|
177
126
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const commonInput = wrapper.find('[data-testid="rke2-directory-config-common-data-dir"]');
|
|
127
|
+
const title = wrapper.find('h3');
|
|
128
|
+
const radioInput = wrapper.find('[data-testid="rke2-directory-config-radio-input"]');
|
|
181
129
|
const systemAgentInput = wrapper.find('[data-testid="rke2-directory-config-systemAgent-data-dir"]');
|
|
182
130
|
const provisioningInput = wrapper.find('[data-testid="rke2-directory-config-provisioning-data-dir"]');
|
|
183
131
|
const k8sDistroInput = wrapper.find('[data-testid="rke2-directory-config-k8sDistro-data-dir"]');
|
|
184
132
|
|
|
185
|
-
expect(
|
|
186
|
-
expect(
|
|
187
|
-
expect(provisioningInput.exists()).toBe(true);
|
|
188
|
-
expect(k8sDistroInput.exists()).toBe(true);
|
|
189
|
-
|
|
190
|
-
expect(wrapper.vm.value.systemAgent).toStrictEqual(inputPath1);
|
|
191
|
-
expect(wrapper.vm.value.provisioning).toStrictEqual(inputPath2);
|
|
192
|
-
expect(wrapper.vm.value.k8sDistro).toStrictEqual(inputPath3);
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
it('on a mode different than _CREATE all visible inputs should be disabled (with common config)', () => {
|
|
196
|
-
const newMountOptions = clone(mountOptions);
|
|
197
|
-
const inputPath = 'some-data-dir';
|
|
198
|
-
|
|
199
|
-
newMountOptions.propsData.value.systemAgent = inputPath;
|
|
200
|
-
newMountOptions.propsData.value.provisioning = inputPath;
|
|
201
|
-
newMountOptions.propsData.value.k8sDistro = inputPath;
|
|
202
|
-
newMountOptions.propsData.mode = _EDIT;
|
|
203
|
-
|
|
204
|
-
wrapper = mount(
|
|
205
|
-
DirectoryConfig,
|
|
206
|
-
newMountOptions
|
|
207
|
-
);
|
|
133
|
+
expect(title.exists()).toBe(true);
|
|
134
|
+
expect(radioInput.exists()).toBe(true);
|
|
208
135
|
|
|
209
|
-
|
|
210
|
-
const commonInput = wrapper.find('[data-testid="rke2-directory-config-common-data-dir"]');
|
|
211
|
-
const systemAgentInput = wrapper.find('[data-testid="rke2-directory-config-systemAgent-data-dir"]');
|
|
212
|
-
const provisioningInput = wrapper.find('[data-testid="rke2-directory-config-provisioning-data-dir"]');
|
|
213
|
-
const k8sDistroInput = wrapper.find('[data-testid="rke2-directory-config-k8sDistro-data-dir"]');
|
|
136
|
+
expect(wrapper.vm.dataConfigRadioValue).toBe(DATA_DIR_RADIO_OPTIONS.DEFAULT);
|
|
214
137
|
|
|
215
|
-
|
|
216
|
-
expect(commonInput.exists()).toBe(true);
|
|
138
|
+
// since we have all of the vars empty, then the inputs should not be there
|
|
217
139
|
expect(systemAgentInput.exists()).toBe(false);
|
|
218
140
|
expect(provisioningInput.exists()).toBe(false);
|
|
219
141
|
expect(k8sDistroInput.exists()).toBe(false);
|
|
220
|
-
|
|
221
|
-
expect(checkbox.find('label').classes('disabled')).toBe(true);
|
|
222
|
-
expect(commonInput.attributes('disabled')).toBe('');
|
|
223
142
|
});
|
|
224
143
|
|
|
225
|
-
it('
|
|
144
|
+
it('radio input should be set to DATA_DIR_RADIO_OPTIONS.CUSTOM with all data dir values existing and different (edit scenario)', async() => {
|
|
226
145
|
const newMountOptions = clone(mountOptions);
|
|
227
|
-
const
|
|
228
|
-
const inputPath2 = 'some-data-dir2';
|
|
229
|
-
const inputPath3 = 'some-data-dir3';
|
|
146
|
+
const inputPath = 'some-data-dir';
|
|
230
147
|
|
|
231
|
-
newMountOptions.propsData.value.systemAgent =
|
|
232
|
-
newMountOptions.propsData.value.provisioning =
|
|
233
|
-
newMountOptions.propsData.value.k8sDistro =
|
|
148
|
+
newMountOptions.propsData.value.systemAgent = `${ inputPath }/${ DEFAULT_SUBDIRS.AGENT }`;
|
|
149
|
+
newMountOptions.propsData.value.provisioning = `${ inputPath }/${ DEFAULT_SUBDIRS.PROVISIONING }`;
|
|
150
|
+
newMountOptions.propsData.value.k8sDistro = `${ inputPath }/${ DEFAULT_SUBDIRS.K8S_DISTRO_K3S }`;
|
|
234
151
|
newMountOptions.propsData.mode = _EDIT;
|
|
235
152
|
|
|
236
153
|
wrapper = mount(
|
|
@@ -238,21 +155,18 @@ describe('component: DirectoryConfig', () => {
|
|
|
238
155
|
newMountOptions
|
|
239
156
|
);
|
|
240
157
|
|
|
241
|
-
|
|
242
|
-
|
|
158
|
+
expect(wrapper.vm.dataConfigRadioValue).toBe(DATA_DIR_RADIO_OPTIONS.CUSTOM);
|
|
159
|
+
|
|
243
160
|
const systemAgentInput = wrapper.find('[data-testid="rke2-directory-config-systemAgent-data-dir"]');
|
|
244
161
|
const provisioningInput = wrapper.find('[data-testid="rke2-directory-config-provisioning-data-dir"]');
|
|
245
162
|
const k8sDistroInput = wrapper.find('[data-testid="rke2-directory-config-k8sDistro-data-dir"]');
|
|
246
163
|
|
|
247
|
-
expect(
|
|
248
|
-
expect(
|
|
249
|
-
expect(
|
|
250
|
-
expect(provisioningInput.exists()).toBe(true);
|
|
251
|
-
expect(k8sDistroInput.exists()).toBe(true);
|
|
164
|
+
expect(systemAgentInput.isVisible()).toBe(true);
|
|
165
|
+
expect(provisioningInput.isVisible()).toBe(true);
|
|
166
|
+
expect(k8sDistroInput.isVisible()).toBe(true);
|
|
252
167
|
|
|
253
|
-
expect(
|
|
254
|
-
expect(
|
|
255
|
-
expect(
|
|
256
|
-
expect(k8sDistroInput.attributes('disabled')).toBe('');
|
|
168
|
+
expect(wrapper.vm.value.systemAgent).toStrictEqual(`${ inputPath }/${ DEFAULT_SUBDIRS.AGENT }`);
|
|
169
|
+
expect(wrapper.vm.value.provisioning).toStrictEqual(`${ inputPath }/${ DEFAULT_SUBDIRS.PROVISIONING }`);
|
|
170
|
+
expect(wrapper.vm.value.k8sDistro).toStrictEqual(`${ inputPath }/${ DEFAULT_SUBDIRS.K8S_DISTRO_K3S }`);
|
|
257
171
|
});
|
|
258
172
|
});
|
|
@@ -62,6 +62,7 @@ import Upgrade from '@shell/edit/provisioning.cattle.io.cluster/tabs/upgrade';
|
|
|
62
62
|
import Registries from '@shell/edit/provisioning.cattle.io.cluster/tabs/registries';
|
|
63
63
|
import AddOnConfig from '@shell/edit/provisioning.cattle.io.cluster/tabs/AddOnConfig';
|
|
64
64
|
import Advanced from '@shell/edit/provisioning.cattle.io.cluster/tabs/Advanced';
|
|
65
|
+
import { DEFAULT_COMMON_BASE_PATH, DEFAULT_SUBDIRS } from '@shell/edit/provisioning.cattle.io.cluster/tabs/DirectoryConfig';
|
|
65
66
|
import ClusterAppearance from '@shell/components/form/ClusterAppearance';
|
|
66
67
|
import AddOnAdditionalManifest from '@shell/edit/provisioning.cattle.io.cluster/tabs/AddOnAdditionalManifest';
|
|
67
68
|
import VsphereUtils from '@shell/utils/v-sphere';
|
|
@@ -1483,7 +1484,8 @@ export default {
|
|
|
1483
1484
|
set(this.chartValues, `${ HARVESTER_CLOUD_PROVIDER }.global.cattle.clusterName`, this.value.metadata.name);
|
|
1484
1485
|
}
|
|
1485
1486
|
|
|
1486
|
-
const
|
|
1487
|
+
const distroSubdir = this.value?.spec?.kubernetesVersion?.includes('k3s') ? DEFAULT_SUBDIRS.K8S_DISTRO_K3S : DEFAULT_SUBDIRS.K8S_DISTRO_RKE2;
|
|
1488
|
+
const distroRoot = this.value?.spec?.rkeConfig?.dataDirectories?.k8sDistro?.length ? this.value?.spec?.rkeConfig?.dataDirectories?.k8sDistro : `${ DEFAULT_COMMON_BASE_PATH }/${ distroSubdir }`;
|
|
1487
1489
|
|
|
1488
1490
|
set(this.chartValues, `${ HARVESTER_CLOUD_PROVIDER }.cloudConfigPath`, `${ distroRoot }/etc/config-files/cloud-provider-config`);
|
|
1489
1491
|
}
|
|
@@ -80,10 +80,14 @@ export default {
|
|
|
80
80
|
return i !== 0 || !this.agentConfig;
|
|
81
81
|
},
|
|
82
82
|
showEmptyKubeletArg(config) {
|
|
83
|
-
return !this.
|
|
83
|
+
return !this.serverArgs?.['kubelet-arg']?.length && !config?.['kubelet-arg']?.length;
|
|
84
84
|
},
|
|
85
85
|
onInputProtectKernelDefaults(value) {
|
|
86
|
-
this.agentConfig
|
|
86
|
+
if (this.agentConfig && this.agentConfig['protect-kernel-defaults'] !== undefined ) {
|
|
87
|
+
this.agentConfig['protect-kernel-defaults'] = value;
|
|
88
|
+
} else {
|
|
89
|
+
this.serverConfig['protect-kernel-defaults'] = value;
|
|
90
|
+
}
|
|
87
91
|
}
|
|
88
92
|
}
|
|
89
93
|
};
|
|
@@ -100,6 +104,7 @@ export default {
|
|
|
100
104
|
<template v-if="haveArgInfo">
|
|
101
105
|
<DirectoryConfig
|
|
102
106
|
v-model:value="value.spec.rkeConfig.dataDirectories"
|
|
107
|
+
:k8s-version="value.spec.kubernetesVersion"
|
|
103
108
|
:mode="mode"
|
|
104
109
|
/>
|
|
105
110
|
<h3>{{ t('cluster.advanced.argInfo.title') }}</h3>
|