Skip to content

Commit abc637d

Browse files
committed
Static IP form for BMC host discovery
1 parent 51b1446 commit abc637d

25 files changed

+847
-527
lines changed

libs/locales/lib/en/translation.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
"ai:An error occured": "An error occured.",
8686
"ai:An error occured while approving agents": "An error occured while approving agents.",
8787
"ai:An error occured while starting installation.": "An error occured while starting installation.",
88+
"ai:An IP address to where any IP packet should be forwarded in case there is no other routing rule configured for a destination IP.": "An IP address to where any IP packet should be forwarded in case there is no other routing rule configured for a destination IP.",
8889
"ai:And verify that this is the output:": "And verify the following output:",
8990
"ai:API connectivity failure": "API connectivity failure",
9091
"ai:API domain name resolution": "API domain name resolution",
@@ -200,6 +201,7 @@
200201
"ai:Configure host inventory settings": "Configure host inventory settings",
201202
"ai:Configure load balancer on Amazon Web Services for me.": "Configure load balancer on Amazon Web Services for me.",
202203
"ai:Configure the SSH key and proxy settings after the modal appears (optional).": "Configure the SSH key and proxy settings after the modal appears (optional).",
204+
"ai:Configure via": "Configure via",
203205
"ai:Configure your own NTP sources to sychronize the time between the hosts that will be added to this infrastructure environment.": "Configure your own NTP sources to sychronize the time between the hosts that will be added to this infrastructure environment.",
204206
"ai:Configure your own NTP sources to synchronize the time between the hosts that will be added to this infrastructure environment.": "Configure your own NTP sources to synchronize the time between the hosts that will be added to this infrastructure environment.",
205207
"ai:Configuring the host inventory settings will enable the Central Infrastructure Management.": "Configuring the host inventory settings will enable the Central Infrastructure Management.",
@@ -235,6 +237,7 @@
235237
"ai:Created at": "Created at",
236238
"ai:Currently, adding additional machines to your cluster is not supported.": "Currently, adding additional machines to your cluster is not supported.",
237239
"ai:Database storage": "Database storage",
240+
"ai:Default gateway": "Default gateway",
238241
"ai:Default route to host": "Default route to host",
239242
"ai:Define the quantity of worker nodes and nodepools to create for your cluster. Additional worker nodes and nodepools can be added after the cluster is created.": "Define the quantity of worker nodes and nodepools to create for your cluster. Additional worker nodes and nodepools can be added after the cluster is created.",
240243
"ai:Deleted hosts": "Deleted hosts",
@@ -283,6 +286,7 @@
283286
"ai:Draft": "Draft",
284287
"ai:Drag a file here or browse to upload": "Drag a file here or browse to upload",
285288
"ai:Drive type": "Drive type",
289+
"ai:Dual-stack": "Dual-stack",
286290
"ai:Edit BMC": "Edit BMC",
287291
"ai:Edit BMH": "Edit BMH",
288292
"ai:Edit BMH dialog": "Edit BMH dialog",
@@ -348,6 +352,7 @@
348352
"ai:Finalizing": "Finalizing",
349353
"ai:Find by hostname": "Find by hostname",
350354
"ai:For example: host-{{n}}": "For example: host-{{n}}",
355+
"ai:Form view": "Form view",
351356
"ai:Format?": "Format?",
352357
"ai:Forwarding it could put your credentials and personal data at risk.": "Forwarding it might put your credentials and personal data at risk.",
353358
"ai:Full image file": "Full image file",
@@ -419,6 +424,7 @@
419424
"ai:If not, please start your VMs with the following configuration:": "If not, start your VMs with the following configuration:",
420425
"ai:If the cluster hosts are in a network with a re-encrypting (MITM) proxy or the cluster needs to trust certificates for other purposes (e.g. container image registries).": "If the cluster hosts are in a network with a re-encrypting (MITM) proxy or the cluster needs to trust certificates for other purposes (e.g. container image registries).",
421426
"ai:If the configuration is taking longer than 5 minutes, you might need to troubleshoot.": "If the configuration is taking longer than 5 minutes, you might need to troubleshoot.",
427+
"ai:If the hosts are in a sub network, enter the VLAN ID.": "If the hosts are in a sub network, enter the VLAN ID.",
422428
"ai:If there are many clusters, use higher values for the storage fields.": "If there are many clusters, use higher values for the storage fields.",
423429
"ai:If you prefer using the CLI, follow the instructions in": "If you prefer using the CLI, follow the instructions in",
424430
"ai:If you used DHCP networking, verify that your DHCP server is enabled": "If you used DHCP networking, verify that your DHCP server is enabled",
@@ -462,7 +468,9 @@
462468
"ai:Insufficient": "Insufficient",
463469
"ai:IP address block from which Pod IPs are allocated This block must not overlap with existing physical networks. These IP addresses are used for the Pod network, and if you need to access the Pods from an external network, configure load balancers and routers to manage the traffic.": "IP address block from which Pod IPs are allocated. This block must not overlap with existing physical networks. These IP addresses are used for the Pod network, and if you need to access the Pods from an external network, configure load balancers and routers to manage the traffic.",
464470
"ai:IP allocation from the DHCP server timed out.": "IP allocation from the DHCP server timed out.",
471+
"ai:IPv4": "IPv4",
465472
"ai:IPv4 address": "IPv4 address",
473+
"ai:IPv6": "IPv6",
466474
"ai:IPv6 address": "IPv6 address",
467475
"ai:iPXE script file is ready to be downloaded": "iPXE script file is ready to be downloaded",
468476
"ai:iPXE script file URL": "iPXE script file URL",
@@ -562,6 +570,7 @@
562570
"ai:Network type": "Network type",
563571
"ai:Network type selection is not supported for SNO clusters or when IPv6 is detected.": "Network type selection is not supported for SNO clusters or when IPv6 is detected.",
564572
"ai:Networking": "Networking",
573+
"ai:Networking stack type": "Networking stack type",
565574
"ai:Networks same address families": "Networks same address families",
566575
"ai:Never share your downloaded ISO with anyone else.": "Never share your downloaded ISO with anyone else.",
567576
"ai:New hostname": "New hostname",
@@ -889,6 +898,7 @@
889898
"ai:Use lowercase alphanumeric characters or hyphen (-)": "Use lowercase alphanumeric characters or hyphen (-)",
890899
"ai:Use lowercase alphanumeric characters, dot (.) or hyphen (-)": "Use lowercase alphanumeric characters, dot (.) or hyphen (-)",
891900
"ai:Use the same host discovery SSH key": "Use the same host discovery SSH key",
901+
"ai:Use VLAN": "Use VLAN",
892902
"ai:Use when you have an iPXE server that has already been set up": "Use when you have an iPXE server that has already been set up",
893903
"ai:useAlerts must be used within AlertsContextProvider": "useAlerts must be used within AlertsContextProvider",
894904
"ai:Used to describe hosts' physical location. Helps for quicker host selection during cluster creation.": "Used to describe hosts' physical location. Helps for quicker host selection during cluster creation.",
@@ -911,6 +921,7 @@
911921
"ai:View host events": "View host events",
912922
"ai:VIP IP allocation from DHCP server has been timed out": "VIP IP allocation from DHCP server has timed out",
913923
"ai:Virtual machine": "Virtual machine",
924+
"ai:VLAN ID": "VLAN ID",
914925
"ai:Vsphere disk uuid enabled": "Vsphere disk uuid enabled",
915926
"ai:Waiting for host...": "Waiting for host...",
916927
"ai:Waiting for host..._plural": "Waiting for hosts...",
@@ -929,6 +940,7 @@
929940
"ai:Workers: At least {{worker_cpu_cores}} CPU cores, {{worker_ram}} RAM, {{worker_disksize}} GB disk size for each worker ": "Workers: At least {{worker_cpu_cores}} CPU cores, {{worker_ram}} RAM, {{worker_disksize}} GB disk size for each worker ",
930941
"ai:World Wide Name (WWN) is a unique disk identifier.": "World Wide Name (WWN) is a unique disk identifier.",
931942
"ai:x86_64": "x86_64",
943+
"ai:Yaml view": "Yaml view",
932944
"ai:You are approving multiple hosts. All hosts listed below will be approved to join the infrastructure environment if you continue. Make sure that you expect and recognize the hosts before approving.": "You are approving multiple hosts. All hosts listed will be approved to join the infrastructure environment, if you continue. Make sure that you expect and recognize the hosts before approving.",
933945
"ai:You can either wait or investigate. A common issue can be misconfigured storage. Once you fix the issue, you can delete AgentServiceConfig to try again.": "You can either wait or investigate. A common issue can be misconfigured storage. After you fix the issue, delete AgentServiceConfig and try again.",
934946
"ai:You can upload additional trusted certificates in PEM-encoded X.509 format if the cluster hosts are in a network with a re-encrypting (MITM) proxy or the cluster needs to trust certificates for other purposes (for example, container image registries).": "You can upload additional trusted certificates in PEM-encoded X.509 format if the cluster hosts are in a network with a re-encrypting (MITM) proxy or the cluster needs to trust certificates for other purposes (for example, container image registries).",

