@openshift-assisted/ui-lib 2.54.1 → 5.0.1-cim
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/build/@types/cim/components/modals/CimConfiguration/CimStorageMissingAlert.d.ts.map +1 -1
- package/build/@types/cim/components/modals/CimConfiguration/constants.d.ts +1 -1
- package/build/@types/common/components/clusterConfiguration/utils.d.ts +9 -1
- package/build/@types/common/components/clusterConfiguration/utils.d.ts.map +1 -1
- package/build/@types/common/components/clusterWizard/networkingSteps/AvailableSubnetsControl.d.ts.map +1 -1
- package/build/@types/common/components/clusterWizard/networkingSteps/StackTypeControlGroup.d.ts.map +1 -1
- package/build/@types/ocm/components/Routes.d.ts +1 -1
- package/build/@types/ocm/components/Routes.d.ts.map +1 -1
- package/build/@types/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfiguration.d.ts.map +1 -1
- package/build/@types/ocm/components/clusterConfiguration/networkConfiguration/networkConfigurationValidation.d.ts.map +1 -1
- package/build/@types/ocm/components/clusterConfiguration/review/ReviewNetworkingTable.d.ts.map +1 -1
- package/build/@types/ocm/components/clusterConfiguration/review/utils.d.ts +1 -1
- package/build/@types/ocm/components/clusterConfiguration/review/utils.d.ts.map +1 -1
- package/build/@types/ocm/components/clusterDetail/AssistedInstallerDetailCard.d.ts +1 -1
- package/build/@types/ocm/components/clusterDetail/AssistedInstallerDetailCard.d.ts.map +1 -1
- package/build/@types/ocm/components/ui/Buttons/BackButton.d.ts +1 -1
- package/build/@types/ocm/components/ui/Buttons/BackButton.d.ts.map +1 -1
- package/build/@types/ocm/store/hooks.d.ts +1 -1
- package/build/@types/ocm/store/slices/clusters/selectors.d.ts +5 -61
- package/build/@types/ocm/store/slices/clusters/selectors.d.ts.map +1 -1
- package/build/@types/ocm/store/slices/feature-flags/selectors.d.ts +2 -20
- package/build/@types/ocm/store/slices/feature-flags/selectors.d.ts.map +1 -1
- package/build/@types/ocm/store/slices/infra-envs/selectors.d.ts +4 -21
- package/build/@types/ocm/store/slices/infra-envs/selectors.d.ts.map +1 -1
- package/build/cjs/cim/components/Agent/NoAgentsAlert.js +2 -2
- package/build/cjs/cim/components/Agent/NoAgentsAlert.js.map +1 -1
- package/build/cjs/cim/components/Agent/tableColumns.js +3 -3
- package/build/cjs/cim/components/Agent/tableColumns.js.map +1 -1
- package/build/cjs/cim/components/Hypershift/DetailsPage/NodePoolsTable.js +2 -2
- package/build/cjs/cim/components/Hypershift/DetailsPage/NodePoolsTable.js.map +1 -1
- package/build/cjs/cim/components/InfraEnv/AddHostDropdown.js +2 -2
- package/build/cjs/cim/components/InfraEnv/AddHostDropdown.js.map +1 -1
- package/build/cjs/cim/components/modals/CimConfiguration/CimConfigProgressAlert.js +3 -3
- package/build/cjs/cim/components/modals/CimConfiguration/CimConfigProgressAlert.js.map +1 -1
- package/build/cjs/cim/components/modals/CimConfiguration/CimConfigurationFormFields.js +1 -1
- package/build/cjs/cim/components/modals/CimConfiguration/CimConfigurationFormFields.js.map +1 -1
- package/build/cjs/cim/components/modals/CimConfiguration/CimConfigurationModal.js +2 -2
- package/build/cjs/cim/components/modals/CimConfiguration/CimConfigurationModal.js.map +1 -1
- package/build/cjs/cim/components/modals/CimConfiguration/CimStorageMissingAlert.js +3 -3
- package/build/cjs/cim/components/modals/CimConfiguration/CimStorageMissingAlert.js.map +1 -1
- package/build/cjs/cim/components/modals/CimConfiguration/constants.js +1 -1
- package/build/cjs/cim/components/modals/MassDeleteAgentModal.js +2 -2
- package/build/cjs/cim/components/modals/MassDeleteAgentModal.js.map +1 -1
- package/build/cjs/common/components/clusterConfiguration/utils.js +13 -1
- package/build/cjs/common/components/clusterConfiguration/utils.js.map +1 -1
- package/build/cjs/common/components/clusterConfiguration/utils.test.js +36 -0
- package/build/cjs/common/components/clusterConfiguration/utils.test.js.map +1 -1
- package/build/cjs/common/components/clusterWizard/networkingSteps/AvailableSubnetsControl.js +29 -31
- package/build/cjs/common/components/clusterWizard/networkingSteps/AvailableSubnetsControl.js.map +1 -1
- package/build/cjs/common/components/clusterWizard/networkingSteps/StackTypeControlGroup.js +19 -30
- package/build/cjs/common/components/clusterWizard/networkingSteps/StackTypeControlGroup.js.map +1 -1
- package/build/cjs/common/validationSchemas/addressValidation.js +1 -1
- package/build/cjs/common/validationSchemas/addressValidation.js.map +1 -1
- package/build/cjs/ocm/components/Routes.js +8 -8
- package/build/cjs/ocm/components/Routes.js.map +1 -1
- package/build/cjs/ocm/components/clusterConfiguration/OcmClusterProgressItems.js +1 -1
- package/build/cjs/ocm/components/clusterConfiguration/OcmClusterProgressItems.js.map +1 -1
- package/build/cjs/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfiguration.js +68 -17
- package/build/cjs/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfiguration.js.map +1 -1
- package/build/cjs/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfigurationForm.js +1 -1
- package/build/cjs/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfigurationForm.js.map +1 -1
- package/build/cjs/ocm/components/clusterConfiguration/networkConfiguration/networkConfigurationValidation.js +50 -13
- package/build/cjs/ocm/components/clusterConfiguration/networkConfiguration/networkConfigurationValidation.js.map +1 -1
- package/build/cjs/ocm/components/clusterConfiguration/review/ReviewNetworkingTable.js +4 -2
- package/build/cjs/ocm/components/clusterConfiguration/review/ReviewNetworkingTable.js.map +1 -1
- package/build/cjs/ocm/components/clusterConfiguration/review/utils.js +7 -1
- package/build/cjs/ocm/components/clusterConfiguration/review/utils.js.map +1 -1
- package/build/cjs/ocm/components/clusterConfiguration/review/utils.test.js +35 -0
- package/build/cjs/ocm/components/clusterConfiguration/review/utils.test.js.map +1 -1
- package/build/cjs/ocm/components/clusterDetail/AssistedInstallerDetailCard.js +4 -4
- package/build/cjs/ocm/components/clusterDetail/AssistedInstallerDetailCard.js.map +1 -1
- package/build/cjs/ocm/components/clusterDetail/ClusterDetail.js +4 -4
- package/build/cjs/ocm/components/clusterDetail/ClusterDetail.js.map +1 -1
- package/build/cjs/ocm/components/clusterWizard/ClusterDetails.js +4 -4
- package/build/cjs/ocm/components/clusterWizard/ClusterDetails.js.map +1 -1
- package/build/cjs/ocm/components/clusterWizard/ClusterDetailsForm.js +2 -2
- package/build/cjs/ocm/components/clusterWizard/ClusterDetailsForm.js.map +1 -1
- package/build/cjs/ocm/components/clusterWizard/ClusterWizardContextProvider.js +2 -2
- package/build/cjs/ocm/components/clusterWizard/ClusterWizardContextProvider.js.map +1 -1
- package/build/cjs/ocm/components/clusterWizard/ClusterWizardFooter.js +2 -2
- package/build/cjs/ocm/components/clusterWizard/ClusterWizardFooter.js.map +1 -1
- package/build/cjs/ocm/components/clusterWizard/Operators.js +4 -4
- package/build/cjs/ocm/components/clusterWizard/Operators.js.map +1 -1
- package/build/cjs/ocm/components/clusterWizard/disconnected/ReviewStep.js +3 -3
- package/build/cjs/ocm/components/clusterWizard/disconnected/ReviewStep.js.map +1 -1
- package/build/cjs/ocm/components/clusters/ClusterBreadcrumbs.js +2 -2
- package/build/cjs/ocm/components/clusters/ClusterBreadcrumbs.js.map +1 -1
- package/build/cjs/ocm/components/clusters/ClusterPage.js +4 -4
- package/build/cjs/ocm/components/clusters/ClusterPage.js.map +1 -1
- package/build/cjs/ocm/components/clusters/Clusters.js +3 -3
- package/build/cjs/ocm/components/clusters/Clusters.js.map +1 -1
- package/build/cjs/ocm/components/clusters/ClustersListToolbar.js +3 -3
- package/build/cjs/ocm/components/clusters/ClustersListToolbar.js.map +1 -1
- package/build/cjs/ocm/components/ui/Buttons/BackButton.js +2 -2
- package/build/cjs/ocm/components/ui/Buttons/BackButton.js.map +1 -1
- package/build/cjs/ocm/store/slices/clusters/selectors.js +2 -2
- package/build/cjs/ocm/store/slices/clusters/selectors.js.map +1 -1
- package/build/cjs/ocm/store/slices/feature-flags/selectors.js.map +1 -1
- package/build/cjs/ocm/store/slices/infra-envs/selectors.js.map +1 -1
- package/lib/cim/components/Agent/NoAgentsAlert.tsx +1 -1
- package/lib/cim/components/Agent/tableColumns.tsx +1 -1
- package/lib/cim/components/Hypershift/DetailsPage/NodePoolsTable.tsx +1 -1
- package/lib/cim/components/InfraEnv/AddHostDropdown.tsx +1 -1
- package/lib/cim/components/modals/CimConfiguration/CimConfigProgressAlert.tsx +2 -2
- package/lib/cim/components/modals/CimConfiguration/CimConfigurationFormFields.tsx +1 -1
- package/lib/cim/components/modals/CimConfiguration/CimConfigurationModal.tsx +2 -2
- package/lib/cim/components/modals/CimConfiguration/CimStorageMissingAlert.tsx +5 -2
- package/lib/cim/components/modals/CimConfiguration/constants.ts +1 -1
- package/lib/cim/components/modals/MassDeleteAgentModal.tsx +1 -1
- package/lib/common/components/clusterConfiguration/utils.test.ts +43 -1
- package/lib/common/components/clusterConfiguration/utils.ts +13 -0
- package/lib/common/components/clusterWizard/networkingSteps/AvailableSubnetsControl.tsx +31 -57
- package/lib/common/components/clusterWizard/networkingSteps/StackTypeControlGroup.tsx +33 -38
- package/lib/common/validationSchemas/addressValidation.tsx +2 -2
- package/lib/ocm/components/Routes.tsx +2 -2
- package/lib/ocm/components/clusterConfiguration/OcmClusterProgressItems.tsx +2 -2
- package/lib/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfiguration.tsx +86 -22
- package/lib/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfigurationForm.tsx +2 -2
- package/lib/ocm/components/clusterConfiguration/networkConfiguration/networkConfigurationValidation.ts +57 -20
- package/lib/ocm/components/clusterConfiguration/review/ReviewNetworkingTable.tsx +4 -2
- package/lib/ocm/components/clusterConfiguration/review/utils.test.ts +41 -0
- package/lib/ocm/components/clusterConfiguration/review/utils.tsx +5 -2
- package/lib/ocm/components/clusterDetail/AssistedInstallerDetailCard.tsx +1 -1
- package/lib/ocm/components/clusterDetail/ClusterDetail.tsx +3 -3
- package/lib/ocm/components/clusterWizard/ClusterDetails.tsx +2 -2
- package/lib/ocm/components/clusterWizard/ClusterDetailsForm.tsx +1 -1
- package/lib/ocm/components/clusterWizard/ClusterWizardContextProvider.tsx +1 -1
- package/lib/ocm/components/clusterWizard/ClusterWizardFooter.tsx +1 -1
- package/lib/ocm/components/clusterWizard/Operators.tsx +2 -2
- package/lib/ocm/components/clusterWizard/disconnected/ReviewStep.tsx +2 -2
- package/lib/ocm/components/clusters/ClusterBreadcrumbs.tsx +1 -1
- package/lib/ocm/components/clusters/ClusterPage.tsx +1 -1
- package/lib/ocm/components/clusters/Clusters.tsx +2 -2
- package/lib/ocm/components/clusters/ClustersListToolbar.tsx +2 -2
- package/lib/ocm/components/ui/Buttons/BackButton.tsx +1 -1
- package/lib/ocm/store/slices/clusters/selectors.tsx +7 -5
- package/lib/ocm/store/slices/feature-flags/selectors.ts +5 -2
- package/lib/ocm/store/slices/infra-envs/selectors.ts +4 -2
- package/package.json +8 -8
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { ButtonVariant, FormGroup, Split, SplitItem, Tooltip } from '@patternfly/react-core';
|
|
2
|
+
import { ButtonVariant, FormGroup, Radio, Split, SplitItem, Tooltip } from '@patternfly/react-core';
|
|
3
3
|
import { useFormikContext } from 'formik';
|
|
4
4
|
import { Address4, Address6 } from 'ip-address';
|
|
5
5
|
|
|
@@ -9,10 +9,9 @@ import {
|
|
|
9
9
|
NETWORK_TYPE_OVN,
|
|
10
10
|
NETWORK_TYPE_SDN,
|
|
11
11
|
} from '../../../types';
|
|
12
|
-
import { getFieldId } from '../../ui';
|
|
12
|
+
import { ConfirmationModal, getFieldId, PopoverIcon } from '../../ui';
|
|
13
13
|
import { DUAL_STACK, NO_SUBNET_SET, SINGLE_STACK } from '../../../config';
|
|
14
14
|
import { RadioField } from '../../ui/formik';
|
|
15
|
-
import { ConfirmationModal, PopoverIcon } from '../../ui';
|
|
16
15
|
import { useTranslation } from '../../../hooks/use-translation-wrapper';
|
|
17
16
|
import { reorderNetworksByCurrentPrimary } from './reorderNetworks';
|
|
18
17
|
import {
|
|
@@ -72,36 +71,32 @@ export const StackTypeControlGroup = ({
|
|
|
72
71
|
|
|
73
72
|
const IPv6Subnets = hostSubnets.filter((subnet) => Address6.isValid(subnet.subnet));
|
|
74
73
|
const cidrIPv6 = IPv6Subnets.length >= 1 ? IPv6Subnets[0].subnet : NO_SUBNET_SET;
|
|
74
|
+
const isSingleStackSelected = values.stackType !== DUAL_STACK;
|
|
75
|
+
|
|
75
76
|
const shouldSetSingleStack =
|
|
76
77
|
!isViewerMode && !isDualStackSelectable && values.stackType === DUAL_STACK;
|
|
77
78
|
|
|
78
79
|
const setSingleStack = React.useCallback(() => {
|
|
79
80
|
setFieldValue('stackType', SINGLE_STACK);
|
|
80
81
|
|
|
81
|
-
// Determine whether the first machine network is IPv4
|
|
82
82
|
const firstNetwork = values.machineNetworks?.[0];
|
|
83
83
|
const isFirstIPv4 = Boolean(firstNetwork?.cidr && Address4.isValid(firstNetwork.cidr));
|
|
84
84
|
|
|
85
85
|
if (values.machineNetworks && values.machineNetworks?.length >= 2) {
|
|
86
|
-
// For single-stack IPv4, prefer IPv4 machine network
|
|
87
86
|
if (isFirstIPv4) {
|
|
88
|
-
// Keep the first network if it's IPv4
|
|
89
87
|
setFieldValue('machineNetworks', [firstNetwork]);
|
|
90
88
|
} else {
|
|
91
|
-
// If first is IPv6, look for IPv4 network or set empty for auto-selection
|
|
92
89
|
const ipv4Network = values.machineNetworks.find(
|
|
93
90
|
(network) => network.cidr && Address4.isValid(network.cidr),
|
|
94
91
|
);
|
|
95
92
|
if (ipv4Network) {
|
|
96
93
|
setFieldValue('machineNetworks', [ipv4Network]);
|
|
97
94
|
} else {
|
|
98
|
-
// No IPv4 network found, set empty for auto-selection
|
|
99
95
|
setFieldValue('machineNetworks', []);
|
|
100
96
|
}
|
|
101
97
|
}
|
|
102
98
|
}
|
|
103
99
|
|
|
104
|
-
// Set cluster/service to IPv4 defaults when switching to single-stack
|
|
105
100
|
if (values.clusterNetworks && values.clusterNetworks.length >= 1) {
|
|
106
101
|
const defaultCluster =
|
|
107
102
|
defaultNetworkValues.clusterNetworksIpv4 && defaultNetworkValues.clusterNetworksIpv4[0];
|
|
@@ -110,12 +105,12 @@ export const StackTypeControlGroup = ({
|
|
|
110
105
|
? {
|
|
111
106
|
cidr: defaultCluster.cidr,
|
|
112
107
|
hostPrefix: defaultCluster.hostPrefix,
|
|
113
|
-
clusterId: firstCluster.clusterId,
|
|
108
|
+
clusterId: firstCluster.clusterId,
|
|
114
109
|
}
|
|
115
110
|
: {
|
|
116
111
|
cidr: '',
|
|
117
112
|
hostPrefix: '',
|
|
118
|
-
clusterId: clusterId,
|
|
113
|
+
clusterId: clusterId,
|
|
119
114
|
};
|
|
120
115
|
setFieldValue('clusterNetworks', [ipv4Cluster]);
|
|
121
116
|
}
|
|
@@ -126,22 +121,20 @@ export const StackTypeControlGroup = ({
|
|
|
126
121
|
const ipv4Service = defaultService
|
|
127
122
|
? {
|
|
128
123
|
cidr: defaultService.cidr,
|
|
129
|
-
clusterId: firstService.clusterId,
|
|
124
|
+
clusterId: firstService.clusterId,
|
|
130
125
|
}
|
|
131
126
|
: {
|
|
132
127
|
cidr: '',
|
|
133
|
-
clusterId: clusterId,
|
|
128
|
+
clusterId: clusterId,
|
|
134
129
|
};
|
|
135
130
|
setFieldValue('serviceNetworks', [ipv4Service]);
|
|
136
131
|
}
|
|
137
132
|
|
|
138
|
-
// Keep only IPv4 VIPs when switching to single-stack (unless DHCP allocation is used)
|
|
139
133
|
if (!values.vipDhcpAllocation) {
|
|
140
134
|
const pruneVips = (
|
|
141
135
|
vips?: { ip?: string; clusterId?: Cluster['id'] }[],
|
|
142
136
|
): { ip: string; clusterId: Cluster['id'] }[] => {
|
|
143
137
|
if (!vips || vips.length === 0) return [];
|
|
144
|
-
// Choose which index to keep based on whether the first network is IPv4
|
|
145
138
|
const keepIndex = isFirstIPv4 ? 0 : 1;
|
|
146
139
|
const chosen = vips[keepIndex];
|
|
147
140
|
return chosen && chosen.ip
|
|
@@ -177,12 +170,10 @@ export const StackTypeControlGroup = ({
|
|
|
177
170
|
}
|
|
178
171
|
|
|
179
172
|
if (values.machineNetworks && values.machineNetworks?.length < 2) {
|
|
180
|
-
// Ensure IPv4 is primary when switching to dual-stack
|
|
181
173
|
const firstNetwork = values.machineNetworks[0];
|
|
182
174
|
const isFirstIPv6 = firstNetwork?.cidr && Address6.isValid(firstNetwork.cidr);
|
|
183
175
|
|
|
184
176
|
if (isFirstIPv6) {
|
|
185
|
-
// If first network is IPv6, make IPv4 primary and IPv6 secondary
|
|
186
177
|
const IPv4Subnets = hostSubnets.filter((subnet) => Address4.isValid(subnet.subnet));
|
|
187
178
|
const cidrIPv4 = IPv4Subnets.length >= 1 ? IPv4Subnets[0].subnet : NO_SUBNET_SET;
|
|
188
179
|
setFieldValue(
|
|
@@ -194,7 +185,6 @@ export const StackTypeControlGroup = ({
|
|
|
194
185
|
false,
|
|
195
186
|
);
|
|
196
187
|
} else {
|
|
197
|
-
// If first network is IPv4, add IPv6 as secondary
|
|
198
188
|
setFieldValue(
|
|
199
189
|
'machineNetworks',
|
|
200
190
|
[...values.machineNetworks, { cidr: cidrIPv6, clusterId: clusterId }],
|
|
@@ -225,7 +215,6 @@ export const StackTypeControlGroup = ({
|
|
|
225
215
|
};
|
|
226
216
|
setFieldValue('serviceNetworks', [...values.serviceNetworks, secondServiceNetwork], false);
|
|
227
217
|
}
|
|
228
|
-
// Initialize VIPs for dual-stack
|
|
229
218
|
if (values.apiVips && values.apiVips.length < 2) {
|
|
230
219
|
setFieldValue(
|
|
231
220
|
'apiVips',
|
|
@@ -244,8 +233,9 @@ export const StackTypeControlGroup = ({
|
|
|
244
233
|
);
|
|
245
234
|
}
|
|
246
235
|
};
|
|
247
|
-
|
|
236
|
+
|
|
248
237
|
const primaryCidr = values.machineNetworks?.[0]?.cidr;
|
|
238
|
+
|
|
249
239
|
React.useEffect(() => {
|
|
250
240
|
if (isViewerMode) {
|
|
251
241
|
return;
|
|
@@ -261,10 +251,11 @@ export const StackTypeControlGroup = ({
|
|
|
261
251
|
values.serviceNetworks,
|
|
262
252
|
]);
|
|
263
253
|
|
|
264
|
-
const
|
|
265
|
-
if (
|
|
266
|
-
|
|
267
|
-
}
|
|
254
|
+
const handleSingleStackRadioClick = () => {
|
|
255
|
+
if (isSingleStackSelected) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
if (
|
|
268
259
|
hasDualStackConfigurationChanged(
|
|
269
260
|
defaultNetworkValues.clusterNetworksDualstack || [],
|
|
270
261
|
defaultNetworkValues.serviceNetworksDualstack || [],
|
|
@@ -284,32 +275,34 @@ export const StackTypeControlGroup = ({
|
|
|
284
275
|
}
|
|
285
276
|
}, [shouldSetSingleStack, setSingleStack]);
|
|
286
277
|
|
|
278
|
+
const singleStackPopoverContent = allowSingleStackIPv6
|
|
279
|
+
? t('ai:Select a single address family (IPv4 or IPv6) for your machine network.')
|
|
280
|
+
: t('ai:Select this when your hosts are using only IPv4.');
|
|
281
|
+
|
|
282
|
+
const singleStackRadioId = getFieldId('stackType', 'radio', SINGLE_STACK);
|
|
283
|
+
|
|
287
284
|
return (
|
|
288
285
|
<>
|
|
289
286
|
<FormGroup
|
|
290
|
-
label=
|
|
287
|
+
label={t('ai:Networking stack type')}
|
|
291
288
|
fieldId={getFieldId('stackType', 'radio')}
|
|
292
|
-
onChange={setStackType}
|
|
293
289
|
isInline
|
|
294
290
|
>
|
|
295
291
|
<Split>
|
|
296
292
|
<SplitItem>
|
|
297
|
-
<
|
|
298
|
-
|
|
293
|
+
<Radio
|
|
294
|
+
id={singleStackRadioId}
|
|
295
|
+
name="stackType"
|
|
299
296
|
value={SINGLE_STACK}
|
|
300
|
-
isDisabled={!isDualStackSelectable || isViewerMode}
|
|
301
297
|
label={`${singleStackLabel}\u00A0`}
|
|
298
|
+
isChecked={isSingleStackSelected}
|
|
299
|
+
isDisabled={!isDualStackSelectable || isViewerMode}
|
|
300
|
+
onChange={() => handleSingleStackRadioClick()}
|
|
301
|
+
data-testid="form-radio-stackType-singleStack-field"
|
|
302
302
|
/>
|
|
303
303
|
</SplitItem>
|
|
304
304
|
<SplitItem>
|
|
305
|
-
<PopoverIcon
|
|
306
|
-
bodyContent={
|
|
307
|
-
allowSingleStackIPv6
|
|
308
|
-
? t('ai:Select a single address family (IPv4 or IPv6) for your machine network.')
|
|
309
|
-
: t('ai:Select this when your hosts are using only IPv4.')
|
|
310
|
-
}
|
|
311
|
-
buttonStyle={{ top: '-4px' }}
|
|
312
|
-
/>
|
|
305
|
+
<PopoverIcon bodyContent={singleStackPopoverContent} buttonStyle={{ top: '-4px' }} />
|
|
313
306
|
</SplitItem>
|
|
314
307
|
</Split>
|
|
315
308
|
<Split>
|
|
@@ -325,6 +318,8 @@ export const StackTypeControlGroup = ({
|
|
|
325
318
|
value={DUAL_STACK}
|
|
326
319
|
isDisabled={!isDualStackSelectable || isViewerMode}
|
|
327
320
|
label="Dual-stack "
|
|
321
|
+
callFormikOnChange={false}
|
|
322
|
+
onChange={() => setDualStack()}
|
|
328
323
|
/>
|
|
329
324
|
</Tooltip>
|
|
330
325
|
</SplitItem>
|
|
@@ -343,7 +338,7 @@ export const StackTypeControlGroup = ({
|
|
|
343
338
|
titleIconVariant={'warning'}
|
|
344
339
|
confirmationButtonText={'Change'}
|
|
345
340
|
confirmationButtonVariant={ButtonVariant.primary}
|
|
346
|
-
content={<p>All data and configuration done for
|
|
341
|
+
content={<p>All data and configuration done for 'Dual-stack' will be lost.</p>}
|
|
347
342
|
onClose={() => {
|
|
348
343
|
setConfirmModal(false);
|
|
349
344
|
setDualStack();
|
|
@@ -9,7 +9,7 @@ import { HostSubnets, NetworkConfigurationValues } from '../types';
|
|
|
9
9
|
import { IP_V4_ZERO, IP_V6_ZERO, MAC_REGEX } from './regexes';
|
|
10
10
|
import { getArrayIndexFromPath, isIPorDN, isIPv4Address, isIPv6Address } from './utils';
|
|
11
11
|
import { NO_SUBNET_SET } from '../config';
|
|
12
|
-
import {
|
|
12
|
+
import { overlapCidr } from 'cidr-tools';
|
|
13
13
|
import parseUrl from 'parse-url';
|
|
14
14
|
import { TFunction } from 'i18next';
|
|
15
15
|
|
|
@@ -272,7 +272,7 @@ export const ipBlockValidationSchema = (
|
|
|
272
272
|
.test('cidrs-can-not-overlap', t('ai:Provided CIDRs can not overlap.'), (cidr: string) => {
|
|
273
273
|
try {
|
|
274
274
|
if (cidr && reservedCidrs && reservedCidrs.length > 0) {
|
|
275
|
-
return !
|
|
275
|
+
return !overlapCidr(cidr, reservedCidrs);
|
|
276
276
|
}
|
|
277
277
|
} catch {
|
|
278
278
|
return false;
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
Outlet,
|
|
8
8
|
unstable_HistoryRouter as HistoryRouter,
|
|
9
9
|
HistoryRouterProps,
|
|
10
|
-
} from 'react-router
|
|
10
|
+
} from 'react-router';
|
|
11
11
|
import { Clusters, ClusterPage, NewClusterPage } from './clusters';
|
|
12
12
|
import type { FeatureListType } from '../../common/features/featureGate';
|
|
13
13
|
import { AssistedUILibVersion } from './ui';
|
|
@@ -39,7 +39,7 @@ export const UILibRoutes = ({
|
|
|
39
39
|
<Route index element={<Clusters />} />
|
|
40
40
|
</Route>
|
|
41
41
|
{children}
|
|
42
|
-
<Route path="*" element={<Navigate to="assisted-installer/clusters" />} />
|
|
42
|
+
<Route path="*" element={<Navigate to="/assisted-installer/clusters" />} />
|
|
43
43
|
</Routes>
|
|
44
44
|
</>
|
|
45
45
|
);
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
EventListFetchProps,
|
|
5
5
|
getEnabledHosts,
|
|
6
6
|
RenderIf,
|
|
7
|
-
|
|
7
|
+
selectAllOlmOperators,
|
|
8
8
|
} from '../../../common';
|
|
9
9
|
import { FinalizingProgress } from '../../../common/components/clusterDetail/FinalizingProgress';
|
|
10
10
|
import { ProgressBarTexts } from '../../../common/components/clusterDetail/ProgressBarTexts';
|
|
@@ -26,7 +26,7 @@ const OcmClusterProgressItems = ({
|
|
|
26
26
|
fallbackEventsURL,
|
|
27
27
|
}: OcmClusterProgressItemsProps) => {
|
|
28
28
|
const enabledHosts = getEnabledHosts(cluster.hosts);
|
|
29
|
-
const olmOperators =
|
|
29
|
+
const olmOperators = selectAllOlmOperators(cluster);
|
|
30
30
|
|
|
31
31
|
const masterHosts = enabledHosts.filter((host) => host.role && 'master' === host.role);
|
|
32
32
|
const workerHosts = enabledHosts.filter((host) => host.role && 'worker' === host.role);
|
package/lib/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfiguration.tsx
CHANGED
|
@@ -6,13 +6,16 @@ import {
|
|
|
6
6
|
canBeDualStack,
|
|
7
7
|
CpuArchitecture,
|
|
8
8
|
DUAL_STACK,
|
|
9
|
+
getIPv6FromDualstack,
|
|
9
10
|
HostSubnets,
|
|
10
11
|
isAdvNetworkConf,
|
|
11
12
|
isSNO,
|
|
12
13
|
NetworkConfigurationValues,
|
|
14
|
+
NO_SUBNET_SET,
|
|
13
15
|
selectApiVip,
|
|
14
16
|
selectIngressVip,
|
|
15
17
|
} from '../../../../common';
|
|
18
|
+
import { Address6 } from 'ip-address';
|
|
16
19
|
import {
|
|
17
20
|
ManagedNetworkingControlGroup,
|
|
18
21
|
UserManagedNetworkingTextContent,
|
|
@@ -36,6 +39,7 @@ import {
|
|
|
36
39
|
} from '@openshift-assisted/types/assisted-installer-service';
|
|
37
40
|
import useSupportLevelsAPI from '../../../hooks/useSupportLevelsAPI';
|
|
38
41
|
import { isOciPlatformType } from '../../utils';
|
|
42
|
+
import { useFeature } from '../../../hooks/use-feature';
|
|
39
43
|
|
|
40
44
|
export type NetworkConfigurationProps = VirtualIPControlGroupProps & {
|
|
41
45
|
hostSubnets: HostSubnets;
|
|
@@ -122,6 +126,33 @@ const getManagedNetworkingState = (
|
|
|
122
126
|
};
|
|
123
127
|
};
|
|
124
128
|
|
|
129
|
+
type DefaultNetworkSettings = NetworkConfigurationProps['defaultNetworkSettings'];
|
|
130
|
+
|
|
131
|
+
const getNetworkDefaultsByFamily = (
|
|
132
|
+
settings: DefaultNetworkSettings,
|
|
133
|
+
isDualStack: boolean,
|
|
134
|
+
isIPv6: boolean,
|
|
135
|
+
) => {
|
|
136
|
+
if (isDualStack) {
|
|
137
|
+
return {
|
|
138
|
+
clusterNetworkDefaults: settings.clusterNetworksDualstack,
|
|
139
|
+
serviceNetworkDefaults: settings.serviceNetworksDualstack,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
if (isIPv6) {
|
|
143
|
+
const ipv6Cluster = getIPv6FromDualstack(settings.clusterNetworksDualstack);
|
|
144
|
+
const ipv6Service = getIPv6FromDualstack(settings.serviceNetworksDualstack);
|
|
145
|
+
return {
|
|
146
|
+
clusterNetworkDefaults: ipv6Cluster ? [ipv6Cluster] : settings.clusterNetworksIpv4,
|
|
147
|
+
serviceNetworkDefaults: ipv6Service ? [ipv6Service] : settings.serviceNetworksIpv4,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
clusterNetworkDefaults: settings.clusterNetworksIpv4,
|
|
152
|
+
serviceNetworkDefaults: settings.serviceNetworksIpv4,
|
|
153
|
+
};
|
|
154
|
+
};
|
|
155
|
+
|
|
125
156
|
const NetworkConfiguration = ({
|
|
126
157
|
cluster,
|
|
127
158
|
hostSubnets,
|
|
@@ -136,8 +167,10 @@ const NetworkConfiguration = ({
|
|
|
136
167
|
cluster.platform?.type,
|
|
137
168
|
);
|
|
138
169
|
const { isViewerMode } = useSelector(selectCurrentClusterPermissionsState);
|
|
139
|
-
const { setFieldValue, values, validateField } =
|
|
170
|
+
const { setFieldValue, values, validateField, validateForm } =
|
|
171
|
+
useFormikContext<NetworkConfigurationValues>();
|
|
140
172
|
|
|
173
|
+
const isSingleClusterFeature = useFeature('ASSISTED_INSTALLER_SINGLE_CLUSTER_FEATURE');
|
|
141
174
|
const isSNOCluster = isSNO(cluster);
|
|
142
175
|
const isUserManagedNetworking = values.managedNetworkingType === 'userManaged';
|
|
143
176
|
const isDualStack = values.stackType === DUAL_STACK;
|
|
@@ -177,30 +210,18 @@ const NetworkConfiguration = ({
|
|
|
177
210
|
setAdvanced(checked);
|
|
178
211
|
|
|
179
212
|
if (!checked) {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
);
|
|
187
|
-
setFieldValue(
|
|
188
|
-
'serviceNetworks',
|
|
189
|
-
isDualStack
|
|
190
|
-
? defaultNetworkSettings.serviceNetworksDualstack
|
|
191
|
-
: defaultNetworkSettings.serviceNetworksIpv4,
|
|
192
|
-
true,
|
|
213
|
+
const primaryCidr = values.machineNetworks?.[0]?.cidr;
|
|
214
|
+
const isIPv6Stack = !!primaryCidr && Address6.isValid(primaryCidr);
|
|
215
|
+
const { clusterNetworkDefaults, serviceNetworkDefaults } = getNetworkDefaultsByFamily(
|
|
216
|
+
defaultNetworkSettings,
|
|
217
|
+
isDualStack,
|
|
218
|
+
isIPv6Stack,
|
|
193
219
|
);
|
|
220
|
+
setFieldValue('clusterNetworks', clusterNetworkDefaults, true);
|
|
221
|
+
setFieldValue('serviceNetworks', serviceNetworkDefaults, true);
|
|
194
222
|
}
|
|
195
223
|
},
|
|
196
|
-
[
|
|
197
|
-
setFieldValue,
|
|
198
|
-
isDualStack,
|
|
199
|
-
defaultNetworkSettings.clusterNetworksDualstack,
|
|
200
|
-
defaultNetworkSettings.clusterNetworksIpv4,
|
|
201
|
-
defaultNetworkSettings.serviceNetworksDualstack,
|
|
202
|
-
defaultNetworkSettings.serviceNetworksIpv4,
|
|
203
|
-
],
|
|
224
|
+
[setFieldValue, isDualStack, values.machineNetworks, defaultNetworkSettings],
|
|
204
225
|
);
|
|
205
226
|
|
|
206
227
|
React.useEffect(() => {
|
|
@@ -209,6 +230,47 @@ const NetworkConfiguration = ({
|
|
|
209
230
|
}
|
|
210
231
|
}, [isDualStack, isViewerMode, toggleAdvConfiguration]);
|
|
211
232
|
|
|
233
|
+
React.useEffect(() => {
|
|
234
|
+
if (!isSingleClusterFeature || isViewerMode || isDualStack || isAdvanced) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const primaryCidr = values.machineNetworks?.[0]?.cidr;
|
|
238
|
+
if (!primaryCidr || primaryCidr === NO_SUBNET_SET) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
const isIPv6 = Address6.isValid(primaryCidr);
|
|
242
|
+
const currentClusterCidr = values.clusterNetworks?.[0]?.cidr;
|
|
243
|
+
const clusterIsIPv6 = currentClusterCidr ? Address6.isValid(currentClusterCidr) : null;
|
|
244
|
+
|
|
245
|
+
if (clusterIsIPv6 === isIPv6) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const { clusterNetworkDefaults, serviceNetworkDefaults } = getNetworkDefaultsByFamily(
|
|
250
|
+
defaultNetworkSettings,
|
|
251
|
+
false,
|
|
252
|
+
isIPv6,
|
|
253
|
+
);
|
|
254
|
+
if (clusterNetworkDefaults) {
|
|
255
|
+
setFieldValue('clusterNetworks', clusterNetworkDefaults);
|
|
256
|
+
}
|
|
257
|
+
if (serviceNetworkDefaults) {
|
|
258
|
+
setFieldValue('serviceNetworks', serviceNetworkDefaults);
|
|
259
|
+
}
|
|
260
|
+
void validateForm();
|
|
261
|
+
}, [
|
|
262
|
+
isSingleClusterFeature,
|
|
263
|
+
isViewerMode,
|
|
264
|
+
isDualStack,
|
|
265
|
+
isAdvanced,
|
|
266
|
+
values.machineNetworks,
|
|
267
|
+
values.clusterNetworks,
|
|
268
|
+
defaultNetworkSettings,
|
|
269
|
+
setFieldValue,
|
|
270
|
+
validateForm,
|
|
271
|
+
cluster.id,
|
|
272
|
+
]);
|
|
273
|
+
|
|
212
274
|
const managedNetworkingState = React.useMemo(
|
|
213
275
|
() =>
|
|
214
276
|
getManagedNetworkingState(
|
|
@@ -252,6 +314,7 @@ const NetworkConfiguration = ({
|
|
|
252
314
|
hostSubnets={hostSubnets}
|
|
253
315
|
defaultNetworkValues={defaultNetworkSettings}
|
|
254
316
|
isViewerMode={isViewerMode}
|
|
317
|
+
allowSingleStackIPv6={isSingleClusterFeature}
|
|
255
318
|
/>
|
|
256
319
|
</StackItem>
|
|
257
320
|
)}
|
|
@@ -277,6 +340,7 @@ const NetworkConfiguration = ({
|
|
|
277
340
|
}
|
|
278
341
|
openshiftVersion={cluster.openshiftVersion}
|
|
279
342
|
isViewerMode={isViewerMode}
|
|
343
|
+
allowSingleStackIPv6={isSingleClusterFeature}
|
|
280
344
|
/>
|
|
281
345
|
</StackItem>
|
|
282
346
|
)}
|
package/lib/ocm/components/clusterConfiguration/networkConfiguration/NetworkConfigurationForm.tsx
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
getFormikErrorFields,
|
|
10
10
|
getHostSubnets,
|
|
11
11
|
HostSubnets,
|
|
12
|
-
|
|
12
|
+
DUAL_STACK,
|
|
13
13
|
isSNO,
|
|
14
14
|
LoadingState,
|
|
15
15
|
NetworkConfigurationValues,
|
|
@@ -262,7 +262,7 @@ const NetworkConfigurationPage = ({ cluster }: { cluster: Cluster }) => {
|
|
|
262
262
|
if (values.vipDhcpAllocation) {
|
|
263
263
|
delete params.apiVips;
|
|
264
264
|
delete params.ingressVips;
|
|
265
|
-
} else if (values.stackType
|
|
265
|
+
} else if (values.stackType !== DUAL_STACK) {
|
|
266
266
|
// The API will rebuild the default machineNetwork
|
|
267
267
|
params.machineNetworks = [];
|
|
268
268
|
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import * as Yup from 'yup';
|
|
2
2
|
import { TFunction } from 'i18next';
|
|
3
|
+
import { Address6 } from 'ip-address';
|
|
3
4
|
import {
|
|
4
5
|
clusterNetworksValidationSchema,
|
|
5
6
|
dualStackValidationSchema,
|
|
7
|
+
getIPv6FromDualstack,
|
|
8
|
+
isPrimaryIPv6,
|
|
6
9
|
HostSubnets,
|
|
7
10
|
isDualStack,
|
|
8
11
|
isSNO,
|
|
@@ -10,6 +13,7 @@ import {
|
|
|
10
13
|
NetworkConfigurationValues,
|
|
11
14
|
serviceNetworkValidationSchema,
|
|
12
15
|
IPv4ValidationSchema,
|
|
16
|
+
IPv6ValidationSchema,
|
|
13
17
|
sshPublicKeyValidationSchema,
|
|
14
18
|
SINGLE_STACK,
|
|
15
19
|
DUAL_STACK,
|
|
@@ -36,6 +40,38 @@ export const getNetworkInitialValues = (
|
|
|
36
40
|
): NetworkConfigurationValues => {
|
|
37
41
|
const isSNOCluster = isSNO(cluster);
|
|
38
42
|
const isDualStackType = isDualStack(cluster);
|
|
43
|
+
const primaryMachineNetworkCidr = cluster.machineNetworks?.[0]?.cidr;
|
|
44
|
+
const isIPv6OnlyStack =
|
|
45
|
+
!isDualStackType && !!primaryMachineNetworkCidr && Address6.isValid(primaryMachineNetworkCidr);
|
|
46
|
+
|
|
47
|
+
const getStackType = (): NetworkConfigurationValues['stackType'] => {
|
|
48
|
+
if (isDualStackType) return DUAL_STACK;
|
|
49
|
+
return SINGLE_STACK;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const getDefaultClusterNetworks = () => {
|
|
53
|
+
if (isDualStackType) return defaultNetworkValues.clusterNetworksDualstack;
|
|
54
|
+
if (isIPv6OnlyStack) {
|
|
55
|
+
const ipv6Entry = getIPv6FromDualstack(defaultNetworkValues.clusterNetworksDualstack);
|
|
56
|
+
return ipv6Entry ? [{ ...ipv6Entry, clusterId: cluster?.id }] : undefined;
|
|
57
|
+
}
|
|
58
|
+
return defaultNetworkValues.clusterNetworksIpv4?.map((network) => ({
|
|
59
|
+
...network,
|
|
60
|
+
clusterId: cluster?.id,
|
|
61
|
+
}));
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const getDefaultServiceNetworks = () => {
|
|
65
|
+
if (isDualStackType) return defaultNetworkValues.serviceNetworksDualstack;
|
|
66
|
+
if (isIPv6OnlyStack) {
|
|
67
|
+
const ipv6Entry = getIPv6FromDualstack(defaultNetworkValues.serviceNetworksDualstack);
|
|
68
|
+
return ipv6Entry ? [{ ...ipv6Entry, clusterId: cluster?.id }] : undefined;
|
|
69
|
+
}
|
|
70
|
+
return defaultNetworkValues.serviceNetworksIpv4?.map((network) => ({
|
|
71
|
+
...network,
|
|
72
|
+
clusterId: cluster?.id,
|
|
73
|
+
}));
|
|
74
|
+
};
|
|
39
75
|
|
|
40
76
|
return {
|
|
41
77
|
apiVips: cluster.apiVips,
|
|
@@ -50,23 +86,9 @@ export const getNetworkInitialValues = (
|
|
|
50
86
|
: 'clusterManaged',
|
|
51
87
|
networkType: cluster.networkType || NETWORK_TYPE_OVN,
|
|
52
88
|
machineNetworks: cluster.machineNetworks || [],
|
|
53
|
-
stackType:
|
|
54
|
-
clusterNetworks:
|
|
55
|
-
|
|
56
|
-
(isDualStackType
|
|
57
|
-
? defaultNetworkValues.clusterNetworksDualstack
|
|
58
|
-
: defaultNetworkValues.clusterNetworksIpv4?.map((network) => ({
|
|
59
|
-
...network,
|
|
60
|
-
clusterId: cluster?.id,
|
|
61
|
-
}))),
|
|
62
|
-
serviceNetworks:
|
|
63
|
-
cluster.serviceNetworks ||
|
|
64
|
-
(isDualStackType
|
|
65
|
-
? defaultNetworkValues.serviceNetworksDualstack
|
|
66
|
-
: defaultNetworkValues.serviceNetworksIpv4?.map((network) => ({
|
|
67
|
-
...network,
|
|
68
|
-
clusterId: cluster?.id,
|
|
69
|
-
}))),
|
|
89
|
+
stackType: getStackType(),
|
|
90
|
+
clusterNetworks: cluster.clusterNetworks || getDefaultClusterNetworks(),
|
|
91
|
+
serviceNetworks: cluster.serviceNetworks || getDefaultServiceNetworks(),
|
|
70
92
|
};
|
|
71
93
|
};
|
|
72
94
|
|
|
@@ -87,7 +109,12 @@ export const getNetworkConfigurationValidationSchema = (
|
|
|
87
109
|
: machineNetworksValidationSchema.when('stackType', {
|
|
88
110
|
is: (stackType: NetworkConfigurationValues['stackType']) =>
|
|
89
111
|
stackType === SINGLE_STACK,
|
|
90
|
-
then: () =>
|
|
112
|
+
then: () => {
|
|
113
|
+
if (isPrimaryIPv6(values.machineNetworks)) {
|
|
114
|
+
return machineNetworksValidationSchema.concat(IPv6ValidationSchema);
|
|
115
|
+
}
|
|
116
|
+
return machineNetworksValidationSchema.concat(IPv4ValidationSchema);
|
|
117
|
+
},
|
|
91
118
|
otherwise: () =>
|
|
92
119
|
values.machineNetworks && values.machineNetworks?.length >= 2
|
|
93
120
|
? machineNetworksValidationSchema.concat(
|
|
@@ -97,13 +124,23 @@ export const getNetworkConfigurationValidationSchema = (
|
|
|
97
124
|
}),
|
|
98
125
|
clusterNetworks: clusterNetworksValidationSchema(t).when('stackType', {
|
|
99
126
|
is: (stackType: NetworkConfigurationValues['stackType']) => stackType === SINGLE_STACK,
|
|
100
|
-
then: (schema) =>
|
|
127
|
+
then: (schema) => {
|
|
128
|
+
if (isPrimaryIPv6(values.machineNetworks)) {
|
|
129
|
+
return schema.concat(IPv6ValidationSchema);
|
|
130
|
+
}
|
|
131
|
+
return schema.concat(IPv4ValidationSchema);
|
|
132
|
+
},
|
|
101
133
|
otherwise: (schema) =>
|
|
102
134
|
schema.concat(dualStackValidationSchema('cluster network', t, openshiftVersion)),
|
|
103
135
|
}),
|
|
104
136
|
serviceNetworks: serviceNetworkValidationSchema(t).when('stackType', {
|
|
105
137
|
is: (stackType: NetworkConfigurationValues['stackType']) => stackType === SINGLE_STACK,
|
|
106
|
-
then: (schema) =>
|
|
138
|
+
then: (schema) => {
|
|
139
|
+
if (isPrimaryIPv6(values.machineNetworks)) {
|
|
140
|
+
return schema.concat(IPv6ValidationSchema);
|
|
141
|
+
}
|
|
142
|
+
return schema.concat(IPv4ValidationSchema);
|
|
143
|
+
},
|
|
107
144
|
otherwise: (schema) =>
|
|
108
145
|
schema.concat(dualStackValidationSchema('service network', t, openshiftVersion)),
|
|
109
146
|
}),
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
useTranslation,
|
|
9
9
|
} from '../../../../common';
|
|
10
10
|
import { getManagementType, getStackTypeLabel } from './utils';
|
|
11
|
+
import { useFeature } from '../../../hooks/use-feature';
|
|
11
12
|
import { Cluster } from '@openshift-assisted/types/assisted-installer-service';
|
|
12
13
|
|
|
13
14
|
type ReviewTableRowsType = {
|
|
@@ -17,6 +18,7 @@ type ReviewTableRowsType = {
|
|
|
17
18
|
|
|
18
19
|
export const ReviewNetworkingTable = ({ cluster }: { cluster: Cluster }) => {
|
|
19
20
|
const { t } = useTranslation();
|
|
21
|
+
const isSingleClusterFeature = useFeature('ASSISTED_INSTALLER_SINGLE_CLUSTER_FEATURE');
|
|
20
22
|
const rows = React.useMemo(() => {
|
|
21
23
|
const networkRows = [
|
|
22
24
|
{
|
|
@@ -34,7 +36,7 @@ export const ReviewNetworkingTable = ({ cluster }: { cluster: Cluster }) => {
|
|
|
34
36
|
cells: [
|
|
35
37
|
{ title: 'Stack type', colSpan: 2 },
|
|
36
38
|
{
|
|
37
|
-
title: getStackTypeLabel(cluster),
|
|
39
|
+
title: getStackTypeLabel(cluster, isSingleClusterFeature),
|
|
38
40
|
props: { 'data-testid': 'stack-type', colSpan: 2 },
|
|
39
41
|
},
|
|
40
42
|
],
|
|
@@ -125,7 +127,7 @@ export const ReviewNetworkingTable = ({ cluster }: { cluster: Cluster }) => {
|
|
|
125
127
|
});
|
|
126
128
|
|
|
127
129
|
return networkRows;
|
|
128
|
-
}, [cluster]);
|
|
130
|
+
}, [cluster, isSingleClusterFeature]);
|
|
129
131
|
|
|
130
132
|
const rowsAdvanced = React.useMemo(() => {
|
|
131
133
|
return [
|
|
@@ -169,6 +169,47 @@ describe('getStackTypeLabel', () => {
|
|
|
169
169
|
});
|
|
170
170
|
});
|
|
171
171
|
|
|
172
|
+
describe('with isSingleClusterFeature=true', () => {
|
|
173
|
+
test('returns "Single stack" for IPv4 single-stack cluster', () => {
|
|
174
|
+
const cluster = createCluster({
|
|
175
|
+
machineNetworks: [createMachineNetwork('192.168.1.0/24')],
|
|
176
|
+
clusterNetworks: [createClusterNetwork('10.128.0.0/14', 23)],
|
|
177
|
+
serviceNetworks: [createServiceNetwork('172.30.0.0/16')],
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
expect(getStackTypeLabel(cluster, true)).toBe('Single stack');
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test('returns "Single stack" for IPv6 single-stack cluster', () => {
|
|
184
|
+
const cluster = createCluster({
|
|
185
|
+
machineNetworks: [createMachineNetwork('2001:db8::/64')],
|
|
186
|
+
clusterNetworks: [createClusterNetwork('fd01::/48', 64)],
|
|
187
|
+
serviceNetworks: [createServiceNetwork('fd02::/112')],
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
expect(getStackTypeLabel(cluster, true)).toBe('Single stack');
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
test('still returns "Dual-stack" for dual-stack cluster', () => {
|
|
194
|
+
const cluster = createCluster({
|
|
195
|
+
machineNetworks: [
|
|
196
|
+
createMachineNetwork('192.168.1.0/24'),
|
|
197
|
+
createMachineNetwork('2001:db8::/64'),
|
|
198
|
+
],
|
|
199
|
+
clusterNetworks: [
|
|
200
|
+
createClusterNetwork('10.128.0.0/14', 23),
|
|
201
|
+
createClusterNetwork('fd01::/48', 64),
|
|
202
|
+
],
|
|
203
|
+
serviceNetworks: [
|
|
204
|
+
createServiceNetwork('172.30.0.0/16'),
|
|
205
|
+
createServiceNetwork('fd02::/112'),
|
|
206
|
+
],
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
expect(getStackTypeLabel(cluster, true)).toBe('Dual-stack');
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
|
|
172
213
|
describe('edge cases', () => {
|
|
173
214
|
test('handles undefined openshiftVersion', () => {
|
|
174
215
|
const cluster = createCluster({
|