@rancher/shell 3.0.9-rc.5 → 3.0.9
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/IconOrSvg.vue +61 -42
- 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/SortableTable/index.vue +2 -2
- 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/BannerSettings.vue +2 -2
- package/components/form/NodeScheduling.vue +81 -7
- package/components/form/NotificationSettings.vue +2 -2
- 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/product/manager.js +0 -1
- 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/fleet.cattle.io.cluster.vue +1 -1
- package/detail/workload/index.vue +11 -16
- package/dialog/DeactivateDriverDialog.vue +1 -1
- package/dialog/FeatureFlagListDialog.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/monitoring.coreos.com.alertmanagerconfig/__tests__/auth.spec.ts +145 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/__tests__/index.test.ts +202 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/__tests__/tls.spec.ts +226 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/auth.vue +24 -21
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/__tests__/opsgenie.spec.ts +157 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/__tests__/pagerduty.spec.ts +132 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/__tests__/slack.spec.ts +108 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/pagerduty.vue +2 -1
- package/edit/monitoring.coreos.com.receiver/__tests__/auth.spec.ts +165 -0
- package/edit/monitoring.coreos.com.receiver/__tests__/index.test.ts +153 -0
- package/edit/monitoring.coreos.com.receiver/__tests__/tls.spec.ts +115 -0
- package/edit/monitoring.coreos.com.receiver/types/__tests__/email.spec.ts +86 -0
- package/edit/monitoring.coreos.com.receiver/types/__tests__/opsgenie.spec.ts +209 -0
- package/edit/monitoring.coreos.com.receiver/types/__tests__/pagerduty.spec.ts +105 -0
- package/edit/monitoring.coreos.com.receiver/types/__tests__/slack.spec.ts +92 -0
- package/edit/monitoring.coreos.com.receiver/types/__tests__/webhook.spec.ts +131 -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 +114 -0
- package/edit/provisioning.cattle.io.cluster/ingress/IngressConfiguration.vue +158 -0
- package/edit/provisioning.cattle.io.cluster/rke2.vue +167 -69
- 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 +70 -7
- package/edit/provisioning.cattle.io.cluster/tabs/Ingress.vue +343 -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__/chart.test.ts +2 -2
- 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/chart.js +3 -3
- 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/AppChartCardFooter.vue +45 -18
- package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +4 -1
- package/pages/c/_cluster/apps/charts/index.vue +82 -3
- package/pages/c/_cluster/apps/charts/install.vue +317 -42
- package/pages/c/_cluster/explorer/tools/index.vue +1 -1
- package/pages/c/_cluster/manager/cloudCredential/index.vue +1 -1
- package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +5 -4
- package/pages/c/_cluster/settings/index.vue +3 -1
- package/pages/c/_cluster/uiplugins/index.vue +1 -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 +72 -20
- 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 +537 -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/utils/svg-filter.js +4 -3
- package/components/__tests__/ProjectRow.test.ts +0 -206
- package/components/form/ResourceQuota/ProjectRow.vue +0 -277
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { shallowMount } from '@vue/test-utils';
|
|
2
|
+
import { nextTick } from 'vue';
|
|
3
|
+
import RKE2 from '@shell/edit/provisioning.cattle.io.cluster/rke2.vue';
|
|
4
|
+
import { AGENT_CONFIGURATION_TYPES } from '@shell/config/settings';
|
|
5
|
+
|
|
6
|
+
jest.mock('@shell/edit/provisioning.cattle.io.cluster/shared', () => ({
|
|
7
|
+
RETENTION_DEFAULT: 5,
|
|
8
|
+
RKE2_INGRESS_NGINX: 'rke2-ingress-nginx',
|
|
9
|
+
RKE2_TRAEFIK: 'rke2-traefik',
|
|
10
|
+
INGRESS_NGINX: 'ingress-nginx',
|
|
11
|
+
INGRESS_CONTROLLER: 'ingress-controller',
|
|
12
|
+
TRAEFIK: 'traefik',
|
|
13
|
+
HARVESTER: 'harvester',
|
|
14
|
+
INGRESS_DUAL: 'dual',
|
|
15
|
+
INGRESS_NONE: 'none',
|
|
16
|
+
INGRESS_OPTIONS: [],
|
|
17
|
+
INGRESS_MIGRATION_KB_LINK: 'mock-link'
|
|
18
|
+
}));
|
|
19
|
+
const mockStore = {
|
|
20
|
+
getters: {
|
|
21
|
+
'management/schemaFor': jest.fn().mockReturnValue(null),
|
|
22
|
+
'management/byId': jest.fn().mockReturnValue({}),
|
|
23
|
+
'management/canList': jest.fn().mockReturnValue(true),
|
|
24
|
+
'management/all': jest.fn().mockReturnValue([]),
|
|
25
|
+
'rancher/all': jest.fn().mockReturnValue([]),
|
|
26
|
+
'rancher/byId': jest.fn().mockReturnValue({}),
|
|
27
|
+
'i18n/t': jest.fn().mockImplementation((key) => key),
|
|
28
|
+
'i18n/withFallback': jest.fn().mockImplementation((key) => key),
|
|
29
|
+
'features/get': jest.fn().mockReturnValue(() => true),
|
|
30
|
+
'plugins/cloudProviderForDriver': jest.fn().mockReturnValue(undefined),
|
|
31
|
+
currentCluster: {},
|
|
32
|
+
'customisation/getPreviewCluster': {
|
|
33
|
+
badge: {
|
|
34
|
+
iconText: '', color: '', text: ''
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
productId: 'rancher',
|
|
38
|
+
currentStore: jest.fn().mockReturnValue('management')
|
|
39
|
+
},
|
|
40
|
+
dispatch: jest.fn().mockResolvedValue({ data: [] })
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const mockRoute = {
|
|
44
|
+
query: {},
|
|
45
|
+
name: 'test'
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const mockValue = {
|
|
49
|
+
metadata: {
|
|
50
|
+
name: 'test-cluster',
|
|
51
|
+
annotations: {}
|
|
52
|
+
},
|
|
53
|
+
spec: {
|
|
54
|
+
kubernetesVersion: 'v1.25.0+rke2r1',
|
|
55
|
+
rkeConfig: {
|
|
56
|
+
machineGlobalConfig: {},
|
|
57
|
+
networking: { stackPreference: 'ipv4' },
|
|
58
|
+
machineSelectorConfig: [{ config: {} }],
|
|
59
|
+
dataDirectories: {}
|
|
60
|
+
},
|
|
61
|
+
clusterAgentDeploymentCustomization: {},
|
|
62
|
+
fleetAgentDeploymentCustomization: {}
|
|
63
|
+
},
|
|
64
|
+
agentConfig: {}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const createWrapper = (propsData: any = {}) => {
|
|
68
|
+
return shallowMount(RKE2, {
|
|
69
|
+
propsData: {
|
|
70
|
+
mode: 'create',
|
|
71
|
+
value: { ...mockValue, ...propsData.value },
|
|
72
|
+
provider: 'custom',
|
|
73
|
+
...propsData
|
|
74
|
+
},
|
|
75
|
+
global: {
|
|
76
|
+
mocks: {
|
|
77
|
+
$store: mockStore,
|
|
78
|
+
$route: mockRoute,
|
|
79
|
+
$router: { replace: jest.fn() },
|
|
80
|
+
t: jest.fn().mockImplementation((key) => key),
|
|
81
|
+
$extension: { getDynamic: jest.fn().mockReturnValue(undefined) },
|
|
82
|
+
$fetchState: { pending: false, error: null }
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
data() {
|
|
86
|
+
return {
|
|
87
|
+
loadedOnce: true,
|
|
88
|
+
rke2Versions: null,
|
|
89
|
+
k3sVersions: null,
|
|
90
|
+
defaultRke2: 'v1.25.0+rke2r1',
|
|
91
|
+
defaultK3s: 'v1.25.0+k3s1'
|
|
92
|
+
} as any;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
describe('component: RKE2 - Fleet Agent Configuration', () => {
|
|
98
|
+
let wrapper: any;
|
|
99
|
+
|
|
100
|
+
beforeEach(() => {
|
|
101
|
+
jest.clearAllMocks();
|
|
102
|
+
wrapper = createWrapper();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
afterEach(() => {
|
|
106
|
+
if (wrapper) {
|
|
107
|
+
wrapper.unmount();
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe('fleet Agent Scheduling Customization', () => {
|
|
112
|
+
beforeEach(async() => {
|
|
113
|
+
// Initialize the component with fleet agent defaults
|
|
114
|
+
wrapper.vm.fleetAgentDefaultPC = { value: 100, preemptionPolicy: 'PreemptLowerPriority' };
|
|
115
|
+
wrapper.vm.fleetAgentDefaultPDB = { maxUnavailable: 1 };
|
|
116
|
+
wrapper.vm.schedulingCustomizationFeatureEnabled = true;
|
|
117
|
+
await nextTick();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should enable Fleet Agent scheduling customization when event is true', async() => {
|
|
121
|
+
const event = { event: true, agentType: AGENT_CONFIGURATION_TYPES.FLEET };
|
|
122
|
+
|
|
123
|
+
wrapper.vm.setSchedulingCustomization(event);
|
|
124
|
+
|
|
125
|
+
expect(wrapper.vm.value.spec.fleetAgentDeploymentCustomization.schedulingCustomization).toStrictEqual({
|
|
126
|
+
priorityClass: wrapper.vm.fleetAgentDefaultPC,
|
|
127
|
+
podDisruptionBudget: wrapper.vm.fleetAgentDefaultPDB
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should disable Fleet Agent scheduling customization when event is false', async() => {
|
|
132
|
+
// First enable it
|
|
133
|
+
const enableEvent = { event: true, agentType: AGENT_CONFIGURATION_TYPES.FLEET };
|
|
134
|
+
|
|
135
|
+
wrapper.vm.setSchedulingCustomization(enableEvent);
|
|
136
|
+
|
|
137
|
+
// Then disable it
|
|
138
|
+
const disableEvent = { event: false, agentType: AGENT_CONFIGURATION_TYPES.FLEET };
|
|
139
|
+
|
|
140
|
+
wrapper.vm.setSchedulingCustomization(disableEvent);
|
|
141
|
+
|
|
142
|
+
expect(wrapper.vm.value.spec.fleetAgentDeploymentCustomization.schedulingCustomization).toBeUndefined();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should enable Cluster Agent scheduling customization when event is true', async() => {
|
|
146
|
+
// Initialize cluster agent defaults
|
|
147
|
+
wrapper.vm.clusterAgentDefaultPC = { value: 200, preemptionPolicy: 'PreemptLowerPriority' };
|
|
148
|
+
wrapper.vm.clusterAgentDefaultPDB = { maxUnavailable: 2 };
|
|
149
|
+
|
|
150
|
+
const event = { event: true, agentType: AGENT_CONFIGURATION_TYPES.CLUSTER };
|
|
151
|
+
|
|
152
|
+
wrapper.vm.setSchedulingCustomization(event);
|
|
153
|
+
|
|
154
|
+
expect(wrapper.vm.value.spec.clusterAgentDeploymentCustomization.schedulingCustomization).toStrictEqual({
|
|
155
|
+
priorityClass: wrapper.vm.clusterAgentDefaultPC,
|
|
156
|
+
podDisruptionBudget: wrapper.vm.clusterAgentDefaultPDB
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('should disable Cluster Agent scheduling customization when event is false', async() => {
|
|
161
|
+
// Initialize cluster agent defaults
|
|
162
|
+
wrapper.vm.clusterAgentDefaultPC = { value: 200, preemptionPolicy: 'PreemptLowerPriority' };
|
|
163
|
+
wrapper.vm.clusterAgentDefaultPDB = { maxUnavailable: 2 };
|
|
164
|
+
|
|
165
|
+
// First enable it
|
|
166
|
+
const enableEvent = { event: true, agentType: AGENT_CONFIGURATION_TYPES.CLUSTER };
|
|
167
|
+
|
|
168
|
+
wrapper.vm.setSchedulingCustomization(enableEvent);
|
|
169
|
+
|
|
170
|
+
// Then disable it
|
|
171
|
+
const disableEvent = { event: false, agentType: AGENT_CONFIGURATION_TYPES.CLUSTER };
|
|
172
|
+
|
|
173
|
+
wrapper.vm.setSchedulingCustomization(disableEvent);
|
|
174
|
+
|
|
175
|
+
expect(wrapper.vm.value.spec.clusterAgentDeploymentCustomization.schedulingCustomization).toBeUndefined();
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('should handle unknown agent types gracefully', async() => {
|
|
179
|
+
const event = { event: true, agentType: 'unknown' };
|
|
180
|
+
|
|
181
|
+
// Should not throw an error
|
|
182
|
+
expect(() => wrapper.vm.setSchedulingCustomization(event)).not.toThrow();
|
|
183
|
+
|
|
184
|
+
// Should not modify any agent configuration
|
|
185
|
+
expect(wrapper.vm.value.spec.clusterAgentDeploymentCustomization.schedulingCustomization).toBeUndefined();
|
|
186
|
+
expect(wrapper.vm.value.spec.fleetAgentDeploymentCustomization.schedulingCustomization).toBeUndefined();
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('should pass the correct agent type to SchedulingCustomization components', async() => {
|
|
190
|
+
await wrapper.vm.$nextTick();
|
|
191
|
+
|
|
192
|
+
// Check if AGENT_CONFIGURATION_TYPES is available in the component data
|
|
193
|
+
expect(wrapper.vm.AGENT_CONFIGURATION_TYPES).toBeDefined();
|
|
194
|
+
expect(wrapper.vm.AGENT_CONFIGURATION_TYPES.CLUSTER).toBe('cluster');
|
|
195
|
+
expect(wrapper.vm.AGENT_CONFIGURATION_TYPES.FLEET).toBe('fleet');
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
describe('fleet Agent Configuration Data Initialization', () => {
|
|
200
|
+
it('should initialize fleet agent default configuration properties', () => {
|
|
201
|
+
expect(wrapper.vm.fleetAgentDefaultPC).toBeDefined();
|
|
202
|
+
expect(wrapper.vm.fleetAgentDefaultPDB).toBeDefined();
|
|
203
|
+
expect(wrapper.vm.AGENT_CONFIGURATION_TYPES).toBeDefined();
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('should have AGENT_CONFIGURATION_TYPES with correct values', () => {
|
|
207
|
+
expect(wrapper.vm.AGENT_CONFIGURATION_TYPES).toStrictEqual({
|
|
208
|
+
CLUSTER: 'cluster',
|
|
209
|
+
FLEET: 'fleet'
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
describe('fleet Agent Configuration Template', () => {
|
|
215
|
+
it('should render AgentConfiguration for fleet agent with correct props', async() => {
|
|
216
|
+
// Set up fleet agent configuration to ensure it renders
|
|
217
|
+
wrapper.vm.value.spec.fleetAgentDeploymentCustomization = {};
|
|
218
|
+
wrapper.vm.schedulingCustomizationFeatureEnabled = true;
|
|
219
|
+
wrapper.vm.fleetAgentDefaultPC = { value: 100 };
|
|
220
|
+
wrapper.vm.fleetAgentDefaultPDB = { maxUnavailable: 1 };
|
|
221
|
+
await nextTick();
|
|
222
|
+
|
|
223
|
+
// Force re-render
|
|
224
|
+
await wrapper.vm.$forceUpdate();
|
|
225
|
+
await nextTick();
|
|
226
|
+
|
|
227
|
+
// The template should contain fleet agent configuration
|
|
228
|
+
// This tests the template structure even if the component isn't fully mounted
|
|
229
|
+
expect(wrapper.vm.value.spec.fleetAgentDeploymentCustomization).toBeDefined();
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
describe('flannel Masquerade Configuration', () => {
|
|
234
|
+
let k3sWrapper: any;
|
|
235
|
+
|
|
236
|
+
beforeEach(() => {
|
|
237
|
+
const k3sValue = {
|
|
238
|
+
...mockValue,
|
|
239
|
+
spec: {
|
|
240
|
+
...mockValue.spec,
|
|
241
|
+
rkeConfig: {
|
|
242
|
+
...mockValue.spec.rkeConfig,
|
|
243
|
+
machineGlobalConfig: { 'flannel-backend': 'vxlan' } // flannel enabled
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
k3sWrapper = createWrapper({ value: k3sValue });
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
afterEach(() => {
|
|
252
|
+
if (k3sWrapper) {
|
|
253
|
+
k3sWrapper.unmount();
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it('should handle flannel masquerade configuration change', async() => {
|
|
258
|
+
k3sWrapper.vm.handleFlannelMasqChanged(true);
|
|
259
|
+
|
|
260
|
+
expect(k3sWrapper.vm.serverConfig['flannel-ipv6-masq']).toBe(true);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it('should remove flannel masquerade configuration when set to false', async() => {
|
|
264
|
+
// First set it to true
|
|
265
|
+
k3sWrapper.vm.handleFlannelMasqChanged(true);
|
|
266
|
+
expect(k3sWrapper.vm.serverConfig['flannel-ipv6-masq']).toBe(true);
|
|
267
|
+
|
|
268
|
+
// Then set it to false
|
|
269
|
+
k3sWrapper.vm.handleFlannelMasqChanged(false);
|
|
270
|
+
expect(k3sWrapper.vm.serverConfig['flannel-ipv6-masq']).toBe(false);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('should remove flannel masquerade configuration when set to null/undefined', async() => {
|
|
274
|
+
// First set it to true
|
|
275
|
+
k3sWrapper.vm.handleFlannelMasqChanged(true);
|
|
276
|
+
expect(k3sWrapper.vm.serverConfig['flannel-ipv6-masq']).toBe(true);
|
|
277
|
+
|
|
278
|
+
// Then set it to null
|
|
279
|
+
k3sWrapper.vm.handleFlannelMasqChanged(null);
|
|
280
|
+
expect(k3sWrapper.vm.serverConfig['flannel-ipv6-masq']).toBeUndefined();
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
});
|
|
@@ -1,10 +1,26 @@
|
|
|
1
1
|
import { mount, shallowMount } from '@vue/test-utils';
|
|
2
2
|
import { SECRET } from '@shell/config/types';
|
|
3
|
-
import { _CREATE } from '@shell/config/query-params';
|
|
3
|
+
import { _CREATE, _EDIT } from '@shell/config/query-params';
|
|
4
4
|
import rke2 from '@shell/edit/provisioning.cattle.io.cluster/rke2.vue';
|
|
5
5
|
import { get } from '@shell/utils/object';
|
|
6
6
|
import { rke2TestTable } from './utils/rke2-test-data';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
RKE2_INGRESS_NGINX, INGRESS_CONTROLLER, INGRESS_NGINX, TRAEFIK, INGRESS_NONE, RKE2_TRAEFIK
|
|
9
|
+
} from '@shell/edit/provisioning.cattle.io.cluster/shared';
|
|
10
|
+
|
|
11
|
+
jest.mock('@shell/edit/provisioning.cattle.io.cluster/shared', () => ({
|
|
12
|
+
RETENTION_DEFAULT: 5,
|
|
13
|
+
RKE2_INGRESS_NGINX: 'rke2-ingress-nginx',
|
|
14
|
+
RKE2_TRAEFIK: 'rke2-traefik',
|
|
15
|
+
INGRESS_NGINX: 'ingress-nginx',
|
|
16
|
+
INGRESS_CONTROLLER: 'ingress-controller',
|
|
17
|
+
TRAEFIK: 'traefik',
|
|
18
|
+
HARVESTER: 'harvester',
|
|
19
|
+
INGRESS_DUAL: 'dual',
|
|
20
|
+
INGRESS_NONE: 'none',
|
|
21
|
+
INGRESS_OPTIONS: [],
|
|
22
|
+
INGRESS_MIGRATION_KB_LINK: 'mock-link'
|
|
23
|
+
}));
|
|
8
24
|
|
|
9
25
|
/**
|
|
10
26
|
* DISCLAIMER ***************************************************************************************
|
|
@@ -453,7 +469,11 @@ describe('component: rke2', () => {
|
|
|
453
469
|
rke2Versions: [{
|
|
454
470
|
id: k8s,
|
|
455
471
|
version: k8s,
|
|
456
|
-
serverArgs: true
|
|
472
|
+
serverArgs: true,
|
|
473
|
+
charts: {
|
|
474
|
+
[RKE2_INGRESS_NGINX]: {},
|
|
475
|
+
[RKE2_TRAEFIK]: {}
|
|
476
|
+
}
|
|
457
477
|
}]
|
|
458
478
|
});
|
|
459
479
|
|
|
@@ -593,6 +613,7 @@ describe('component: rke2', () => {
|
|
|
593
613
|
repo: 'rancher-rke2-charts',
|
|
594
614
|
version: '3.12.200'
|
|
595
615
|
},
|
|
616
|
+
'rke2-traefik': {}
|
|
596
617
|
}
|
|
597
618
|
}
|
|
598
619
|
]
|
|
@@ -616,10 +637,10 @@ describe('component: rke2', () => {
|
|
|
616
637
|
|
|
617
638
|
describe('should correctly update NGINX configuration', () => {
|
|
618
639
|
const k8sVersion = 'v1.25.0+rke2r1';
|
|
619
|
-
const createWrapper = () => {
|
|
640
|
+
const createWrapper = (mode = _EDIT) => {
|
|
620
641
|
return shallowMount(rke2, {
|
|
621
642
|
props: {
|
|
622
|
-
mode
|
|
643
|
+
mode,
|
|
623
644
|
value: {
|
|
624
645
|
spec: {
|
|
625
646
|
...defaultSpec,
|
|
@@ -646,33 +667,47 @@ describe('component: rke2', () => {
|
|
|
646
667
|
},
|
|
647
668
|
});
|
|
648
669
|
};
|
|
670
|
+
const mockCharts = {
|
|
671
|
+
[RKE2_INGRESS_NGINX]: {},
|
|
672
|
+
[RKE2_TRAEFIK]: {}
|
|
673
|
+
};
|
|
649
674
|
|
|
650
|
-
it('should set ingress-controller to
|
|
651
|
-
const wrapper = createWrapper();
|
|
675
|
+
it('should set ingress-controller to traefik by default for new clusters', async() => {
|
|
676
|
+
const wrapper = createWrapper(_CREATE);
|
|
652
677
|
|
|
653
678
|
await wrapper.setData({
|
|
654
679
|
rke2Versions: [{
|
|
655
680
|
id: k8sVersion,
|
|
656
681
|
version: k8sVersion,
|
|
657
|
-
serverArgs: { disable: { options: [
|
|
682
|
+
serverArgs: { disable: { options: [RKE2_INGRESS_NGINX] } },
|
|
683
|
+
charts: mockCharts
|
|
658
684
|
}]
|
|
659
685
|
});
|
|
660
686
|
|
|
661
|
-
expect(wrapper.vm.value.spec.rkeConfig.machineGlobalConfig[INGRESS_CONTROLLER]).toBe(
|
|
687
|
+
expect(wrapper.vm.value.spec.rkeConfig.machineGlobalConfig[INGRESS_CONTROLLER]).toBe(TRAEFIK);
|
|
662
688
|
});
|
|
663
689
|
|
|
664
|
-
it('should set ingress-controller to
|
|
690
|
+
it('should set ingress-controller to None on version change when nginx is not supported', async() => {
|
|
665
691
|
const wrapper = createWrapper();
|
|
692
|
+
const newVersion = 'v1.26.0+rke2r1';
|
|
666
693
|
|
|
667
694
|
await wrapper.setData({
|
|
668
695
|
rke2Versions: [{
|
|
669
696
|
id: k8sVersion,
|
|
670
697
|
version: k8sVersion,
|
|
671
|
-
serverArgs: { disable: { options: [] } }
|
|
698
|
+
serverArgs: { disable: { options: [] } },
|
|
699
|
+
charts: mockCharts
|
|
700
|
+
},
|
|
701
|
+
{
|
|
702
|
+
id: newVersion,
|
|
703
|
+
version: newVersion,
|
|
704
|
+
serverArgs: { disable: { options: [] } },
|
|
705
|
+
charts: mockCharts
|
|
672
706
|
}]
|
|
673
707
|
});
|
|
674
|
-
|
|
675
|
-
|
|
708
|
+
wrapper.vm.value.spec.kubernetesVersion = newVersion;
|
|
709
|
+
(wrapper.vm as any).handleKubernetesChange(newVersion);
|
|
710
|
+
expect(wrapper.vm.value.spec.rkeConfig.machineGlobalConfig[INGRESS_CONTROLLER]).toBe(INGRESS_NONE);
|
|
676
711
|
});
|
|
677
712
|
|
|
678
713
|
it('should set ingress-controller to ingress-nginx on change when nginx is supported and not disabled', () => {
|
|
@@ -682,7 +717,8 @@ describe('component: rke2', () => {
|
|
|
682
717
|
rke2Versions: [{
|
|
683
718
|
id: k8sVersion,
|
|
684
719
|
version: k8sVersion,
|
|
685
|
-
serverArgs: { disable: { options: [
|
|
720
|
+
serverArgs: { disable: { options: [RKE2_INGRESS_NGINX] } },
|
|
721
|
+
charts: mockCharts
|
|
686
722
|
}]
|
|
687
723
|
});
|
|
688
724
|
|
|
@@ -691,36 +727,38 @@ describe('component: rke2', () => {
|
|
|
691
727
|
expect(wrapper.vm.value.spec.rkeConfig.machineGlobalConfig[INGRESS_CONTROLLER]).toBe(INGRESS_NGINX);
|
|
692
728
|
});
|
|
693
729
|
|
|
694
|
-
it('should set ingress-controller to
|
|
730
|
+
it('should set ingress-controller to None when nginx is supported but disabled', () => {
|
|
695
731
|
const wrapper = createWrapper();
|
|
696
732
|
|
|
697
733
|
wrapper.setData({
|
|
698
734
|
rke2Versions: [{
|
|
699
735
|
id: k8sVersion,
|
|
700
736
|
version: k8sVersion,
|
|
701
|
-
serverArgs: { disable: { options: [
|
|
737
|
+
serverArgs: { disable: { options: [RKE2_INGRESS_NGINX] } },
|
|
738
|
+
charts: mockCharts
|
|
702
739
|
}]
|
|
703
740
|
});
|
|
704
741
|
|
|
705
|
-
(wrapper.vm as any).handleEnabledSystemServicesChanged([
|
|
742
|
+
(wrapper.vm as any).handleEnabledSystemServicesChanged([RKE2_INGRESS_NGINX]);
|
|
706
743
|
|
|
707
|
-
expect(wrapper.vm.value.spec.rkeConfig.machineGlobalConfig[INGRESS_CONTROLLER]).
|
|
744
|
+
expect(wrapper.vm.value.spec.rkeConfig.machineGlobalConfig[INGRESS_CONTROLLER]).toBe(INGRESS_NONE);
|
|
708
745
|
});
|
|
709
746
|
|
|
710
|
-
it('should set ingress-controller to
|
|
747
|
+
it('should set ingress-controller for existing cluster to None when nginx is not supported', () => {
|
|
711
748
|
const wrapper = createWrapper();
|
|
712
749
|
|
|
713
750
|
wrapper.setData({
|
|
714
751
|
rke2Versions: [{
|
|
715
752
|
id: k8sVersion,
|
|
716
753
|
version: k8sVersion,
|
|
717
|
-
serverArgs: { disable: { options: [] } }
|
|
754
|
+
serverArgs: { disable: { options: [] } },
|
|
755
|
+
charts: mockCharts
|
|
718
756
|
}]
|
|
719
757
|
});
|
|
720
758
|
|
|
721
759
|
(wrapper.vm as any).handleEnabledSystemServicesChanged([]);
|
|
722
760
|
|
|
723
|
-
expect(wrapper.vm.value.spec.rkeConfig.machineGlobalConfig[INGRESS_CONTROLLER]).
|
|
761
|
+
expect(wrapper.vm.value.spec.rkeConfig.machineGlobalConfig[INGRESS_CONTROLLER]).toBe(INGRESS_NONE);
|
|
724
762
|
});
|
|
725
763
|
|
|
726
764
|
it('should correctly update disable list in serverConfig', () => {
|
|
@@ -730,7 +768,8 @@ describe('component: rke2', () => {
|
|
|
730
768
|
rke2Versions: [{
|
|
731
769
|
id: k8sVersion,
|
|
732
770
|
version: k8sVersion,
|
|
733
|
-
serverArgs: { disable: { options: [
|
|
771
|
+
serverArgs: { disable: { options: [RKE2_INGRESS_NGINX] } },
|
|
772
|
+
charts: mockCharts
|
|
734
773
|
}]
|
|
735
774
|
});
|
|
736
775
|
const disabledServices = ['other-service'];
|
|
@@ -749,12 +788,14 @@ describe('component: rke2', () => {
|
|
|
749
788
|
{
|
|
750
789
|
id: k8sVersion,
|
|
751
790
|
version: k8sVersion,
|
|
752
|
-
serverArgs: { disable: { options: [
|
|
791
|
+
serverArgs: { disable: { options: [RKE2_INGRESS_NGINX] } },
|
|
792
|
+
charts: mockCharts
|
|
753
793
|
},
|
|
754
794
|
{
|
|
755
795
|
id: newVersion,
|
|
756
796
|
version: newVersion,
|
|
757
|
-
serverArgs: { disable: { options: [
|
|
797
|
+
serverArgs: { disable: { options: [RKE2_INGRESS_NGINX] } },
|
|
798
|
+
charts: mockCharts
|
|
758
799
|
}
|
|
759
800
|
]
|
|
760
801
|
});
|
|
@@ -764,30 +805,5 @@ describe('component: rke2', () => {
|
|
|
764
805
|
|
|
765
806
|
expect(wrapper.vm.value.spec.rkeConfig.machineGlobalConfig[INGRESS_CONTROLLER]).toBe(INGRESS_NGINX);
|
|
766
807
|
});
|
|
767
|
-
|
|
768
|
-
it('should not set ingress-controller to ingress-nginx on version change when nginx is not supported', async() => {
|
|
769
|
-
const wrapper = createWrapper();
|
|
770
|
-
const newVersion = 'v1.26.0+rke2r1';
|
|
771
|
-
|
|
772
|
-
await wrapper.setData({
|
|
773
|
-
k3sVersions: [
|
|
774
|
-
{
|
|
775
|
-
id: k8sVersion,
|
|
776
|
-
version: k8sVersion,
|
|
777
|
-
serverArgs: { disable: { options: [] } }
|
|
778
|
-
},
|
|
779
|
-
{
|
|
780
|
-
id: newVersion,
|
|
781
|
-
version: newVersion,
|
|
782
|
-
serverArgs: { disable: { options: [] } }
|
|
783
|
-
}
|
|
784
|
-
]
|
|
785
|
-
});
|
|
786
|
-
|
|
787
|
-
wrapper.vm.value.spec.kubernetesVersion = newVersion;
|
|
788
|
-
(wrapper.vm as any).handleKubernetesChange(newVersion);
|
|
789
|
-
|
|
790
|
-
expect(wrapper.vm.value.spec.rkeConfig.machineGlobalConfig[INGRESS_CONTROLLER]).toBeUndefined();
|
|
791
|
-
});
|
|
792
808
|
});
|
|
793
809
|
});
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { _CREATE, _VIEW } from '@shell/config/query-params';
|
|
3
|
+
import { PropType } from 'vue';
|
|
4
|
+
import { useStore } from 'vuex';
|
|
5
|
+
import { useI18n } from '@shell/composables/useI18n';
|
|
6
|
+
import { RcItemCard, RcItemCardAction } from '@components/RcItemCard';
|
|
7
|
+
|
|
8
|
+
interface IngressCard {
|
|
9
|
+
id: string;
|
|
10
|
+
image?: any;
|
|
11
|
+
header: { title: { key: string } };
|
|
12
|
+
subHeader: { label: { key: string } };
|
|
13
|
+
content: { key: string };
|
|
14
|
+
doc?: {url: string};
|
|
15
|
+
selected?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
defineProps({
|
|
19
|
+
options: {
|
|
20
|
+
type: Array as PropType<IngressCard[]>,
|
|
21
|
+
required: true
|
|
22
|
+
},
|
|
23
|
+
mode: { type: String, default: _CREATE },
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const emit = defineEmits(['select']);
|
|
27
|
+
|
|
28
|
+
const store = useStore();
|
|
29
|
+
const { t } = useI18n(store);
|
|
30
|
+
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<template>
|
|
34
|
+
<div class="ingress-cards">
|
|
35
|
+
<rc-item-card
|
|
36
|
+
v-for="card in options"
|
|
37
|
+
:id="card.id"
|
|
38
|
+
:key="card.id"
|
|
39
|
+
:header="card.header"
|
|
40
|
+
:image="card.image"
|
|
41
|
+
:content="card.content"
|
|
42
|
+
:selected="card.selected"
|
|
43
|
+
variant="small"
|
|
44
|
+
role="link"
|
|
45
|
+
:disabled="mode === _VIEW"
|
|
46
|
+
:class="{ 'single-card': options.length === 1 }"
|
|
47
|
+
:clickable="mode !== _VIEW"
|
|
48
|
+
@card-click="emit('select', card.id)"
|
|
49
|
+
>
|
|
50
|
+
<template
|
|
51
|
+
v-once
|
|
52
|
+
#item-card-sub-header
|
|
53
|
+
>
|
|
54
|
+
<p class="ingress-card-sub-header">
|
|
55
|
+
{{ t(card.subHeader.label.key) }}
|
|
56
|
+
</p>
|
|
57
|
+
</template>
|
|
58
|
+
<template
|
|
59
|
+
v-if="!!card.doc"
|
|
60
|
+
v-once
|
|
61
|
+
#item-card-footer
|
|
62
|
+
>
|
|
63
|
+
<div class="mmt-2">
|
|
64
|
+
<rc-item-card-action>
|
|
65
|
+
<a
|
|
66
|
+
:href="card.doc.url"
|
|
67
|
+
rel="nofollow noopener noreferrer"
|
|
68
|
+
target="_blank"
|
|
69
|
+
class="ingress-card-footer-button secondary-text-link"
|
|
70
|
+
>
|
|
71
|
+
{{ t('cluster.ingress.learnMore.label') }}
|
|
72
|
+
<i class="icon icon-external-link" />
|
|
73
|
+
<span class="sr-only">{{ t('generic.opensInNewTab') }}</span>
|
|
74
|
+
</a>
|
|
75
|
+
</rc-item-card-action>
|
|
76
|
+
</div>
|
|
77
|
+
</template>
|
|
78
|
+
</rc-item-card>
|
|
79
|
+
</div>
|
|
80
|
+
</template>
|
|
81
|
+
|
|
82
|
+
<style scoped lang="scss">
|
|
83
|
+
.ingress-cards{
|
|
84
|
+
display: grid;
|
|
85
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
86
|
+
grid-gap: var(--gap-md);
|
|
87
|
+
width: 100%;
|
|
88
|
+
height: max-content;
|
|
89
|
+
overflow: hidden;
|
|
90
|
+
|
|
91
|
+
.single-card {
|
|
92
|
+
max-width: 500px;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
.ingress-card-sub-header {
|
|
96
|
+
display: flex;
|
|
97
|
+
flex-wrap: wrap;
|
|
98
|
+
gap: var(--gap) var(--gap-md);
|
|
99
|
+
color: var(--link-text-secondary);
|
|
100
|
+
margin-bottom: 8px;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
button.variant-ghost.ingress-card-footer-button {
|
|
104
|
+
padding: 0;
|
|
105
|
+
gap: 0;
|
|
106
|
+
min-height: 20px;
|
|
107
|
+
|
|
108
|
+
&:focus-visible {
|
|
109
|
+
border-color: var(--primary);
|
|
110
|
+
@include focus-outline;
|
|
111
|
+
outline-offset: -2px;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
</style>
|