libs/ui-lib/lib/cim/components/Agent/BMCForm/BMCForm.tsx

Lines changed: 67 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,82 @@ import { Formik, FormikProps, FormikConfig } from 'formik';
1515

1616
import {
1717
InputField,
18-
CodeField,
1918
getRichTextValidation,
2019
RichInputField,
2120
BMCValidationMessages,
21+
StaticIpView,
2222
} from '../../../../common';
23-
import { Language } from '@patternfly/react-code-editor';
2423
import { InfraEnvK8sResource, NMStateK8sResource } from '../../../types';
2524
import { AddBmcValues, BMCFormProps } from '../types';
2625
import { AGENT_BMH_NAME_LABEL_KEY, INFRAENV_AGENTINSTALL_LABEL_KEY } from '../../common';
2726
import { getErrorMessage } from '../../../../common/utils';
2827
import { useTranslation } from '../../../../common/hooks/use-translation-wrapper';
29-
import { MacMapping } from './MacMapping';
3028
import { getInitValues, getValidationSchema } from './validationSchemas';
3129
import ProvisioningConfigErrorAlert from '../../modals/ProvisioningConfigErrorAlert';
30+
import { NMStateConfig } from './NMstateConfig';
3231

3332
const getNMState = (values: AddBmcValues, infraEnv: InfraEnvK8sResource): NMStateK8sResource => {
34-
const config = yaml.load(values.nmState);
33+
let config;
34+
if (values.staticIPView === StaticIpView.YAML) {
35+
config = yaml.load(values.nmState);
36+
} else {
37+
config = {
38+
interfaces: [
39+
{
40+
name: values.macMapping[0].name,
41+
type: values.useVlan ? 'vlan' : 'ethernet',
42+
state: 'up',
43+
vlan: values.useVlan
44+
? {
45+
'base-iface': 'eth0',
46+
id: values.vlanId,
47+
}
48+
: undefined,
49+
ipv4: {
50+
address: [
51+
{
52+
ip: values.ipConfigs.ipv4.machineNetwork.ip,
53+
'prefix-length': values.ipConfigs.ipv4.machineNetwork.prefixLength,
54+
},
55+
],
56+
enabled: true,
57+
dhcp: false,
58+
},
59+
ipv6:
60+
values.protocolType === 'dualStack'
61+
? {
62+
address: [
63+
{
64+
ip: values.ipConfigs.ipv6.machineNetwork.ip,
65+
'prefix-length': values.ipConfigs.ipv6.machineNetwork.prefixLength,
66+
},
67+
],
68+
enabled: true,
69+
dhcp: false,
70+
}
71+
: undefined,
72+
},
73+
],
74+
'dns-resolver': { config: { server: [values.dns] } },
75+
routes: {
76+
config: [
77+
{
78+
destination: '0.0.0.0/0',
79+
'next-hop-address': values.ipConfigs.ipv4.gateway,
80+
'next-hop-interface':
81+
values.useVlan && values.vlanId ? `eth0.${values.vlanId}` : 'eth0',
82+
},
83+
values.protocolType === 'dualStack' && {
84+
destination: '::/0',
85+
'next-hop-address': values.ipConfigs.ipv6.gateway,
86+
'next-hop-interface':
87+
values.useVlan && values.vlanId ? `eth0.${values.vlanId}` : 'eth0',
88+
},
89+
].filter(Boolean),
90+
},
91+
};
92+
}
93+
3594
const nmState = {
3695
apiVersion: 'agent-install.openshift.io/v1beta1',
3796
kind: 'NMStateConfig',
@@ -41,15 +100,16 @@ const getNMState = (values: AddBmcValues, infraEnv: InfraEnvK8sResource): NMStat
41100
labels: {
42101
[AGENT_BMH_NAME_LABEL_KEY]: values.name,
43102
[INFRAENV_AGENTINSTALL_LABEL_KEY]: infraEnv?.metadata?.name || '',
103+
'configured-via': values.staticIPView,
44104
},
45105
},
46106
spec: {
47-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
48107
config,
49108
interfaces: values.macMapping.filter((m) => m.macAddress.length && m.name.length),
50109
},
51110
};
52-
return nmState;
111+
112+
return nmState as NMStateK8sResource;
53113
};
54114

