@rancher/shell 3.0.9-rc.5 → 3.0.9-rc.6
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/providers/oci-open-containers.svg +22 -0
- package/assets/images/providers/traefik.png +0 -0
- package/assets/styles/themes/_dark.scss +2 -0
- package/assets/styles/themes/_light.scss +2 -0
- package/assets/styles/themes/_modern.scss +6 -0
- package/assets/translations/en-us.yaml +129 -25
- package/components/CruResource.vue +3 -1
- package/components/ExplorerProjectsNamespaces.vue +12 -12
- package/components/Resource/Detail/Card/StatusCard/__tests__/StatusCard.test.ts +109 -0
- package/components/Resource/Detail/Card/StatusCard/index.vue +21 -4
- package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/identifying-fields.test.ts +19 -2
- package/components/Resource/Detail/Metadata/IdentifyingInformation/identifying-fields.ts +19 -11
- package/components/Resource/Detail/ResourcePopover/__tests__/index.test.ts +12 -0
- package/components/Resource/Detail/ResourcePopover/index.vue +2 -0
- package/components/Resource/Detail/ResourceRow.vue +2 -2
- package/components/ResourceList/index.vue +7 -4
- package/components/Window/ContainerLogs.vue +48 -37
- package/components/fleet/FleetClusterTargets/TargetsList.vue +2 -2
- package/components/fleet/FleetClusterTargets/index.vue +6 -1
- package/components/fleet/GitRepoAdvancedTab.vue +333 -0
- package/components/fleet/GitRepoMetadataTab.vue +43 -0
- package/components/fleet/GitRepoRepositoryTab.vue +101 -0
- package/components/fleet/GitRepoTargetTab.vue +77 -0
- package/components/fleet/HelmOpAdvancedTab.vue +247 -0
- package/components/fleet/HelmOpChartTab.vue +158 -0
- package/components/fleet/HelmOpMetadataTab.vue +46 -0
- package/components/fleet/HelmOpTargetTab.vue +84 -0
- package/components/fleet/HelmOpValuesTab.vue +147 -0
- package/components/fleet/__tests__/FleetClusterTargets.test.ts +119 -70
- package/components/form/NodeScheduling.vue +81 -7
- package/components/form/PodAffinity.vue +1 -36
- package/components/form/ResourceLabeledSelect.vue +8 -4
- package/components/form/ResourceQuota/Namespace.vue +30 -9
- package/components/form/ResourceQuota/NamespaceRow.vue +25 -7
- package/components/form/ResourceQuota/Project.vue +140 -82
- package/components/form/ResourceQuota/ResourceQuotaEntry.vue +145 -0
- package/components/form/ResourceQuota/__tests__/Namespace.test.ts +307 -0
- package/components/form/ResourceQuota/__tests__/NamespaceRow.test.ts +281 -0
- package/components/form/ResourceQuota/__tests__/Project.test.ts +274 -27
- package/components/form/ResourceQuota/__tests__/ResourceQuotaEntry.test.ts +215 -0
- package/components/form/SchedulingCustomization.vue +14 -6
- package/components/form/SelectOrCreateAuthSecret.vue +107 -18
- package/components/form/__tests__/NodeScheduling.test.ts +12 -9
- package/components/form/__tests__/PodAffinity.test.ts +21 -2
- package/components/form/__tests__/SchedulingCustomization.test.ts +240 -0
- package/components/formatter/ClusterLink.vue +8 -0
- package/components/formatter/SecretOrigin.vue +79 -0
- package/config/labels-annotations.js +7 -6
- package/config/pagination-table-headers.js +6 -4
- package/config/product/explorer.js +1 -11
- package/config/query-params.js +3 -0
- package/config/settings.ts +15 -2
- package/config/table-headers.js +21 -17
- package/config/types.js +23 -8
- package/detail/workload/index.vue +11 -16
- package/dialog/DeactivateDriverDialog.vue +1 -1
- package/dialog/Ipv6NetworkingDialog.vue +156 -0
- package/dialog/ScalePoolDownDialog.vue +2 -2
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +1 -1
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +1 -0
- package/edit/__tests__/management.cattle.io.project.test.js +56 -128
- package/edit/auth/oidc.vue +1 -1
- package/edit/catalog.cattle.io.clusterrepo.vue +155 -25
- package/edit/fleet.cattle.io.gitrepo.vue +153 -283
- package/edit/fleet.cattle.io.helmop.vue +190 -332
- package/edit/management.cattle.io.project.vue +5 -42
- package/edit/management.cattle.io.setting.vue +6 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/Basics.test.ts +55 -24
- package/edit/provisioning.cattle.io.cluster/__tests__/Networking.test.ts +1 -103
- package/edit/provisioning.cattle.io.cluster/__tests__/index.test.ts +13 -1
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2-fleet-cluster-agent.test.ts +283 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +65 -49
- package/edit/provisioning.cattle.io.cluster/ingress/IngressCards.vue +112 -0
- package/edit/provisioning.cattle.io.cluster/ingress/IngressConfiguration.vue +158 -0
- package/edit/provisioning.cattle.io.cluster/rke2.vue +171 -72
- package/edit/provisioning.cattle.io.cluster/shared.ts +36 -1
- package/edit/provisioning.cattle.io.cluster/tabs/AgentConfiguration.vue +2 -1
- package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +55 -7
- package/edit/provisioning.cattle.io.cluster/tabs/Ingress.vue +319 -0
- package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +2 -1
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/__tests__/S3Config.test.ts +13 -1
- package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +10 -44
- package/edit/secret/index.vue +1 -1
- package/edit/token.vue +68 -29
- package/edit/workload/__tests__/index.test.ts +2 -37
- package/edit/workload/index.vue +6 -2
- package/edit/workload/mixins/workload.js +0 -32
- package/list/__tests__/management.cattle.io.setting.test.ts +198 -0
- package/list/management.cattle.io.setting.vue +13 -0
- package/list/provisioning.cattle.io.cluster.vue +50 -1
- package/list/secret.vue +4 -9
- package/list/service.vue +6 -8
- package/machine-config/amazonec2.vue +11 -4
- package/machine-config/components/EC2Networking.vue +46 -30
- package/machine-config/components/__tests__/EC2Networking.test.ts +7 -7
- package/machine-config/components/__tests__/utils/vpcSubnetMockData.js +0 -9
- package/machine-config/digitalocean.vue +3 -3
- package/models/__tests__/namespace.test.ts +11 -0
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +96 -0
- package/models/__tests__/workload.test.ts +42 -1
- package/models/catalog.cattle.io.clusterrepo.js +30 -4
- package/models/ext.cattle.io.token.js +48 -0
- package/models/kontainerdriver.js +2 -2
- package/models/namespace.js +7 -1
- package/models/nodedriver.js +2 -2
- package/models/provisioning.cattle.io.cluster.js +28 -7
- package/models/secret.js +0 -17
- package/models/service.js +44 -1
- package/models/token.js +4 -0
- package/models/workload.js +12 -6
- package/package.json +1 -1
- package/pages/account/index.vue +96 -67
- package/pages/auth/setup.vue +5 -14
- package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +4 -1
- package/pages/c/_cluster/apps/charts/index.vue +93 -4
- package/pages/c/_cluster/apps/charts/install.vue +317 -42
- package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +5 -4
- package/pages/c/_cluster/settings/index.vue +3 -1
- package/plugins/dashboard-store/__tests__/getters.test.ts +108 -0
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +27 -0
- package/plugins/dashboard-store/actions.js +3 -8
- package/plugins/dashboard-store/getters.js +7 -5
- package/plugins/dashboard-store/mutations.js +4 -1
- package/plugins/dashboard-store/resource-class.js +3 -3
- package/plugins/steve/__tests__/steve-class.test.ts +102 -141
- package/plugins/steve/steve-class.js +12 -3
- package/plugins/steve/steve-pagination-utils.ts +6 -2
- package/rancher-components/RcIcon/types.ts +2 -0
- package/rancher-components/RcItemCard/RcItemCard.vue +64 -19
- package/store/prefs.js +3 -0
- package/types/aws-sdk.d.ts +121 -0
- package/types/resources/node.ts +15 -0
- package/types/shell/index.d.ts +536 -506
- package/types/store/pagination.types.ts +5 -5
- package/utils/__tests__/array.test.ts +1 -29
- package/utils/__tests__/cluster-agent-configuration.test.ts +203 -0
- package/utils/array.ts +0 -11
- package/utils/aws.ts +21 -0
- package/utils/cluster.js +22 -2
- package/utils/selector-typed.ts +1 -1
- package/components/__tests__/ProjectRow.test.ts +0 -206
- package/components/form/ResourceQuota/ProjectRow.vue +0 -277
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { shallowMount } from '@vue/test-utils';
|
|
2
|
+
import { createStore } from 'vuex';
|
|
3
|
+
import ResourceQuotaEntry from '@shell/components/form/ResourceQuota/ResourceQuotaEntry.vue';
|
|
4
|
+
import { LabeledInput } from '@components/Form/LabeledInput';
|
|
5
|
+
import { RcButton } from '@components/RcButton';
|
|
6
|
+
import { TYPES } from '@shell/components/form/ResourceQuota/shared';
|
|
7
|
+
|
|
8
|
+
describe('component: ResourceQuotaEntry', () => {
|
|
9
|
+
const store = createStore({});
|
|
10
|
+
|
|
11
|
+
const mockType = {
|
|
12
|
+
value: 'configMaps',
|
|
13
|
+
inputExponent: 0,
|
|
14
|
+
baseUnit: '',
|
|
15
|
+
placeholder: 'Enter count',
|
|
16
|
+
increment: 1,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const podsType = {
|
|
20
|
+
value: 'pods',
|
|
21
|
+
inputExponent: 0,
|
|
22
|
+
baseUnit: '',
|
|
23
|
+
placeholder: 'Enter count',
|
|
24
|
+
increment: 1,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const limitsCpuType = {
|
|
28
|
+
value: 'limitsCpu',
|
|
29
|
+
inputExponent: -1,
|
|
30
|
+
baseUnit: '',
|
|
31
|
+
placeholder: 'Enter CPU',
|
|
32
|
+
increment: 1,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const extendedType = {
|
|
36
|
+
value: TYPES.EXTENDED,
|
|
37
|
+
inputExponent: 0,
|
|
38
|
+
baseUnit: '',
|
|
39
|
+
placeholder: 'Enter value',
|
|
40
|
+
increment: 1,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const allTypes = [mockType, podsType, limitsCpuType, extendedType];
|
|
44
|
+
|
|
45
|
+
const defaultProps = {
|
|
46
|
+
id: '1',
|
|
47
|
+
mode: 'edit',
|
|
48
|
+
types: allTypes,
|
|
49
|
+
resourceType: 'configMaps',
|
|
50
|
+
resourceIdentifier: 'configMaps',
|
|
51
|
+
projectLimit: '20',
|
|
52
|
+
namespaceDefaultLimit: '10',
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const createWrapper = (propsOverrides: Record<string, unknown> = {}) => {
|
|
56
|
+
return shallowMount(ResourceQuotaEntry, {
|
|
57
|
+
props: { ...defaultProps, ...propsOverrides },
|
|
58
|
+
global: { provide: { store } },
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
describe('rendering', () => {
|
|
63
|
+
it('should render all input fields with their data-testid attributes', () => {
|
|
64
|
+
const wrapper = createWrapper();
|
|
65
|
+
|
|
66
|
+
expect(wrapper.find('[data-testid="projectrow-type-input"]').exists()).toBe(true);
|
|
67
|
+
expect(wrapper.find('[data-testid="projectrow-custom-type-input"]').exists()).toBe(true);
|
|
68
|
+
expect(wrapper.find('[data-testid="projectrow-project-quota-input"]').exists()).toBe(true);
|
|
69
|
+
expect(wrapper.find('[data-testid="projectrow-namespace-quota-input"]').exists()).toBe(true);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe('computed: typeOption', () => {
|
|
74
|
+
it('should return the matching type option for a given resourceType', () => {
|
|
75
|
+
const wrapper = createWrapper({ resourceType: 'configMaps' });
|
|
76
|
+
|
|
77
|
+
expect((wrapper.vm as any).typeOption).toStrictEqual(mockType);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should return the extended type option when resourceType is TYPES.EXTENDED', () => {
|
|
81
|
+
const wrapper = createWrapper({ resourceType: TYPES.EXTENDED });
|
|
82
|
+
|
|
83
|
+
expect((wrapper.vm as any).typeOption).toStrictEqual(extendedType);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe('computed: isCustom', () => {
|
|
88
|
+
it('should return true when resourceType equals TYPES.EXTENDED', () => {
|
|
89
|
+
const wrapper = createWrapper({ resourceType: TYPES.EXTENDED });
|
|
90
|
+
|
|
91
|
+
expect((wrapper.vm as any).isCustom).toBe(true);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it.each([
|
|
95
|
+
['configMaps'],
|
|
96
|
+
['pods'],
|
|
97
|
+
['limitsCpu'],
|
|
98
|
+
])('should return false when resourceType is "%s"', (resourceType) => {
|
|
99
|
+
const wrapper = createWrapper({ resourceType });
|
|
100
|
+
|
|
101
|
+
expect((wrapper.vm as any).isCustom).toBe(false);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe('computed: customTypeRules', () => {
|
|
106
|
+
it('should return an empty array when resourceType is a standard type', () => {
|
|
107
|
+
const wrapper = createWrapper({ resourceType: 'configMaps' });
|
|
108
|
+
|
|
109
|
+
expect((wrapper.vm as any).customTypeRules).toStrictEqual([]);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should return one validation rule when resourceType is TYPES.EXTENDED', () => {
|
|
113
|
+
const wrapper = createWrapper({ resourceType: TYPES.EXTENDED });
|
|
114
|
+
|
|
115
|
+
expect((wrapper.vm as any).customTypeRules).toHaveLength(1);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe('validation rule behavior for custom type', () => {
|
|
119
|
+
it.each([
|
|
120
|
+
['', 'resourceQuota.errors.customTypeRequired'],
|
|
121
|
+
[null, 'resourceQuota.errors.customTypeRequired'],
|
|
122
|
+
[undefined, 'resourceQuota.errors.customTypeRequired'],
|
|
123
|
+
])('should return an error message for falsy value "%s"', (value, expectedError) => {
|
|
124
|
+
const wrapper = createWrapper({ resourceType: TYPES.EXTENDED });
|
|
125
|
+
const [rule] = (wrapper.vm as any).customTypeRules;
|
|
126
|
+
|
|
127
|
+
expect(rule(value)).toBe(expectedError);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it.each([
|
|
131
|
+
['my-resource'],
|
|
132
|
+
['cpu'],
|
|
133
|
+
['custom.resource/name'],
|
|
134
|
+
])('should return undefined for non-empty value "%s"', (value) => {
|
|
135
|
+
const wrapper = createWrapper({ resourceType: TYPES.EXTENDED });
|
|
136
|
+
const [rule] = (wrapper.vm as any).customTypeRules;
|
|
137
|
+
|
|
138
|
+
expect(rule(value)).toBeUndefined();
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
describe('method: remove', () => {
|
|
144
|
+
it('should emit remove event with the resource quota id', () => {
|
|
145
|
+
const id = 'test-remove-id';
|
|
146
|
+
const wrapper = createWrapper({ id });
|
|
147
|
+
|
|
148
|
+
(wrapper.vm as any).remove(id);
|
|
149
|
+
|
|
150
|
+
expect(wrapper.emitted('remove')).toBeTruthy();
|
|
151
|
+
expect(wrapper.emitted('remove')![0]).toStrictEqual([id]);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('should emit remove when the Remove button is clicked', async() => {
|
|
155
|
+
const id = 'click-test-id';
|
|
156
|
+
const wrapper = createWrapper({ id });
|
|
157
|
+
|
|
158
|
+
await wrapper.findComponent(RcButton as any).trigger('click');
|
|
159
|
+
|
|
160
|
+
expect(wrapper.emitted('remove')).toBeTruthy();
|
|
161
|
+
expect(wrapper.emitted('remove')![0]).toStrictEqual([id]);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
describe('method: updateResourceIdentifier', () => {
|
|
166
|
+
it('should emit update:resourceIdentifier with the new type for standard types', () => {
|
|
167
|
+
const wrapper = createWrapper({ resourceType: 'configMaps' });
|
|
168
|
+
|
|
169
|
+
(wrapper.vm as any).updateResourceIdentifier('pods');
|
|
170
|
+
|
|
171
|
+
expect(wrapper.emitted('update:resourceIdentifier')).toBeTruthy();
|
|
172
|
+
expect(wrapper.emitted('update:resourceIdentifier')![0]).toStrictEqual(['pods']);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('should not emit update:resourceIdentifier when called with TYPES.EXTENDED', () => {
|
|
176
|
+
const wrapper = createWrapper({ resourceType: TYPES.EXTENDED });
|
|
177
|
+
|
|
178
|
+
(wrapper.vm as any).updateResourceIdentifier(TYPES.EXTENDED);
|
|
179
|
+
|
|
180
|
+
expect(wrapper.emitted('update:resourceIdentifier')).toBeFalsy();
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
describe('template: LabeledInput disabled state', () => {
|
|
185
|
+
it('should have the identifier input disabled when resourceType is a standard type', () => {
|
|
186
|
+
const wrapper = createWrapper({ resourceType: 'configMaps' });
|
|
187
|
+
const input = wrapper.findComponent(LabeledInput as any);
|
|
188
|
+
|
|
189
|
+
expect(input.props('disabled')).toBe(true);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('should not have the identifier input disabled when resourceType is TYPES.EXTENDED', () => {
|
|
193
|
+
const wrapper = createWrapper({ resourceType: TYPES.EXTENDED });
|
|
194
|
+
const input = wrapper.findComponent(LabeledInput as any);
|
|
195
|
+
|
|
196
|
+
expect(input.props('disabled')).toBe(false);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
describe('template: LabeledInput required state', () => {
|
|
201
|
+
it('should have the identifier input required when resourceType is TYPES.EXTENDED', () => {
|
|
202
|
+
const wrapper = createWrapper({ resourceType: TYPES.EXTENDED });
|
|
203
|
+
const input = wrapper.findComponent(LabeledInput as any);
|
|
204
|
+
|
|
205
|
+
expect(input.props('required')).toBe(true);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it('should not have the identifier input required when resourceType is a standard type', () => {
|
|
209
|
+
const wrapper = createWrapper({ resourceType: 'configMaps' });
|
|
210
|
+
const input = wrapper.findComponent(LabeledInput as any);
|
|
211
|
+
|
|
212
|
+
expect(input.props('required')).toBe(false);
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
});
|
|
@@ -7,6 +7,10 @@ export default {
|
|
|
7
7
|
components: { Checkbox, Banner },
|
|
8
8
|
emits: ['scheduling-customization-changed'],
|
|
9
9
|
props: {
|
|
10
|
+
type: {
|
|
11
|
+
type: String,
|
|
12
|
+
required: true,
|
|
13
|
+
},
|
|
10
14
|
value: {
|
|
11
15
|
type: Object,
|
|
12
16
|
default: () => {},
|
|
@@ -26,6 +30,10 @@ export default {
|
|
|
26
30
|
defaultPDB: {
|
|
27
31
|
type: Object,
|
|
28
32
|
default: () => {},
|
|
33
|
+
},
|
|
34
|
+
checkboxWithOnlyAgentName: {
|
|
35
|
+
type: Boolean,
|
|
36
|
+
default: false
|
|
29
37
|
}
|
|
30
38
|
},
|
|
31
39
|
data() {
|
|
@@ -59,10 +67,10 @@ export default {
|
|
|
59
67
|
<Checkbox
|
|
60
68
|
:value="enabled"
|
|
61
69
|
:mode="mode"
|
|
62
|
-
label
|
|
63
|
-
|
|
70
|
+
:label="checkboxWithOnlyAgentName ? t(`cluster.agentConfig.subGroups.agentsScheduling.${type}`) : t('cluster.agentConfig.subGroups.agentsScheduling.label', { agent: t(`cluster.agentConfig.subGroups.agentsScheduling.${type}`)})"
|
|
71
|
+
:description="checkboxWithOnlyAgentName ? '' :t('cluster.agentConfig.subGroups.agentsScheduling.description', { agent: t(`cluster.agentConfig.subGroups.agentsScheduling.${type}`)})"
|
|
64
72
|
data-testid="scheduling-customization-checkbox"
|
|
65
|
-
@update:value="$emit('scheduling-customization-changed', $event)"
|
|
73
|
+
@update:value="$emit('scheduling-customization-changed', { event: $event, agentType: type })"
|
|
66
74
|
>
|
|
67
75
|
<template
|
|
68
76
|
v-if="feature && isEdit && settingMissmatch"
|
|
@@ -71,13 +79,13 @@ export default {
|
|
|
71
79
|
<Banner
|
|
72
80
|
class="mt-10 mb-10"
|
|
73
81
|
color="info"
|
|
74
|
-
label
|
|
82
|
+
:label="t('cluster.agentConfig.subGroups.agentsScheduling.banner', { agent: t(`cluster.agentConfig.subGroups.agentsScheduling.${type}`)})"
|
|
75
83
|
/>
|
|
76
84
|
<Checkbox
|
|
77
85
|
:value="applyGlobal"
|
|
78
86
|
:mode="mode"
|
|
79
|
-
label
|
|
80
|
-
@update:value="$emit('scheduling-customization-changed',
|
|
87
|
+
:label="t('cluster.agentConfig.subGroups.agentsScheduling.innerCheckbox', { agent: t(`cluster.agentConfig.subGroups.agentsScheduling.${type}`)})"
|
|
88
|
+
@update:value="$emit('scheduling-customization-changed', { event: $event, agentType: type })"
|
|
81
89
|
/>
|
|
82
90
|
</template>
|
|
83
91
|
</Checkbox>
|
|
@@ -71,6 +71,11 @@ export default {
|
|
|
71
71
|
default: 'auth-',
|
|
72
72
|
},
|
|
73
73
|
|
|
74
|
+
clientGeneratedName: {
|
|
75
|
+
type: String,
|
|
76
|
+
default: null,
|
|
77
|
+
},
|
|
78
|
+
|
|
74
79
|
allowNone: {
|
|
75
80
|
type: Boolean,
|
|
76
81
|
default: true,
|
|
@@ -150,6 +155,42 @@ export default {
|
|
|
150
155
|
default: false,
|
|
151
156
|
},
|
|
152
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Used specifically to fix the HTTP BASIC auth to generate specific authentication
|
|
160
|
+
* This is used to clear up the SELECT to make sure it only has HTTP BASIC with some special conditions
|
|
161
|
+
*/
|
|
162
|
+
fixedHttpBasicAuth: {
|
|
163
|
+
type: Boolean,
|
|
164
|
+
default: false,
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
/** Used together with fixedHttpBasicAuth
|
|
168
|
+
* It will filter all the cases to use this specific label at the start.
|
|
169
|
+
*/
|
|
170
|
+
filterBasicAuth: {
|
|
171
|
+
type: String,
|
|
172
|
+
default: '',
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* This works similar to other allow* but this makes specific to create as ImagePullSecret since it is specific for one page that only uses it
|
|
177
|
+
* To avoid using it in other places.
|
|
178
|
+
*/
|
|
179
|
+
fixedImagePullSecret: {
|
|
180
|
+
type: Boolean,
|
|
181
|
+
default: false,
|
|
182
|
+
},
|
|
183
|
+
/**
|
|
184
|
+
* Whenever the fixedImagePullSecret is setup the dockerJsonUrlConfig needs to be passed that will be used to create the DockerJsonConfig file
|
|
185
|
+
*/
|
|
186
|
+
imagePullSecretDockerJsonUrlConfig: {
|
|
187
|
+
type: String,
|
|
188
|
+
default: '',
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Specific property to change labels if it is Github.com repository
|
|
193
|
+
*/
|
|
153
194
|
isGithubDotComRepository: {
|
|
154
195
|
type: Boolean,
|
|
155
196
|
default: false,
|
|
@@ -157,7 +198,7 @@ export default {
|
|
|
157
198
|
},
|
|
158
199
|
|
|
159
200
|
async fetch() {
|
|
160
|
-
if ( (this.allowSsh || this.allowBasic || this.allowRke) && this.$store.getters[`${ this.inStore }/schemaFor`](SECRET) ) {
|
|
201
|
+
if ( (this.allowSsh || this.allowBasic || this.allowRke || this.fixedImagePullSecret) && this.$store.getters[`${ this.inStore }/schemaFor`](SECRET) ) {
|
|
161
202
|
if (this.$store.getters[`${ this.inStore }/paginationEnabled`](SECRET)) {
|
|
162
203
|
// Filter results via api (because we shouldn't be fetching them all...)
|
|
163
204
|
this.filteredSecrets = await this.filterSecretsByApi();
|
|
@@ -200,6 +241,8 @@ export default {
|
|
|
200
241
|
|
|
201
242
|
selected: null,
|
|
202
243
|
|
|
244
|
+
previousValue: null,
|
|
245
|
+
|
|
203
246
|
filterByNamespace: this.namespace && this.limitToNamespace,
|
|
204
247
|
|
|
205
248
|
publicKey: '',
|
|
@@ -207,10 +250,11 @@ export default {
|
|
|
207
250
|
sshKnownHosts: '',
|
|
208
251
|
uniqueId: new Date().getTime(), // Allows form state to be individually tracked if the form is in a list
|
|
209
252
|
|
|
210
|
-
SSH:
|
|
211
|
-
BASIC:
|
|
212
|
-
|
|
213
|
-
|
|
253
|
+
SSH: AUTH_TYPE._SSH,
|
|
254
|
+
BASIC: AUTH_TYPE._BASIC,
|
|
255
|
+
IMAGE_PULL_SECRET: AUTH_TYPE._IMAGE_PULL_SECRET,
|
|
256
|
+
S3: AUTH_TYPE._S3,
|
|
257
|
+
RKE: AUTH_TYPE._RKE,
|
|
214
258
|
};
|
|
215
259
|
},
|
|
216
260
|
|
|
@@ -218,6 +262,12 @@ export default {
|
|
|
218
262
|
secretTypes() {
|
|
219
263
|
const types = [];
|
|
220
264
|
|
|
265
|
+
if ( this.fixedImagePullSecret ) {
|
|
266
|
+
types.push(SECRET_TYPES.DOCKER_JSON);
|
|
267
|
+
|
|
268
|
+
return types;
|
|
269
|
+
}
|
|
270
|
+
|
|
221
271
|
if ( this.allowSsh ) {
|
|
222
272
|
types.push(SECRET_TYPES.SSH);
|
|
223
273
|
}
|
|
@@ -325,7 +375,7 @@ export default {
|
|
|
325
375
|
});
|
|
326
376
|
}
|
|
327
377
|
|
|
328
|
-
if (this.allowSsh || this.allowS3 || this.allowBasic || this.allowRke) {
|
|
378
|
+
if (this.allowSsh || this.allowS3 || this.allowBasic || this.allowRke || this.fixedImagePullSecret) {
|
|
329
379
|
out.unshift({
|
|
330
380
|
label: 'divider',
|
|
331
381
|
disabled: true,
|
|
@@ -366,6 +416,18 @@ export default {
|
|
|
366
416
|
});
|
|
367
417
|
}
|
|
368
418
|
|
|
419
|
+
if ( this.fixedImagePullSecret ) {
|
|
420
|
+
out.unshift({
|
|
421
|
+
label: this.t('selectOrCreateAuthSecret.createImagePullSecret'),
|
|
422
|
+
value: AUTH_TYPE._IMAGE_PULL_SECRET,
|
|
423
|
+
kind: 'highlighted'
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (this.fixedHttpBasicAuth) {
|
|
428
|
+
out = out.filter((o) => o.label.search(this.filterBasicAuth) === 0 || ['title', 'divider'].includes(o.kind) || o.value === AUTH_TYPE._BASIC);
|
|
429
|
+
}
|
|
430
|
+
|
|
369
431
|
return out;
|
|
370
432
|
},
|
|
371
433
|
|
|
@@ -374,7 +436,7 @@ export default {
|
|
|
374
436
|
return '';
|
|
375
437
|
}
|
|
376
438
|
|
|
377
|
-
if ( this.selected === AUTH_TYPE._SSH || this.selected === AUTH_TYPE._BASIC || this.selected === AUTH_TYPE._RKE || this.selected === AUTH_TYPE._S3 ) {
|
|
439
|
+
if ( this.selected === AUTH_TYPE._SSH || this.selected === AUTH_TYPE._BASIC || this.selected === AUTH_TYPE._RKE || this.selected === AUTH_TYPE._S3 || this.selected === AUTH_TYPE._IMAGE_PULL_SECRET ) {
|
|
378
440
|
return 'col span-4';
|
|
379
441
|
}
|
|
380
442
|
|
|
@@ -395,6 +457,7 @@ export default {
|
|
|
395
457
|
publicKey: 'updateKeyVal',
|
|
396
458
|
privateKey: 'updateKeyVal',
|
|
397
459
|
sshKnownHosts: 'updateKeyVal',
|
|
460
|
+
preSelect: 'updateSelectedFromValue',
|
|
398
461
|
value: 'updateSelectedFromValue',
|
|
399
462
|
|
|
400
463
|
async namespace(ns) {
|
|
@@ -478,7 +541,7 @@ export default {
|
|
|
478
541
|
},
|
|
479
542
|
|
|
480
543
|
updateKeyVal() {
|
|
481
|
-
if ( ![AUTH_TYPE._SSH, AUTH_TYPE._BASIC, AUTH_TYPE._S3, AUTH_TYPE._RKE].includes(this.selected) ) {
|
|
544
|
+
if ( ![AUTH_TYPE._SSH, AUTH_TYPE._BASIC, AUTH_TYPE._S3, AUTH_TYPE._RKE, AUTH_TYPE._IMAGE_PULL_SECRET].includes(this.selected) ) {
|
|
482
545
|
this.privateKey = '';
|
|
483
546
|
this.publicKey = '';
|
|
484
547
|
this.sshKnownHosts = '';
|
|
@@ -498,9 +561,9 @@ export default {
|
|
|
498
561
|
},
|
|
499
562
|
|
|
500
563
|
update() {
|
|
501
|
-
if ( (!this.selected || [AUTH_TYPE._SSH, AUTH_TYPE._BASIC, AUTH_TYPE._S3, AUTH_TYPE._RKE, AUTH_TYPE._NONE].includes(this.selected))) {
|
|
564
|
+
if ( (!this.selected || [AUTH_TYPE._SSH, AUTH_TYPE._BASIC, AUTH_TYPE._S3, AUTH_TYPE._RKE, AUTH_TYPE._NONE, AUTH_TYPE._IMAGE_PULL_SECRET].includes(this.selected))) {
|
|
502
565
|
this.$emit('update:value', null);
|
|
503
|
-
} else if ( this.selected.includes(':')
|
|
566
|
+
} else if ( this.selected.includes(':')) {
|
|
504
567
|
// Cloud creds
|
|
505
568
|
this.$emit('update:value', this.selected);
|
|
506
569
|
} else {
|
|
@@ -522,7 +585,7 @@ export default {
|
|
|
522
585
|
},
|
|
523
586
|
|
|
524
587
|
async doCreate() {
|
|
525
|
-
if ( ![AUTH_TYPE._SSH, AUTH_TYPE._BASIC, AUTH_TYPE._S3, AUTH_TYPE._RKE].includes(this.selected) || this.delegateCreateToParent ) {
|
|
588
|
+
if ( ![AUTH_TYPE._SSH, AUTH_TYPE._BASIC, AUTH_TYPE._S3, AUTH_TYPE._RKE, AUTH_TYPE._IMAGE_PULL_SECRET].includes(this.selected) || this.delegateCreateToParent ) {
|
|
526
589
|
return;
|
|
527
590
|
}
|
|
528
591
|
|
|
@@ -537,12 +600,17 @@ export default {
|
|
|
537
600
|
},
|
|
538
601
|
});
|
|
539
602
|
} else {
|
|
603
|
+
const metadata = { namespace: this.namespace };
|
|
604
|
+
|
|
605
|
+
if (this.clientGeneratedName) {
|
|
606
|
+
metadata.name = this.clientGeneratedName;
|
|
607
|
+
} else {
|
|
608
|
+
metadata.generateName = this.generateName;
|
|
609
|
+
}
|
|
610
|
+
|
|
540
611
|
secret = await this.$store.dispatch(`${ this.inStore }/create`, {
|
|
541
|
-
type:
|
|
542
|
-
metadata
|
|
543
|
-
namespace: this.namespace,
|
|
544
|
-
generateName: this.generateName
|
|
545
|
-
},
|
|
612
|
+
type: SECRET,
|
|
613
|
+
metadata,
|
|
546
614
|
});
|
|
547
615
|
|
|
548
616
|
let type, publicField, privateField;
|
|
@@ -558,6 +626,11 @@ export default {
|
|
|
558
626
|
publicField = 'username';
|
|
559
627
|
privateField = 'password';
|
|
560
628
|
break;
|
|
629
|
+
case AUTH_TYPE._IMAGE_PULL_SECRET:
|
|
630
|
+
type = SECRET_TYPES.DOCKER_JSON;
|
|
631
|
+
publicField = 'username';
|
|
632
|
+
privateField = 'password';
|
|
633
|
+
break;
|
|
561
634
|
case AUTH_TYPE._RKE:
|
|
562
635
|
type = SECRET_TYPES.RKE_AUTH_CONFIG;
|
|
563
636
|
// Set the 'auth' key to be the base64 of the username and password concatenated with a ':' character
|
|
@@ -581,6 +654,22 @@ export default {
|
|
|
581
654
|
if ((this.selected === AUTH_TYPE._SSH) && this.showSshKnownHosts) {
|
|
582
655
|
secret.data.known_hosts = base64Encode(this.sshKnownHosts || '');
|
|
583
656
|
}
|
|
657
|
+
|
|
658
|
+
if (this.selected === AUTH_TYPE._IMAGE_PULL_SECRET && this.imagePullSecretDockerJsonUrlConfig) {
|
|
659
|
+
const registryHost = this.imagePullSecretDockerJsonUrlConfig ? new URL(this.imagePullSecretDockerJsonUrlConfig).host : '';
|
|
660
|
+
|
|
661
|
+
const config = {
|
|
662
|
+
auths: {
|
|
663
|
+
[registryHost]: {
|
|
664
|
+
[publicField]: this.publicKey,
|
|
665
|
+
[privateField]: this.privateKey,
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
};
|
|
669
|
+
const json = JSON.stringify(config);
|
|
670
|
+
|
|
671
|
+
secret.setData('.dockerconfigjson', json);
|
|
672
|
+
}
|
|
584
673
|
}
|
|
585
674
|
}
|
|
586
675
|
|
|
@@ -609,7 +698,7 @@ export default {
|
|
|
609
698
|
v-model:value="selected"
|
|
610
699
|
data-testid="auth-secret-select"
|
|
611
700
|
:mode="mode"
|
|
612
|
-
:label-key="labelKey"
|
|
701
|
+
:label-key="fixedImagePullSecret ? 'selectOrCreateAuthSecret.imagePullSecret' : labelKey"
|
|
613
702
|
:loading="$fetchState.pending"
|
|
614
703
|
:options="options"
|
|
615
704
|
:selectable="option => !option.disabled"
|
|
@@ -645,7 +734,7 @@ export default {
|
|
|
645
734
|
/>
|
|
646
735
|
</div>
|
|
647
736
|
</template>
|
|
648
|
-
<template v-else-if="selected === BASIC || selected === RKE">
|
|
737
|
+
<template v-else-if="selected === BASIC || selected === RKE || selected === IMAGE_PULL_SECRET">
|
|
649
738
|
<Banner
|
|
650
739
|
v-if="selected === RKE"
|
|
651
740
|
color="info"
|
|
@@ -6,12 +6,17 @@ const requiredSetup = () => {
|
|
|
6
6
|
return {
|
|
7
7
|
global: {
|
|
8
8
|
mocks: {
|
|
9
|
-
$
|
|
9
|
+
$fetchState: { pending: false },
|
|
10
|
+
$store: {
|
|
10
11
|
getters: {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
t:
|
|
14
|
-
|
|
12
|
+
currentStore: () => 'cluster',
|
|
13
|
+
currentProduct: { inStore: 'cluster' },
|
|
14
|
+
'i18n/t': (text: string) => text,
|
|
15
|
+
t: (text: string) => text,
|
|
16
|
+
'cluster/paginationEnabled': () => false,
|
|
17
|
+
'cluster/all': () => ['node-0', 'node-1'],
|
|
18
|
+
},
|
|
19
|
+
dispatch: jest.fn(),
|
|
15
20
|
}
|
|
16
21
|
},
|
|
17
22
|
}
|
|
@@ -21,8 +26,6 @@ const requiredSetup = () => {
|
|
|
21
26
|
describe('component: NodeScheduling', () => {
|
|
22
27
|
const value = { nodeName: 'node-1' };
|
|
23
28
|
|
|
24
|
-
const nodes = ['node-0', 'node-1'];
|
|
25
|
-
|
|
26
29
|
it.each([
|
|
27
30
|
_VIEW,
|
|
28
31
|
_CREATE,
|
|
@@ -32,13 +35,13 @@ describe('component: NodeScheduling', () => {
|
|
|
32
35
|
NodeScheduling,
|
|
33
36
|
{
|
|
34
37
|
props: {
|
|
35
|
-
mode, loading: false, value
|
|
38
|
+
mode, loading: false, value
|
|
36
39
|
},
|
|
37
40
|
...requiredSetup(),
|
|
38
41
|
}
|
|
39
42
|
);
|
|
40
43
|
|
|
41
44
|
expect(wrapper.find('[data-testid="node-scheduling-selectNode"]').exists()).toBeTruthy();
|
|
42
|
-
expect(wrapper.find('[data-testid="node-scheduling-nodeSelector"]').
|
|
45
|
+
expect(wrapper.find('[data-testid="node-scheduling-nodeSelector"] .vs__selected').text()).toBe(value.nodeName);
|
|
43
46
|
});
|
|
44
47
|
});
|
|
@@ -3,6 +3,23 @@ import { mount } from '@vue/test-utils';
|
|
|
3
3
|
import PodAffinity from '@shell/components/form/PodAffinity.vue';
|
|
4
4
|
import { _CREATE } from '@shell/config/query-params';
|
|
5
5
|
|
|
6
|
+
const requiredSetup = () => {
|
|
7
|
+
return {
|
|
8
|
+
global: {
|
|
9
|
+
mocks: {
|
|
10
|
+
$store: {
|
|
11
|
+
getters: {
|
|
12
|
+
currentStore: () => 'cluster',
|
|
13
|
+
'i18n/t': (text: string) => text,
|
|
14
|
+
'cluster/schemaFor': jest.fn(),
|
|
15
|
+
'cluster/canList': jest.fn(),
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
|
|
6
23
|
describe('component: PodAffinity', () => {
|
|
7
24
|
it('should display the weight input when the priority is preferred', () => {
|
|
8
25
|
const podAffinity = {
|
|
@@ -15,7 +32,8 @@ describe('component: PodAffinity', () => {
|
|
|
15
32
|
const wrapper = mount(PodAffinity, {
|
|
16
33
|
props: {
|
|
17
34
|
mode: _CREATE, field: 'overrideAffinity', value: { overrideAffinity: { podAffinity } }
|
|
18
|
-
}
|
|
35
|
+
},
|
|
36
|
+
...requiredSetup()
|
|
19
37
|
});
|
|
20
38
|
|
|
21
39
|
expect(wrapper.find('[data-testid="pod-affinity-weight-index0"]').exists()).toBeTruthy();
|
|
@@ -33,7 +51,8 @@ describe('component: PodAffinity', () => {
|
|
|
33
51
|
const wrapper = mount(PodAffinity, {
|
|
34
52
|
props: {
|
|
35
53
|
mode: _CREATE, field: 'overrideAffinity', value: { overrideAffinity: { podAffinity } }
|
|
36
|
-
}
|
|
54
|
+
},
|
|
55
|
+
...requiredSetup()
|
|
37
56
|
});
|
|
38
57
|
|
|
39
58
|
const weightInput = wrapper.find('[data-testid="pod-affinity-weight-index0"]');
|