@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.
Files changed (142) hide show
  1. package/assets/images/providers/oci-open-containers.svg +22 -0
  2. package/assets/images/providers/traefik.png +0 -0
  3. package/assets/styles/themes/_dark.scss +2 -0
  4. package/assets/styles/themes/_light.scss +2 -0
  5. package/assets/styles/themes/_modern.scss +6 -0
  6. package/assets/translations/en-us.yaml +129 -25
  7. package/components/CruResource.vue +3 -1
  8. package/components/ExplorerProjectsNamespaces.vue +12 -12
  9. package/components/Resource/Detail/Card/StatusCard/__tests__/StatusCard.test.ts +109 -0
  10. package/components/Resource/Detail/Card/StatusCard/index.vue +21 -4
  11. package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/identifying-fields.test.ts +19 -2
  12. package/components/Resource/Detail/Metadata/IdentifyingInformation/identifying-fields.ts +19 -11
  13. package/components/Resource/Detail/ResourcePopover/__tests__/index.test.ts +12 -0
  14. package/components/Resource/Detail/ResourcePopover/index.vue +2 -0
  15. package/components/Resource/Detail/ResourceRow.vue +2 -2
  16. package/components/ResourceList/index.vue +7 -4
  17. package/components/Window/ContainerLogs.vue +48 -37
  18. package/components/fleet/FleetClusterTargets/TargetsList.vue +2 -2
  19. package/components/fleet/FleetClusterTargets/index.vue +6 -1
  20. package/components/fleet/GitRepoAdvancedTab.vue +333 -0
  21. package/components/fleet/GitRepoMetadataTab.vue +43 -0
  22. package/components/fleet/GitRepoRepositoryTab.vue +101 -0
  23. package/components/fleet/GitRepoTargetTab.vue +77 -0
  24. package/components/fleet/HelmOpAdvancedTab.vue +247 -0
  25. package/components/fleet/HelmOpChartTab.vue +158 -0
  26. package/components/fleet/HelmOpMetadataTab.vue +46 -0
  27. package/components/fleet/HelmOpTargetTab.vue +84 -0
  28. package/components/fleet/HelmOpValuesTab.vue +147 -0
  29. package/components/fleet/__tests__/FleetClusterTargets.test.ts +119 -70
  30. package/components/form/NodeScheduling.vue +81 -7
  31. package/components/form/PodAffinity.vue +1 -36
  32. package/components/form/ResourceLabeledSelect.vue +8 -4
  33. package/components/form/ResourceQuota/Namespace.vue +30 -9
  34. package/components/form/ResourceQuota/NamespaceRow.vue +25 -7
  35. package/components/form/ResourceQuota/Project.vue +140 -82
  36. package/components/form/ResourceQuota/ResourceQuotaEntry.vue +145 -0
  37. package/components/form/ResourceQuota/__tests__/Namespace.test.ts +307 -0
  38. package/components/form/ResourceQuota/__tests__/NamespaceRow.test.ts +281 -0
  39. package/components/form/ResourceQuota/__tests__/Project.test.ts +274 -27
  40. package/components/form/ResourceQuota/__tests__/ResourceQuotaEntry.test.ts +215 -0
  41. package/components/form/SchedulingCustomization.vue +14 -6
  42. package/components/form/SelectOrCreateAuthSecret.vue +107 -18
  43. package/components/form/__tests__/NodeScheduling.test.ts +12 -9
  44. package/components/form/__tests__/PodAffinity.test.ts +21 -2
  45. package/components/form/__tests__/SchedulingCustomization.test.ts +240 -0
  46. package/components/formatter/ClusterLink.vue +8 -0
  47. package/components/formatter/SecretOrigin.vue +79 -0
  48. package/config/labels-annotations.js +7 -6
  49. package/config/pagination-table-headers.js +6 -4
  50. package/config/product/explorer.js +1 -11
  51. package/config/query-params.js +3 -0
  52. package/config/settings.ts +15 -2
  53. package/config/table-headers.js +21 -17
  54. package/config/types.js +23 -8
  55. package/detail/workload/index.vue +11 -16
  56. package/dialog/DeactivateDriverDialog.vue +1 -1
  57. package/dialog/Ipv6NetworkingDialog.vue +156 -0
  58. package/dialog/ScalePoolDownDialog.vue +2 -2
  59. package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +1 -1
  60. package/edit/__tests__/fleet.cattle.io.helmop.test.ts +1 -0
  61. package/edit/__tests__/management.cattle.io.project.test.js +56 -128
  62. package/edit/auth/oidc.vue +1 -1
  63. package/edit/catalog.cattle.io.clusterrepo.vue +155 -25
  64. package/edit/fleet.cattle.io.gitrepo.vue +153 -283
  65. package/edit/fleet.cattle.io.helmop.vue +190 -332
  66. package/edit/management.cattle.io.project.vue +5 -42
  67. package/edit/management.cattle.io.setting.vue +6 -0
  68. package/edit/provisioning.cattle.io.cluster/__tests__/Basics.test.ts +55 -24
  69. package/edit/provisioning.cattle.io.cluster/__tests__/Networking.test.ts +1 -103
  70. package/edit/provisioning.cattle.io.cluster/__tests__/index.test.ts +13 -1
  71. package/edit/provisioning.cattle.io.cluster/__tests__/rke2-fleet-cluster-agent.test.ts +283 -0
  72. package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +65 -49
  73. package/edit/provisioning.cattle.io.cluster/ingress/IngressCards.vue +112 -0
  74. package/edit/provisioning.cattle.io.cluster/ingress/IngressConfiguration.vue +158 -0
  75. package/edit/provisioning.cattle.io.cluster/rke2.vue +171 -72
  76. package/edit/provisioning.cattle.io.cluster/shared.ts +36 -1
  77. package/edit/provisioning.cattle.io.cluster/tabs/AgentConfiguration.vue +2 -1
  78. package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +55 -7
  79. package/edit/provisioning.cattle.io.cluster/tabs/Ingress.vue +319 -0
  80. package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +2 -1
  81. package/edit/provisioning.cattle.io.cluster/tabs/etcd/__tests__/S3Config.test.ts +13 -1
  82. package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +10 -44
  83. package/edit/secret/index.vue +1 -1
  84. package/edit/token.vue +68 -29
  85. package/edit/workload/__tests__/index.test.ts +2 -37
  86. package/edit/workload/index.vue +6 -2
  87. package/edit/workload/mixins/workload.js +0 -32
  88. package/list/__tests__/management.cattle.io.setting.test.ts +198 -0
  89. package/list/management.cattle.io.setting.vue +13 -0
  90. package/list/provisioning.cattle.io.cluster.vue +50 -1
  91. package/list/secret.vue +4 -9
  92. package/list/service.vue +6 -8
  93. package/machine-config/amazonec2.vue +11 -4
  94. package/machine-config/components/EC2Networking.vue +46 -30
  95. package/machine-config/components/__tests__/EC2Networking.test.ts +7 -7
  96. package/machine-config/components/__tests__/utils/vpcSubnetMockData.js +0 -9
  97. package/machine-config/digitalocean.vue +3 -3
  98. package/models/__tests__/namespace.test.ts +11 -0
  99. package/models/__tests__/provisioning.cattle.io.cluster.test.ts +96 -0
  100. package/models/__tests__/workload.test.ts +42 -1
  101. package/models/catalog.cattle.io.clusterrepo.js +30 -4
  102. package/models/ext.cattle.io.token.js +48 -0
  103. package/models/kontainerdriver.js +2 -2
  104. package/models/namespace.js +7 -1
  105. package/models/nodedriver.js +2 -2
  106. package/models/provisioning.cattle.io.cluster.js +28 -7
  107. package/models/secret.js +0 -17
  108. package/models/service.js +44 -1
  109. package/models/token.js +4 -0
  110. package/models/workload.js +12 -6
  111. package/package.json +1 -1
  112. package/pages/account/index.vue +96 -67
  113. package/pages/auth/setup.vue +5 -14
  114. package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +4 -1
  115. package/pages/c/_cluster/apps/charts/index.vue +93 -4
  116. package/pages/c/_cluster/apps/charts/install.vue +317 -42
  117. package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +5 -4
  118. package/pages/c/_cluster/settings/index.vue +3 -1
  119. package/plugins/dashboard-store/__tests__/getters.test.ts +108 -0
  120. package/plugins/dashboard-store/__tests__/resource-class.test.ts +27 -0
  121. package/plugins/dashboard-store/actions.js +3 -8
  122. package/plugins/dashboard-store/getters.js +7 -5
  123. package/plugins/dashboard-store/mutations.js +4 -1
  124. package/plugins/dashboard-store/resource-class.js +3 -3
  125. package/plugins/steve/__tests__/steve-class.test.ts +102 -141
  126. package/plugins/steve/steve-class.js +12 -3
  127. package/plugins/steve/steve-pagination-utils.ts +6 -2
  128. package/rancher-components/RcIcon/types.ts +2 -0
  129. package/rancher-components/RcItemCard/RcItemCard.vue +64 -19
  130. package/store/prefs.js +3 -0
  131. package/types/aws-sdk.d.ts +121 -0
  132. package/types/resources/node.ts +15 -0
  133. package/types/shell/index.d.ts +536 -506
  134. package/types/store/pagination.types.ts +5 -5
  135. package/utils/__tests__/array.test.ts +1 -29
  136. package/utils/__tests__/cluster-agent-configuration.test.ts +203 -0
  137. package/utils/array.ts +0 -11
  138. package/utils/aws.ts +21 -0
  139. package/utils/cluster.js +22 -2
  140. package/utils/selector-typed.ts +1 -1
  141. package/components/__tests__/ProjectRow.test.ts +0 -206
  142. package/components/form/ResourceQuota/ProjectRow.vue +0 -277