55115
const BMCForm: React.FC<BMCFormProps> = ({
@@ -144,19 +204,7 @@ const BMCForm: React.FC<BMCFormProps> = ({
144204
placeholder={t('ai:Enter a password for the BMC')}
145205
isRequired
146206
/>
147-
{!hasDHCP && (
148-
<>
149-
<CodeField
150-
label={t('ai:NMState')}
151-
name="nmState"
152-
language={Language.yaml}
153-
description={t(
154-
'ai:Upload a YAML file in NMstate format (not the entire NMstate config CR) that includes your network configuration (static IPs, bonds, etc.).',
155-
)}
156-
/>
157-
<MacMapping />
158-
</>
159-
)}
207+
{!hasDHCP && <NMStateConfig />}
160208
</Form>
161209
{error && (
162210
<Alert

libs/ui-lib/lib/cim/components/Agent/BMCForm/MacMapping.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ import { getFieldId, InputField, useTranslation } from '../../../../common';
44
import { Button, FormGroup, Grid, GridItem, Text, TextVariants } from '@patternfly/react-core';
55
import PlusCircleIcon from '@patternfly/react-icons/dist/js/icons/plus-circle-icon';
66
import MinusCircleIcon from '@patternfly/react-icons/dist/js/icons/minus-circle-icon';
7+
import { AddBmcValues } from '../types';
78

89
type MacMappingFieldProps = { macAddress: string; name: string }[];
910

10-
const getFieldError = (errors: FormikErrors<MacMappingFieldProps>, fieldName: string): string => {
11+
const getFieldError = (errors: FormikErrors<AddBmcValues>, fieldName: string): string => {
1112
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
1213
// @ts-ignore
1314
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
@@ -18,7 +19,7 @@ export const MacMapping = () => {
1819
const [field] = useField<MacMappingFieldProps>({
1920
name: 'macMapping',
2021
});
21-
const { errors } = useFormikContext<MacMappingFieldProps>();
22+
const { errors } = useFormikContext<AddBmcValues>();
2223
const fieldId = getFieldId('macMapping', 'input');
2324
const { t } = useTranslation();
2425

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import React from 'react';
2+
import { useFormikContext } from 'formik';
3+
import { Language } from '@patternfly/react-code-editor';
4+
import { FormGroup } from '@patternfly/react-core';
5+
6+
import {
7+
CheckboxField,
8+
CodeField,
9+
InputField,
10+
IpConfigFields,
11+
MAX_VLAN_ID,
12+
MIN_VLAN_ID,
13+
PopoverIcon,
14+
ProtocolVersion,
15+
RadioField,
16+
StaticIpView,
17+
useTranslation,
18+
} from '../../../../common';
19+
import { AddBmcValues } from '../types';
20+
import { MacMapping } from './MacMapping';
21+
22+
export const NMStateConfig = () => {
23+
const { t } = useTranslation();
24+
const { values, setFieldValue } = useFormikContext<AddBmcValues>();
25+
26+
return (
27+
<>
28+
<FormGroup label={t('ai:Configure via')} name="staticIPView" isInline isRequired>
29+
<RadioField name={'staticIPView'} value={StaticIpView.FORM} label={t('ai:Form view')} />
30+
<RadioField name={'staticIPView'} value={StaticIpView.YAML} label={t('ai:Yaml view')} />
31+
</FormGroup>
32+
33+
{values.staticIPView === StaticIpView.FORM ? (
34+
<>
35+
<FormGroup label={t('ai:Networking stack type')} isInline isRequired>
36+
<RadioField name={'protocolType'} value={'ipv4'} label={t('ai:IPv4')} />
37+
<RadioField name={'protocolType'} value={'dualStack'} label={t('ai:Dual-stack')} />
38+
</FormGroup>
39+
40+
<CheckboxField
41+
name={'useVlan'}
42+
label={
43+
<>
44+
{t('ai:Use VLAN')}{' '}
45+
<PopoverIcon
46+
bodyContent={t('ai:If the hosts are in a sub network, enter the VLAN ID.')}
47+
noVerticalAlign
48+
/>
49+
</>
50+
}
51+
onChange={() => setFieldValue('vlanId', '')}
52+
/>
53+
54+
{values.useVlan === true && (
55+
<div className="pf-v5-u-ml-md">
56+
<InputField
57+
name={'vlanId'}
58+
label={t('ai:VLAN ID')}
59+
min={MIN_VLAN_ID}
60+
max={MAX_VLAN_ID}
61+
/>
62+
</div>
63+
)}
64+
65+
<InputField name={'dns'} label={t('ai:DNS')} />
66+
67+
{values.protocolType === 'ipv4' ? (
68+
<IpConfigFields
69+
fieldName={`ipConfigs.${ProtocolVersion.ipv4}`}
70+
protocolVersion={ProtocolVersion.ipv4}
71+
/>
72+
) : (
73+
<>
74+
<IpConfigFields
75+
fieldName={`ipConfigs.${ProtocolVersion.ipv4}`}
76+
protocolVersion={ProtocolVersion.ipv4}
77+
/>
78+
<IpConfigFields
79+
fieldName={`ipConfigs.${ProtocolVersion.ipv6}`}
80+
protocolVersion={ProtocolVersion.ipv6}
81+
/>
82+
</>
83+
)}
84+
</>
85+
) : (
86+
<CodeField
87+
label={t('ai:NMState')}
88+
name="nmState"
89+
language={Language.yaml}
90+
description={t(
91+
'ai:Upload a YAML file in NMstate format (not the entire NMstate config CR) that includes your network configuration (static IPs, bonds, etc.).',
92+
)}
93+
/>
94+
)}
95+
<MacMapping />
96+
</>
97+
);
98+
};

0 commit comments

Comments
 (0)