bmh_clean_host:
pushd $(BMDIR) && ./06_host_cleanup.sh && popd
-dhcp_start:
- pushd $(BMDIR) && ./03_launch_prereq.sh --dhcp-start && popd
-
-dhcp_reset:
- pushd $(BMDIR) && ./03_launch_prereq.sh --dhcp-reset && popd
-
clean_packages:
pushd $(BOOTLOADER_ENV) && \
./02_clean_bootloader_package_req.sh --only-packages && popd
bm_verifer: package_prerequisite \
kud_bm_deploy_mini \
bmh_all \
- dhcp_start \
bpa_op_bmh_verifier \
bpa_rest_api_verifier \
- dhcp_reset \
clean_all
verify_all: prerequisite \
(Tested as below)
Hostname | CPU Model | Memory | Storage | 1GbE: NIC#, VLAN, (Connected extreme 480 switch) | 10GbE: NIC# VLAN, Network (Connected with IZ1 switch)
---------|-----------|--------|---------|--------------------------------------------------|------------------------------------------------------
-jump0 | Intel 2xE5-2699 | 64GB | 3TB (Sata)<br/>180 (SSD) | eth0: VLAN 110<br/>eno1: VLAN 110<br/>eno2: VLAN 111 | eno3: VLAN 112
+jump0 | Intel 2xE5-2699 | 64GB | 3TB (Sata)<br/>180 (SSD) | eth0: VLAN 110<br/>eno1: VLAN 110<br/>eno2: VLAN 111 |
#### Jump Server Software Requirements
ICN supports Ubuntu 18.04. The ICN blueprint installs all required
(Tested as below)
Hostname | CPU Model | Memory | Storage | 1GbE: NIC#, VLAN, (Connected extreme 480 switch) | 10GbE: NIC# VLAN, Network (Connected with IZ1 switch)
---------|-----------|--------|---------|--------------------------------------------------|------------------------------------------------------
-node1 | Intel 2xE5-2699 | 64GB | 3TB (Sata)<br/>180 (SSD) | eth0: VLAN 110<br/>eno1: VLAN 110<br/>eno2: VLAN 111 | eno3: VLAN 112<br/>eno4: VLAN 113
-node2 | Intel 2xE5-2699 | 64GB | 3TB (Sata)<br/>180 (SSD) | eth0: VLAN 110<br/>eno1: VLAN 110<br/>eno2: VLAN 111 | eno3: VLAN 112<br/>eno4: VLAN 113
-node3 | Intel 2xE5-2699 | 64GB | 3TB (Sata)<br/>180 (SSD) | eth0: VLAN 110<br/>eno1: VLAN 110<br/>eno2: VLAN 111 | eno3: VLAN 112<br/>eno4: VLAN 113
+node1 | Intel 2xE5-2699 | 64GB | 3TB (Sata)<br/>180 (SSD) | eth0: VLAN 110<br/>eno1: VLAN 110<br/>eno2: VLAN 111 | eno3: VLAN 113
+node2 | Intel 2xE5-2699 | 64GB | 3TB (Sata)<br/>180 (SSD) | eth0: VLAN 110<br/>eno1: VLAN 110<br/>eno2: VLAN 111 | eno3: VLAN 113
+node3 | Intel 2xE5-2699 | 64GB | 3TB (Sata)<br/>180 (SSD) | eth0: VLAN 110<br/>eno1: VLAN 110<br/>eno2: VLAN 111 | eno3: VLAN 113
#### Compute Server Software Requirements
The Local Controller will install all the software in compute servers
baremetal network. If you want to increase servers, just add another
array. If the baremetal network provides a DHCP server with gateway
and DNS server information, just change the baremetal type to "ipv4".
-ICN provides DHCP servers for the provisioning and bootstrap networks.
+ICN provides DHCP servers for the provisioning network.
`node.json.sample`
``` json
"ethernet_mac_address": "00:1e:67:fe:f4:1a",
"type": "phy"
},
- {
- "id": "bootstrap_nic",
- "ethernet_mac_address": "00:1e:67:f8:6a:40",
- "type": "phy"
- },
{
"id": "sriov_nic",
"ethernet_mac_address": "00:1e:67:f8:6a:41",
"link": "provisioning_nic",
"type": "ipv4_dhcp"
},
- {
- "id": "bootstrap",
- "link": "bootstrap_nic",
- "type": "ipv4_dhcp"
- },
{
"id": "sriov",
"link": "sriov_nic",
"ethernet_mac_address": "00:1e:67:f1:5b:90",
"type": "phy"
},
- {
- "id": "bootstrap_nic",
- "ethernet_mac_address": "00:1e:67:f8:69:80",
- "type": "phy"
- },
{
"id": "provisioning_nic",
"ethernet_mac_address": "00:1e:67:f1:5b:91",
"link": "provisioning_nic",
"type": "ipv4_dhcp"
},
- {
- "id": "bootstrap",
- "link": "bootstrap_nic",
- "type": "ipv4_dhcp"
- },
{
"id": "sriov",
"link": "sriov_nic",
``` shell
#!/bin/bash
-#Local Controller - Bootstrap cluster DHCP connection
-#BS_DHCP_INTERFACE defines the interfaces, to which ICN DHCP deployment will bind
-export BS_DHCP_INTERFACE="eno3"
-
-#BS_DHCP_INTERFACE_IP defines the IPAM for the ICN DHCP to be managed.
-export BS_DHCP_INTERFACE_IP="172.31.1.1/24"
-
#Edge Location Provider Network configuration
#Net A - Provider Network
#If provider having specific Gateway and DNS server details in the edge location,
image: akraino.org/icn/bpa-operator:latest
imagePullPolicy: IfNotPresent
volumeMounts:
- - name: dhcp-shared
- mountPath: /var/lib/dhcp/
- name: icn-cluster
mountPath: /multi-cluster
command:
- name: OPERATOR_NAME
value: "bpa-operator"
volumes:
- - name: dhcp-shared
- hostPath:
- path: /opt/icn/dhcp/
- name: icn-cluster
hostPath:
path: /opt/kud/multi-cluster
NUM_MASTERS=${NUM_MASTERS:-"1"}
NUM_WORKERS=${NUM_WORKERS:-"1"}
-# Create Fake DHCP File
-mkdir -p /opt/icn/dhcp
-cat <<EOF > /opt/icn/dhcp/dhcpd.leases
-# The format of this file is documented in the dhcpd.leases(5) manual page.
-# This lease file was written by isc-dhcp-4.3.5
-
-# authoring-byte-order entry is generated, DO NOT DELETE
-authoring-byte-order little-endian;
-
-EOF
-for ((master=0;master<NUM_MASTERS;++master)); do
- lease=$(virsh net-dhcp-leases baremetal |grep "master-${master}")
- mac=$(echo $lease | cut -d " " -f 3)
- ip=$(echo $lease | cut -d " " -f 5)
- ip="${ip%%/*}"
- cat <<EOF >> /opt/icn/dhcp/dhcpd.leases
-lease ${ip} {
- starts 4 2019/08/08 22:32:49;
- ends 4 2019/08/08 23:52:49;
- cltt 4 2019/08/08 22:32:49;
- binding state active;
- next binding state free;
- rewind binding state free;
- hardware ethernet ${mac};
- client-hostname "master-${master}";
-}
-EOF
-done
-for ((worker=0;worker<NUM_WORKERS;++worker)); do
- lease=$(virsh net-dhcp-leases baremetal |grep "worker-${worker}")
- mac=$(echo $lease | cut -d " " -f 3)
- ip=$(echo $lease | cut -d " " -f 5)
- ip="${ip%%/*}"
- cat <<EOF >> /opt/icn/dhcp/dhcpd.leases
-lease ${ip} {
- starts 4 2019/08/08 22:32:49;
- ends 4 2019/08/08 23:52:49;
- cltt 4 2019/08/08 22:32:49;
- binding state active;
- next binding state free;
- rewind binding state free;
- hardware ethernet ${mac};
- client-hostname "worker-${worker}";
-}
-EOF
-done
-
# Create provisioning CR file for testing
cat <<EOF > e2etest/e2e_test_provisioning_cr.yaml
apiVersion: bpa.akraino.org/v1alpha1
masters:
EOF
for ((master=0;master<NUM_MASTERS;++master)); do
- lease=$(virsh net-dhcp-leases baremetal |grep "master-${master}")
- mac=$(echo $lease | cut -d " " -f 3)
+ mac=$(virsh domiflist "master_${master}" | awk '/provisioning/ {print $5}')
cat <<EOF >> e2etest/e2e_test_provisioning_cr.yaml
- master-${master}:
mac-address: ${mac}
workers:
EOF
for ((worker=0;worker<NUM_WORKERS;++worker)); do
- lease=$(virsh net-dhcp-leases baremetal |grep "worker-${worker}")
- mac=$(echo $lease | cut -d " " -f 3)
+ mac=$(virsh domiflist "worker_${worker}" | awk '/provisioning/ {print $5}')
cat <<EOF >> e2etest/e2e_test_provisioning_cr.yaml
- worker-${worker}:
mac-address: ${mac}
rm e2etest/e2e_test_provisioning_cr.yaml
rm -rf /opt/kud/multi-cluster/${CLUSTER_NAME}
rm -rf /opt/kud/multi-cluster/addons
-rm /opt/icn/dhcp/dhcpd.leases
make delete
spec:
masters:
- pod11-node3:
- mac-address: 00:1e:67:f8:69:80
+ mac-address: 00:1e:67:f1:5b:91
workers:
- pod11-node2:
- mac-address: 00:1e:67:f8:6a:40
+ mac-address: 00:1e:67:fe:f4:1a
KUDPlugins:
- emco
"fmt"
"io/ioutil"
"os"
- "regexp"
"strings"
"time"
var masterString string
var workerString string
- dhcpLeaseFile := "/var/lib/dhcp/dhcpd.leases"
multiClusterDir := "/multi-cluster"
//Create Directory for the specific cluster
fmt.Printf("BareMetalHost CR %s has NIC with MAC Address %s\n", bmhCR, masterMAC)
//Get IP address of master
- hostIPaddress, err = getHostIPaddress(masterMAC, dhcpLeaseFile)
+ hostIPaddress, err = getHostIPaddress(bareMetalHostList, masterMAC)
if err != nil || hostIPaddress == "" {
err = fmt.Errorf("IP address not found for host with MAC address %s \n", masterMAC)
return reconcile.Result{}, err
fmt.Printf("Host %s matches that macAddress\n", bmhCR)
//Get IP address of worker
- hostIPaddress, err = getHostIPaddress(workerMAC, dhcpLeaseFile)
+ hostIPaddress, err = getHostIPaddress(bareMetalHostList, workerMAC)
if err != nil {
fmt.Errorf("IP address not found for host with MAC address %s \n", workerMAC)
return reconcile.Result{}, err
}
-//Function to get the IP address of a host from the DHCP file
-func getHostIPaddress(macAddress string, dhcpLeaseFilePath string) (string, error) {
+//Function to get the IP address of a host from the BareMetalHost resource
+func getHostIPaddress(bareMetalHostList *unstructured.UnstructuredList, macAddress string) (string, error) {
- //Read the dhcp lease file
- dhcpFile, err := ioutil.ReadFile(dhcpLeaseFilePath)
- if err != nil {
- fmt.Printf("Failed to read lease file\n")
- return "", err
- }
-
- dhcpLeases := string(dhcpFile)
-
- //Regex to use to search dhcpLeases
- reg := "lease.*{|ethernet.*|\n. binding state.*"
- re, err := regexp.Compile(reg)
- if err != nil {
- fmt.Printf("Could not create Regexp object, Error %v occured\n", err)
- return "", err
- }
-
- //Get String containing leased Ip addresses and Corressponding MAC addresses
- out := re.FindAllString(dhcpLeases, -1)
- outString := strings.Join(out, " ")
- stringReplacer := strings.NewReplacer("lease", "", "ethernet ", "", ";", "",
- " binding state", "", "{", "")
- replaced := stringReplacer.Replace(outString)
- ipMacList := strings.Fields(replaced)
-
- //Get IP addresses corresponding to Input MAC Address
- for idx := len(ipMacList) - 1; idx >= 0; idx-- {
- item := ipMacList[idx]
- if item == macAddress {
-
- leaseState := ipMacList[idx-1]
- if leaseState != "active" {
- err := fmt.Errorf("No active ip address lease found for MAC address %s \n", macAddress)
- fmt.Printf("%v\n", err)
- return "", err
+ for _, bareMetalHost := range bareMetalHostList.Items {
+ status, ok := bareMetalHost.Object["status"].(map[string]interface{})
+ if !ok {
+ continue
+ }
+ hardware, ok := status["hardware"].(map[string]interface{})
+ if !ok {
+ continue
+ }
+ nics, ok := hardware["nics"].([]interface{})
+ if !ok {
+ continue
+ }
+ for _, nic := range nics {
+ n, ok := nic.(map[string]interface{})
+ if !ok {
+ continue
+ }
+ ip, ok := n["ip"].(string)
+ if !ok {
+ continue
+ }
+ if macAddress == n["mac"] {
+ return ip, nil
}
- ipAdd := ipMacList[idx-2]
- return ipAdd, nil
}
-
}
return "", nil
}
package provisioning
import (
- "io/ioutil"
"os"
"testing"
logf.SetLogger(logf.ZapLogger(true))
bpaName1 := "bpa-test-cr"
bpaName2 := "bpa-test-2"
- bpaName3 := "bpa-test-3"
namespace := "default"
clusterName := "test-cluster"
clusterName2 := "test-cluster-2"
clusterName3 := "test-cluster-3"
macAddress1 := "08:00:27:00:ab:2c"
macAddress2 := "08:00:27:00:ab:3d"
- macAddress3 := "08:00:27:00:ab:1c"
-
- // Create Fake DHCP file
- err := createFakeDHCP()
- if err != nil {
- t.Fatalf("Cannot create Fake DHCP file for testing\n")
- }
// Create Fake baremetalhost
bmhList := newBMList()
// Create Fake Provisioning CR
provisioning := newBPA(bpaName1, namespace, clusterName, macAddress1)
provisioning2 := newBPA(bpaName2, namespace, clusterName2, macAddress2)
- provisioning3 := newBPA(bpaName3, namespace, clusterName3, macAddress3)
// Objects to track in the fake Client
- objs := []runtime.Object{provisioning, provisioning2, provisioning3}
+ objs := []runtime.Object{provisioning, provisioning2}
// Register operator types with the runtime scheme
sc := scheme.Scheme
- sc.AddKnownTypes(bpav1alpha1.SchemeGroupVersion, provisioning, provisioning2, provisioning3)
+ sc.AddKnownTypes(bpav1alpha1.SchemeGroupVersion, provisioning, provisioning2)
// Create Fake Clients and Clientset
fakeClient := fake.NewFakeClient(objs...)
// Mock request to simulate Reconcile() being called on an event for a watched resource
req := simulateRequest(provisioning)
- _, err = r.Reconcile(req)
+ _, err := r.Reconcile(req)
if err != nil {
t.Fatalf("reconcile: (%v)", err)
}
t.Fatalf("Failed, Unexpected error occured %v\n", err)
}
- // Test 4: Check that the right error is produced when MAC address is not found in the DHCP lease file
- req = simulateRequest(provisioning3)
- _, err = r.Reconcile(req)
- expectedErr = "IP address not found for host with MAC address " + macAddress3 + " \n"
- if err.Error() != expectedErr {
- t.Fatalf("Failed, Unexpected error occured %v\n", err)
- }
-
- // Delete Fake DHCP file and cluster directories
- err = os.Remove("/var/lib/dhcp/dhcpd.leases")
- if err != nil {
- t.Logf("\nUnable to delete fake DHCP file\n")
- }
+ // Delete cluster directories
err = os.RemoveAll("/multi-cluster/" + clusterName)
if err != nil {
t.Logf("\nUnable to delete cluster directory %s\n", clusterName)
}
nicMap1 := map[string]interface{}{
- "ip": "",
+ "ip": "192.168.50.63",
"mac": "08:00:27:00:ab:2c",
"model": "0x8086 0x1572",
"name": "eth3",
}
nicMap2 := map[string]interface{}{
- "ip": "",
+ "ip": "192.168.60.73",
"mac": "08:00:27:00:ab:1c",
"model": "0x8086 0x1572",
"name": "eth4",
}
specMap := map[string]interface{}{
- "status": map[string]interface{}{
- "errorMessage": "",
- "hardware": map[string]interface{}{
- "nics": map[string]interface{}{
- "nic1": nicMap1,
- "nic2": nicMap2,
- },
+ "bootMACAddress": "08:00:27:00:ab:2c",
+ }
+
+ statusMap := map[string]interface{}{
+ "errorMessage": "",
+ "hardware": map[string]interface{}{
+ "nics": []interface{}{
+ nicMap1,
+ nicMap2,
},
},
}
"kind": "BareMetalHost",
"metadata": metaData,
"spec": specMap,
+ "status": statusMap,
}
itemU := unstructured.Unstructured{
Object: itemMap,
return bmhList
}
-
-// Create DHCP file for testing
-func createFakeDHCP() error {
-
- dhcpData := []byte(`lease 192.168.50.63 {
- starts 4 2019/08/08 22:32:49;
- ends 4 2019/08/08 23:52:49;
- cltt 4 2019/08/08 22:32:49;
- binding state active;
- next binding state free;
- rewind binding state free;
- hardware ethernet 08:00:27:00:ab:2c;
- client-hostname "fake-test-bmh"";
-}`)
- err := ioutil.WriteFile("/var/lib/dhcp/dhcpd.leases", dhcpData, 0777)
-
- if err != nil {
- return err
- }
-
- return nil
-}
fi
cat $HOME/.ssh/id_rsa.pub >> $name-userdata.yaml
+ cloud_init_scripts >> $name-userdata.yaml
printf "\n" >> $name-userdata.yaml
}
+function cloud_init_scripts {
+ # set_dhcp_indentifier.sh:
+ # The IP address assigned to the provisioning NIC will change
+ # due to IPA using the MAC address as the client ID and systemd
+ # using a different ID. Tell systemd to use the MAC as the
+ # client ID. We can't do this in the network data as only the
+ # JSON format is supported by metal3, and the JSON format does
+ # not support the dhcp-identifier field.
+ cat << 'EOF'
+write_files:
+- path: /var/lib/cloud/scripts/per-instance/set_dhcp_identifier.sh
+ owner: root:root
+ permissions: '0777'
+ content: |
+ #!/usr/bin/env bash
+ set -eux -o pipefail
+ sed -i -e '/dhcp4: true$/!b' -e 'h;s/\S.*/dhcp-identifier: mac/;H;g' /etc/netplan/50-cloud-init.yaml
+ netplan apply
+EOF
+}
+
function apply_userdata_credential {
name="$1"
cat <<EOF > ./$name-user-data-credential.yaml
}
function cloud_init_scripts {
- # The "intel_iommu=on iommu=pt" kernel command line is necessary
- # for QAT support.
+ # set_dhcp_indentifier.sh:
+ # The IP address assigned to the provisioning NIC will change
+ # due to IPA using the MAC address as the client ID and systemd
+ # using a different ID. Tell systemd to use the MAC as the
+ # client ID. We can't do this in the network data as only the
+ # JSON format is supported by metal3, and the JSON format does
+ # not support the dhcp-identifier field.
+ # set_kernel_cmdline.sh:
+ # The "intel_iommu=on iommu=pt" kernel command line is necessary
+ # for QAT support.
cat << 'EOF'
write_files:
+- path: /var/lib/cloud/scripts/per-instance/set_dhcp_identifier.sh
+ owner: root:root
+ permissions: '0777'
+ content: |
+ #!/usr/bin/env bash
+ set -eux -o pipefail
+ sed -i -e '/dhcp4: true$/!b' -e 'h;s/\S.*/dhcp-identifier: mac/;H;g' /etc/netplan/50-cloud-init.yaml
+ netplan apply
- path: /var/lib/cloud/scripts/per-instance/set_kernel_cmdline.sh
owner: root:root
permissions: '0777'
"ethernet_mac_address": "00:1e:67:fe:f4:19",
"type": "phy"
},
- {
- "id": "bootstrap_nic",
- "ethernet_mac_address": "00:1e:67:f8:6a:40",
- "type": "phy"
- },
{
"id": "provisioning_nic",
"ethernet_mac_address": "00:1e:67:fe:f4:1a",
"link": "provisioning_nic",
"type": "ipv4_dhcp"
},
- {
- "id": "bootstrap",
- "link": "bootstrap_nic",
- "type": "ipv4_dhcp"
- },
{
"id": "sriov",
"link": "sriov_nic",
"ethernet_mac_address": "00:1e:67:f1:5b:90",
"type": "phy"
},
- {
- "id": "bootstrap_nic",
- "ethernet_mac_address": "00:1e:67:f8:69:80",
- "type": "phy"
- },
{
"id": "provisioning_nic",
"ethernet_mac_address": "00:1e:67:f1:5b:91",
"link": "provisioning_nic",
"type": "ipv4_dhcp"
},
- {
- "id": "bootstrap",
- "link": "bootstrap_nic",
- "type": "ipv4_dhcp"
- },
{
"id": "sriov",
"link": "sriov_nic",
POD_NETWORK_CIDR=${POD_NETWORK_CIDR:-"10.244.0.0/16"}
PODMAN_CNI_CONFLIST=${PODMAN_CNI_CONFLIST:-"https://raw.githubusercontent.com/containers/libpod/v1.4.4/cni/87-podman-bridge.conflist"}
-#Bootstrap K8s cluster
-BS_DHCP_INTERFACE=${BS_DHCP_INTERFACE:-}
-BS_DHCP_INTERFACE_IP=${BS_DHCP_INTERFACE_IP:-}
-BS_DHCP_DIR=${BS_DHCP_DIR:-$DOWNLOAD_PATH/dhcp}
-
#Ironic variables
IRONIC_IMAGE=${IRONIC_IMAGE:-"integratedcloudnative/ironic:v1.0-icn"}
IRONIC_INSPECTOR_IMAGE=${IRONIC_INSPECTOR_IMAGE:-"integratedcloudnative/ironic-inspector:v1.0-icn"}
fi
}
-function configure_dhcp_bridge {
- brctl addbr dhcp0
- ip link set dhcp0 up
- brctl addif dhcp0 $BS_DHCP_INTERFACE
- ip addr add dev dhcp0 $BS_DHCP_INTERFACE_IP
-}
-
function configure_ironic_bridge {
brctl addbr provisioning
ip link set provisioning up
#configure_kubeadm $1
#configure_kubelet
configure_ironic $1
- configure_dhcp_bridge
configure_ironic_bridge
configure_ironic_interfaces
}
fi
}
-function install_dhcp {
- if [ ! -d $BS_DHCP_DIR ]; then
- mkdir -p $BS_DHCP_DIR
- fi
-
- #make sure the dhcp conf sample are configured
- if [ ! -f $BS_DHCP_DIR/dhcpd.conf ]; then
- cp $PWD/05_dhcp.conf.sample $BS_DHCP_DIR/dhcpd.conf
- fi
-
- kubectl create -f $PWD/04_dhcp.yaml
-}
-
-function reset_dhcp {
- kubectl delete --ignore-not-found=true -f $PWD/04_dhcp.yaml
- if [ -d $BS_DHCP_DIR ]; then
- rm -rf $BS_DHCP_DIR
- fi
-}
-
function create_ironic_env {
cat <<EOF > ${PWD}/ironic.env
PROVISIONING_INTERFACE=provisioning
install online
elif [ "$1" == "-o" ]; then
install offline
-elif [ "$1" == "--dhcp-start" ]; then
- install_dhcp
- echo "wait for 320s for nodes to be assigned"
- sleep 6m
-elif [ "$1" == "--dhcp-reset" ]; then
- reset_dhcp
- echo "wait for 320s for nodes to be re-assigned"
- sleep 6m
else
exit 1
fi
+++ /dev/null
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: bootstrap-cluster-dhcp
-spec:
- replicas: 1
- selector:
- matchLabels:
- name: bootstrap-cluster-dhcp
- template:
- metadata:
- labels:
- name: bootstrap-cluster-dhcp
- spec:
- hostNetwork: true
- containers:
- - name: dhcp
- image: networkboot/dhcpd
- securityContext:
- privileged: true
- command: ["/entrypoint.sh"]
- args: ["dhcp0"]
- volumeMounts:
- - mountPath: /data
- name: dhcp-data-volume
- volumes:
- - name: dhcp-data-volume
- hostPath:
- path: /opt/icn/dhcp/
ip link set provisioning down || true
brctl delbr provisioning || true
-ip link set dhcp0 down || true
-brctl delbr dhcp0 || true
-
rm -rf ${IRONIC_DATA_DIR}
#!/usr/bin/env bash
-#Local controller - Bootstrap cluster DHCP connection
-export BS_DHCP_INTERFACE="eno3"
-export BS_DHCP_INTERFACE_IP="172.31.1.1/24"
-
#Ironic Metal3 settings for provisioning network
export IRONIC_INTERFACE="enp4s0f3"