@@ -162,6 +162,12 @@ export default {
162
162
  class="edit-help"
163
163
  />
164
164
 
165
+ <Banner
166
+ v-if="setting.agent"
167
+ color="info"
168
+ :label="t('advancedSettings.edit.agentConfigBanner.text', { agent: t('advancedSettings.edit.agentConfigBanner.' + setting.agent) })"
169
+ data-testid="setting-agent-config-banner"
170
+ />
165
171
  <div class="edit-change mt-20">
166
172
  <h5 v-t="'advancedSettings.edit.changeSetting'" />
167
173
  <button
@@ -2,17 +2,20 @@ import { nextTick } from 'vue';
2
2
  import { mount } from '@vue/test-utils';
3
3
  import Basics from '@shell/edit/provisioning.cattle.io.cluster/tabs/Basics.vue';
4
4
  // import Checkbox from '@components/Form/Checkbox/Checkbox.vue';
5
+ import { RKE2_INGRESS_NGINX, RKE2_TRAEFIK } from '@shell/edit/provisioning.cattle.io.cluster/shared';
5
6
 
6
7
  const defaultStubs = {
7
- Banner: true,
8
- LabeledSelect: true,
9
- YamlEditor: true,
10
- Checkbox: true
8
+ Banner: true,
9
+ LabeledSelect: true,
10
+ YamlEditor: true,
11
+ Checkbox: true,
12
+ RichTranslation: true
11
13
  };
12
14
 
13
15
  const defaultCiliumStubs = {
14
- LabeledSelect: true,
15
- YamlEditor: true,
16
+ LabeledSelect: true,
17
+ YamlEditor: true,
18
+ RichTranslation: true
16
19
  };
17
20
 
18
21
  // const defaultComputed = {
@@ -25,46 +28,65 @@ const defaultCiliumStubs = {
25
28
  // };
26
29
 
27
30
  const mockAgentArgs = { 'cloud-provider-name': { options: [], profile: { options: [{ anything: 'yes' }] } } };
28
- const mockServerArgs = { disable: {}, cni: { options: [] } };
29
-
31
+ const mockServerArgs = { disable: { options: [] }, cni: { options: [] } };
32
+
33
+ jest.mock('@shell/edit/provisioning.cattle.io.cluster/shared', () => ({
34
+ RETENTION_DEFAULT: 5,
35
+ RKE2_INGRESS_NGINX: 'rke2-ingress-nginx',
36
+ RKE2_TRAEFIK: 'rke2-traefik',
37
+ INGRESS_NGINX: 'ingress-nginx',
38
+ INGRESS_CONTROLLER: 'ingress-controller',
39
+ TRAEFIK: 'traefik',
40
+ HARVESTER: 'harvester',
41
+ INGRESS_DUAL: 'dual',
42
+ INGRESS_NONE: 'none',
43
+ INGRESS_OPTIONS: [],
44
+ INGRESS_MIGRATION_KB_LINK: 'mock-link'
45
+ }));
46
+ const mockRke2Charts = {
47
+ [RKE2_INGRESS_NGINX]: {},
48
+ [RKE2_TRAEFIK]: {},
49
+ 'rke2-cilium': {}
50
+ };
51
+ const mockK3sCharts = { 'rke2-cilium': {} };
30
52
  const rke2Versions = [
31
53
  {
32
- id: 'v1.31.0+rke2r1', value: 'v1.31.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
54
+ id: 'v1.31.0+rke2r1', value: 'v1.31.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: mockRke2Charts
33
55
  },
34
56
  {
35
- id: 'v1.30.0+rke2r1', value: 'v1.30.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
57
+ id: 'v1.30.0+rke2r1', value: 'v1.30.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: mockRke2Charts
36
58
  },
37
59
  {
38
- id: 'v1.29.1+rke2r1', value: 'v1.29.1+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
60
+ id: 'v1.29.1+rke2r1', value: 'v1.29.1+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: mockRke2Charts
39
61
  },
40
62
  {
41
- id: 'v1.25.0+rke2r1', value: 'v1.25.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
63
+ id: 'v1.25.0+rke2r1', value: 'v1.25.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: mockRke2Charts
42
64
  },
43
65
  {
44
- id: 'v1.24.0+rke2r1', value: 'v1.24.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
66
+ id: 'v1.24.0+rke2r1', value: 'v1.24.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: mockRke2Charts
45
67
  },
46
68
  {
47
- id: 'v1.23.0+rke2r1', value: 'v1.23.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
69
+ id: 'v1.23.0+rke2r1', value: 'v1.23.0+rke2r1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: mockRke2Charts
48
70
  }
49
71
  ];
50
72
  const k3sVersions = [
51
73
  {
52
- id: 'v1.31.0+k3s1', value: 'v1.31.0+k3s1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
74
+ id: 'v1.31.0+k3s1', value: 'v1.31.0+k3s1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: mockK3sCharts
53
75
  },
54
76
  {
55
- id: 'v1.30.0+k3s1', value: 'v1.30.0+k3s1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
77
+ id: 'v1.30.0+k3s1', value: 'v1.30.0+k3s1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: mockK3sCharts
56
78
  },
57
79
  {
58
- id: 'v1.29.1+k3s1', value: 'v1.29.1+k3s1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
80
+ id: 'v1.29.1+k3s1', value: 'v1.29.1+k3s1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: mockK3sCharts
59
81
  },
60
82
  {
61
- id: 'v1.25.0+k3s1', value: 'v1.25.0+k3s1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
83
+ id: 'v1.25.0+k3s1', value: 'v1.25.0+k3s1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: mockK3sCharts
62
84
  },
63
85
  {
64
- id: 'v1.24.0+k3s1', value: 'v1.24.0+k3s1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
86
+ id: 'v1.24.0+k3s1', value: 'v1.24.0+k3s1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: mockK3sCharts
65
87
  },
66
88
  {
67
- id: 'v1.23.0+k3s1', value: 'v1.23.0+k3s1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: {}
89
+ id: 'v1.23.0+k3s1', value: 'v1.23.0+k3s1', serverArgs: mockServerArgs, agentArgs: mockAgentArgs, charts: mockK3sCharts
68
90
  }
69
91
  ];
70
92
  const mockVersionOptions = [...rke2Versions, ...k3sVersions];
@@ -83,7 +105,7 @@ const defaultMocks = {
83
105
  $route: {
84
106
  name: 'anything',
85
107
  query: { AS: 'yaml' },
86
- },
108
+ }
87
109
  };
88
110
 
89
111
  const defaultSpec = {
@@ -103,6 +125,9 @@ const bmOffValue = { bandwidthManager: { enabled: false } };
103
125
  function createBasicsTab(version : string, userChartValues: any, options = {}) {
104
126
  const k8s = mockVersionOptions.find((v) => v.id === version) || mockVersionOptions[0];
105
127
  const label = 'whatever';
128
+ const providedUserChartValues = userChartValues || {};
129
+ const providedVersionInfo = k8s.charts || {};
130
+
106
131
  const wrapper = mount(Basics, {
107
132
  props: {
108
133
  mode: 'create',
@@ -116,7 +141,8 @@ function createBasicsTab(version : string, userChartValues: any, options = {}) {
116
141
  },
117
142
  addonVersions: [],
118
143
  provider: 'custom',
119
- userChartValues: userChartValues || {},
144
+ userChartValues: providedUserChartValues,
145
+ versionInfo: providedVersionInfo,
120
146
  cisOverride: false,
121
147
  cisPsaChangeBanner: true,
122
148
  allPsas: [],
@@ -142,7 +168,6 @@ function createBasicsTab(version : string, userChartValues: any, options = {}) {
142
168
  ...defaultMocks,
143
169
  $store: { getters: defaultGetters },
144
170
  },
145
-
146
171
  stubs: defaultCiliumStubs,
147
172
  },
148
173
  });
@@ -176,6 +201,8 @@ describe('component: Basics', () => {
176
201
  },
177
202
  provider: 'whatever',
178
203
  userChartValues: {},
204
+ addonVersions: [],
205
+ versionInfo: {},
179
206
  cisOverride: false,
180
207
  cisPsaChangeBanner: true,
181
208
  allPsas: [],
@@ -228,6 +255,8 @@ describe('component: Basics', () => {
228
255
  },
229
256
  provider: 'whatever',
230
257
  userChartValues: {},
258
+ addonVersions: [],
259
+ versionInfo: {},
231
260
  cisOverride: false,
232
261
  cisPsaChangeBanner: true,
233
262
  allPsas: [],
@@ -277,6 +306,8 @@ describe('component: Basics', () => {
277
306
  },
278
307
  provider: 'custom',
279
308
  userChartValues: {},
309
+ addonVersions: [],
310
+ versionInfo: {},
280
311
  cisPsaChangeBanner: true,
281
312
  allPsas: [],
282
313
  cisOverride: override,
@@ -284,7 +315,7 @@ describe('component: Basics', () => {
284
315
  versionOptions: [{
285
316
  value: k8s,
286
317
  agentArgs: { profile: { options: [cis] } },
287
- charts: {},
318
+ charts: mockRke2Charts,
288
319
  profile: { options: [cis] }
289
320
  }],
290
321
  isHarvesterDriver: false,
@@ -1,4 +1,4 @@
1
- import { mount, shallowMount } from '@vue/test-utils';
1
+ import { shallowMount } from '@vue/test-utils';
2
2
  import Networking from '@shell/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue';
3
3
 
4
4
  const mockServerArgs = { disable: {}, cni: { options: [] } };
@@ -47,34 +47,6 @@ describe('component: RKE2Networking', () => {
47
47
  expect(dropdown.props('options')).toHaveLength(3);
48
48
  });
49
49
 
50
- it('should show an error when an ipv6 pool is present and the user selects the ipv4-only stack preference when creating a new cluster', async() => {
51
- const spec = { ...defaultSpec, rkeConfig: { ...defaultSpec.rkeConfig, networking: { stackPreference: 'ipv4' } } };
52
- const wrapper = mount(Networking, {
53
- propsData: {
54
- mode: 'create',
55
- value: { spec },
56
- selectedVersion: { serverArgs: mockServerArgs },
57
- hasSomeIpv6Pools: true,
58
- },
59
- global: {
60
- mocks: {
61
- ...defaultMocks,
62
- $store: { getters: defaultGetters },
63
- },
64
- },
65
- });
66
-
67
- expect(wrapper.emitted('validationChanged')?.[0]?.[0]).toBe(false);
68
- expect(wrapper.emitted('validationChanged')).toHaveLength(1);
69
-
70
- spec.rkeConfig.networking.stackPreference = 'ipv6';
71
- wrapper.setProps({ value: { spec } });
72
- await wrapper.vm.$nextTick();
73
-
74
- expect(wrapper.emitted('validationChanged')?.[1]?.[0]).toBe(true);
75
- expect(wrapper.emitted('validationChanged')).toHaveLength(2);
76
- });
77
-
78
50
  it('should show a flannel masq input when provisioning k3s and flannel is enabled', () => {
79
51
  const spec = { ...defaultSpec } as any;
80
52
 
@@ -119,78 +91,4 @@ describe('component: RKE2Networking', () => {
119
91
  expect(wrapper.vm.showFlannelMasq).toBe(false);
120
92
  expect(input.exists()).toBe(false);
121
93
  });
122
-
123
- it('should automatically check the flannel masq input when stack preference is changed from ipv4 to ipv6 or dual', async() => {
124
- const spec = { ...defaultSpec } as any;
125
-
126
- spec.rkeConfig.networking.stackPreference = 'ipv4';
127
-
128
- const wrapper = shallowMount(Networking, {
129
- propsData: {
130
- mode: 'create',
131
- value: { spec },
132
- selectedVersion: { serverArgs: mockServerArgs, label: 'k3s' },
133
- },
134
- global: { mocks: {} }
135
- });
136
-
137
- const newSpec = { ...spec };
138
-
139
- newSpec.rkeConfig.networking.stackPreference = 'dual';
140
-
141
- await wrapper.setProps({ value: { spec: newSpec } });
142
-
143
- expect(wrapper.emitted('enable-flannel-masq-changed')?.[0]?.[0]).toBe(true);
144
- });
145
-
146
- it('should automatically un-check the flannel masq input when stack preference is changed from ipv6 or dual to ipv4', async() => {
147
- const spec = { ...defaultSpec } as any;
148
-
149
- spec.rkeConfig.networking.stackPreference = 'ipv6';
150
-
151
- const wrapper = shallowMount(Networking, {
152
- propsData: {
153
- mode: 'create',
154
- value: { spec },
155
- selectedVersion: { serverArgs: mockServerArgs, label: 'k3s' },
156
- },
157
- global: {
158
- mocks: {
159
- ...defaultMocks,
160
- $store: { getters: defaultGetters },
161
- },
162
- },
163
- });
164
-
165
- const newSpec = { ...spec };
166
-
167
- newSpec.rkeConfig.networking.stackPreference = 'ipv4';
168
-
169
- await wrapper.setProps({ value: { spec: newSpec } });
170
-
171
- expect(wrapper.emitted('enable-flannel-masq-changed')?.[0]?.[0]).toBe(false);
172
- });
173
-
174
- it('should not automatically update stack preference or validate it when editing an existing cluster even if its set to ipv4 and the user appears to have ipv6 pools', async() => {
175
- const spec = { ...defaultSpec, rkeConfig: { ...defaultSpec.rkeConfig, networking: { stackPreference: 'ipv4' } } };
176
- const wrapper = mount(Networking, {
177
- propsData: {
178
- mode: 'edit',
179
- value: { spec },
180
- selectedVersion: { serverArgs: mockServerArgs },
181
- hasSomeIpv6Pools: true,
182
- },
183
- global: {
184
- mocks: {
185
- ...defaultMocks,
186
- $store: { getters: defaultGetters },
187
- },
188
- },
189
- });
190
-
191
- await wrapper.vm.$nextTick();
192
-
193
- expect(wrapper.emitted('validationChanged')?.[0]?.[0]).toBe(true);
194
- expect(wrapper.emitted('stack-preference-changed')).toBeUndefined();
195
- });
196
94
  });
@@ -1,7 +1,19 @@
1
1
  import { shallowMount } from '@vue/test-utils';
2
2
  import { createStore } from 'vuex';
3
3
  import ClusterCreate from '@shell/edit/provisioning.cattle.io.cluster/index.vue';
4
-
4
+ jest.mock('@shell/edit/provisioning.cattle.io.cluster/shared', () => ({
5
+ RETENTION_DEFAULT: 5,
6
+ RKE2_INGRESS_NGINX: 'rke2-ingress-nginx',
7
+ RKE2_TRAEFIK: 'rke2-traefik',
8
+ INGRESS_NGINX: 'ingress-nginx',
9
+ INGRESS_CONTROLLER: 'ingress-controller',
10
+ TRAEFIK: 'traefik',
11
+ HARVESTER: 'harvester',
12
+ INGRESS_DUAL: 'dual',
13
+ INGRESS_NONE: 'none',
14
+ INGRESS_OPTIONS: [],
15
+ INGRESS_MIGRATION_KB_LINK: 'mock-link'
16
+ }));
5
17
  describe('component: Cluster: Create', () => {
6
18
  it('should hide RKE1 and RKE2 toggle button if RKE1 ui feature flag is NOT set', () => {
7
19
  const store = createStore({
@@ -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
+ });