diff --git a/libs/ui-lib/lib/cim/components/ClusterDeployment/ClusterDeploymentNetworkingStep.tsx b/libs/ui-lib/lib/cim/components/ClusterDeployment/ClusterDeploymentNetworkingStep.tsx index 59516781ed..4e676d3985 100644 --- a/libs/ui-lib/lib/cim/components/ClusterDeployment/ClusterDeploymentNetworkingStep.tsx +++ b/libs/ui-lib/lib/cim/components/ClusterDeployment/ClusterDeploymentNetworkingStep.tsx @@ -88,7 +88,7 @@ const NetworkingForm: React.FC = ({ React.useEffect(() => { setNextRequested(false); setShowClusterErrors(false); - }, [values.apiVip, values.ingressVip]); + }, [values.apiVips, values.ingressVips]); React.useEffect(() => { if (nextRequested) { diff --git a/libs/ui-lib/lib/cim/components/ClusterDeployment/NetworkConfiguration.tsx b/libs/ui-lib/lib/cim/components/ClusterDeployment/NetworkConfiguration.tsx index 4e1f3d85aa..d295c2be43 100644 --- a/libs/ui-lib/lib/cim/components/ClusterDeployment/NetworkConfiguration.tsx +++ b/libs/ui-lib/lib/cim/components/ClusterDeployment/NetworkConfiguration.tsx @@ -97,12 +97,12 @@ const NetworkConfiguration = ({ // We need to reset these fields' values in order to align with the values the server sends setFieldValue('vipDhcpAllocation', false); - setFieldValue('ingressVip', '', shouldValidate); - setFieldValue('apiVip', '', shouldValidate); + setFieldValue('ingressVips', [], shouldValidate); + setFieldValue('apiVips', [], shouldValidate); } else { - if (!values.vipDhcpAllocation && touched.hostSubnet) { - validateField('ingressVip'); - validateField('apiVip'); + if (!values.vipDhcpAllocation) { + validateField('ingressVips'); + validateField('apiVips'); } } }, [ diff --git a/libs/ui-lib/lib/cim/components/ClusterDeployment/networkConfigurationValidation.ts b/libs/ui-lib/lib/cim/components/ClusterDeployment/networkConfigurationValidation.ts index 75e4630c44..de3af51d63 100644 --- a/libs/ui-lib/lib/cim/components/ClusterDeployment/networkConfigurationValidation.ts +++ b/libs/ui-lib/lib/cim/components/ClusterDeployment/networkConfigurationValidation.ts @@ -1,17 +1,8 @@ -import * as Yup from 'yup'; import { Cluster, ClusterDefaultConfig, } from '@openshift-assisted/types/assisted-installer-service'; -import { HostSubnets, NetworkConfigurationValues } from '../../../common/types/clusters'; -import { - hostPrefixValidationSchema, - hostSubnetValidationSchema, - ipBlockValidationSchema, - sshPublicKeyValidationSchema, - vipValidationSchema, -} from '../../../common/components/ui'; - +import { NetworkConfigurationValues } from '../../../common/types/clusters'; import { getSubnetFromMachineNetworkCidr, getHostSubnets, @@ -63,19 +54,3 @@ export const getNetworkInitialValues = ( networkType: cluster.networkType || NETWORK_TYPE_OVN, }; }; - -export const getNetworkConfigurationValidationSchema = ( - initialValues: NetworkConfigurationValues, - hostSubnets: HostSubnets, -) => - Yup.lazy((values: NetworkConfigurationValues) => - Yup.object().shape({ - clusterNetworkHostPrefix: hostPrefixValidationSchema(values.clusterNetworkCidr), - clusterNetworkCidr: ipBlockValidationSchema(values.serviceNetworkCidr), - serviceNetworkCidr: ipBlockValidationSchema(values.clusterNetworkCidr), - apiVip: vipValidationSchema(hostSubnets, values, initialValues.apiVip), - ingressVip: vipValidationSchema(hostSubnets, values, initialValues.ingressVip), - sshPublicKey: sshPublicKeyValidationSchema, - hostSubnet: hostSubnetValidationSchema, - }), - ); diff --git a/libs/ui-lib/lib/cim/components/ClusterDeployment/use-networking-formik.ts b/libs/ui-lib/lib/cim/components/ClusterDeployment/use-networking-formik.ts index bca87f8cc8..e3d778d337 100644 --- a/libs/ui-lib/lib/cim/components/ClusterDeployment/use-networking-formik.ts +++ b/libs/ui-lib/lib/cim/components/ClusterDeployment/use-networking-formik.ts @@ -17,7 +17,7 @@ import { HostSubnets, hostPrefixValidationSchema, ipBlockValidationSchema, - vipValidationSchema, + vipArrayValidationSchema, sshPublicKeyValidationSchema, hostSubnetValidationSchema, httpProxyValidationSchema, @@ -50,8 +50,8 @@ const getNetworkConfigurationValidationSchema = ( clusterNetworkHostPrefix: hostPrefixValidationSchema(values.clusterNetworkCidr), clusterNetworkCidr: ipBlockValidationSchema(values.serviceNetworkCidr), serviceNetworkCidr: ipBlockValidationSchema(values.clusterNetworkCidr), - apiVip: vipValidationSchema(hostSubnets, values, initialValues.apiVip), - ingressVip: vipValidationSchema(hostSubnets, values, initialValues.ingressVip), + apiVips: vipArrayValidationSchema(hostSubnets, values, initialValues.apiVips), + ingressVips: vipArrayValidationSchema(hostSubnets, values, initialValues.ingressVips), sshPublicKey: sshPublicKeyValidationSchema, hostSubnet: hostSubnetValidationSchema, httpProxy: httpProxyValidationSchema({ values, pairValueName: 'httpsProxy' }), diff --git a/libs/ui-lib/lib/cim/components/helpers/toAssisted.ts b/libs/ui-lib/lib/cim/components/helpers/toAssisted.ts index 352a0435ce..462f5a865d 100644 --- a/libs/ui-lib/lib/cim/components/helpers/toAssisted.ts +++ b/libs/ui-lib/lib/cim/components/helpers/toAssisted.ts @@ -140,14 +140,18 @@ export const getAICluster = ({ name: clusterDeployment.spec?.clusterName, baseDnsDomain: clusterDeployment.spec?.baseDomain, openshiftVersion: installVersion, - apiVips: [ - { - ip: agentClusterInstall?.status?.apiVIP || agentClusterInstall?.spec?.apiVIP, - }, - ], - ingressVips: [ - { ip: agentClusterInstall?.status?.ingressVIP || agentClusterInstall?.spec?.apiVIP }, - ], + apiVips: + agentClusterInstall?.status?.apiVIP || agentClusterInstall?.spec?.apiVIP + ? [ + { + ip: agentClusterInstall?.status?.apiVIP || agentClusterInstall?.spec?.apiVIP, + }, + ] + : [], + ingressVips: + agentClusterInstall?.status?.ingressVIP || agentClusterInstall?.spec?.ingressVIP + ? [{ ip: agentClusterInstall?.status?.ingressVIP || agentClusterInstall?.spec?.ingressVIP }] + : [], highAvailabilityMode: agentClusterInstall?.spec?.provisionRequirements?.controlPlaneAgents === 1 ? 'None' : 'Full', status, diff --git a/libs/ui-lib/lib/common/components/clusterWizard/networkingSteps/AvailableSubnetsControl.tsx b/libs/ui-lib/lib/common/components/clusterWizard/networkingSteps/AvailableSubnetsControl.tsx index cf25dee415..777e7a06de 100644 --- a/libs/ui-lib/lib/common/components/clusterWizard/networkingSteps/AvailableSubnetsControl.tsx +++ b/libs/ui-lib/lib/common/components/clusterWizard/networkingSteps/AvailableSubnetsControl.tsx @@ -1,68 +1,11 @@ import React from 'react'; import { Alert, AlertActionLink, AlertVariant, Popover } from '@patternfly/react-core'; -import { HostSubnet, HostSubnets } from '../../../types/clusters'; -import { Cluster, Host } from '@openshift-assisted/types/assisted-installer-service'; +import { HostSubnets } from '../../../types/clusters'; +import { Host } from '@openshift-assisted/types/assisted-installer-service'; import { SelectField } from '../../ui'; import { NO_SUBNET_SET } from '../../../config'; import { useTranslation } from '../../../hooks/use-translation-wrapper'; -interface SubnetHelperTextProps { - matchingSubnet: HostSubnet; - hosts: Cluster['hosts']; -} - -const SubnetHelperText = ({ matchingSubnet, hosts }: SubnetHelperTextProps) => { - const { t } = useTranslation(); - const excludedHosts = - hosts?.filter( - (host) => - !['disabled', 'disconnected'].includes(host.status) && - !matchingSubnet.hostIDs.includes(host.requestedHostname || ''), - ) || []; - - // Workaround for bug in CIM backend. hostIDs are empty - if (excludedHosts.length === 0 || !matchingSubnet.hostIDs.length) { - return null; - } - - const actionLinks = ( - - {excludedHosts - .sort( - (hostA, hostB) => - hostA.requestedHostname?.localeCompare(hostB.requestedHostname || '') || 0, - ) - .map((host) => ( -
  • {host.requestedHostname || host.id}
  • - ))} - - } - minWidth="30rem" - maxWidth="50rem" - > - - {t('ai:View {{count}} affected host', { - count: excludedHosts.length, - })} - -
    - ); - - return ( - - {t('ai:Hosts outside of this range will not be included in the new cluster.')} - - ); -}; - export interface AvailableSubnetsControlProps { hostSubnets: HostSubnets; hosts: Host[]; @@ -79,14 +22,60 @@ export const AvailableSubnetsControl = ({ const { t } = useTranslation(); const getHelperText = (value: string) => { const matchingSubnet = hostSubnets.find((hn) => hn.subnet === value); - if (matchingSubnet) { + if (matchingSubnet && isMultiNodeCluster) { + const excludedHosts = + hosts?.filter( + (host) => + !['disabled', 'disconnected'].includes(host.status) && + !matchingSubnet.hostIDs.includes(host.requestedHostname || ''), + ) || []; + + // Workaround for bug in CIM backend. hostIDs are empty + if (excludedHosts.length === 0 || !matchingSubnet.hostIDs.length) { + return undefined; + } + + const actionLinks = ( + + {excludedHosts + .sort( + (hostA, hostB) => + hostA.requestedHostname?.localeCompare(hostB.requestedHostname || '') || 0, + ) + .map((host) => ( +
  • {host.requestedHostname || host.id}
  • + ))} + + } + minWidth="30rem" + maxWidth="50rem" + > + + {t('ai:View {{count}} affected host', { + count: excludedHosts.length, + })} + +
    + ); + return ( - isMultiNodeCluster && + + {t('ai:Hosts outside of this range will not be included in the new cluster.')} + ); } return undefined; }; + const hostSubnetLength = hostSubnets.length; return ( >( values: NetworkConfigurationValues, initialValues?: ApiVip[] | IngressVip[], ) => - (values.apiVips?.length && values.managedNetworkingType === 'clusterManaged' + (values.managedNetworkingType === 'clusterManaged' ? Yup.array().of( Yup.object({ clusterId: Yup.string(),