Skip to content

Commit

Permalink
Enable IPv6 Support
Browse files Browse the repository at this point in the history
This commit adds support for IPv6. When $PROVISIONING_IP is specified,
which may be an IPv6 address, the various containers will wait for that
IP to become available on an interface.

If the IP is IPv6, then we use an IPv6-specific configurations. Note,
IPv6 hosts are expected to be using UEFI boot, as we use snponly.efi.
snponly.efi uses the UEFI network stack instead of the iPXE drivers.
When using EDK2 OVMF + iPXE + ipxe.efi, we have seen lock-ups in
initialization of the hardware devices.

As neither CentOS nor RHEL distribute iPXE builds with IPv6 support, we
build them from source as part of the container build.
  • Loading branch information
stbenjam committed Nov 8, 2019
1 parent cc5cc77 commit 2ad2b0d
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 41 deletions.
30 changes: 23 additions & 7 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,18 +1,32 @@
## Build iPXE w/ IPv6 Support
## Note: we are pinning to a specific commit for reproducible builds.
## Updated as needed.
FROM docker.io/centos:centos7 AS builder
RUN yum install -y gcc git make genisoimage xz-devel
WORKDIR /tmp
COPY . .
RUN git clone http://git.ipxe.org/ipxe.git && \
cd ipxe && \
git checkout 3fe683ebab29afacf224e6b0921f6329bebcdca7 && \
cd src && \
sed -i -e "s/#undef.*NET_PROTO_IPV6/#define NET_PROTO_IPV6/g" config/general.h && \
make bin/undionly.kpxe bin-x86_64-efi/ipxe.efi bin-x86_64-efi/snponly.efi

FROM docker.io/centos:centos7

RUN yum install -y python-requests && \
curl https://raw.githubusercontent.com/openstack/tripleo-repos/master/tripleo_repos/main.py | python - -b train current-tripleo && \
yum update -y && \
yum install -y python-gunicorn openstack-ironic-api openstack-ironic-conductor crudini \
iproute iptables dnsmasq httpd qemu-img-ev iscsi-initiator-utils \
parted gdisk ipxe-bootimgs psmisc sysvinit-tools \
mariadb-server genisoimage && \
yum install -y python-ironic-prometheus-exporter && \
iproute iptables dnsmasq httpd qemu-img-ev iscsi-initiator-utils parted gdisk psmisc \
sysvinit-tools mariadb-server genisoimage python-ironic-prometheus-exporter && \
yum clean all && \
rm -rf /var/cache/{yum,dnf}/*

RUN mkdir /tftpboot && \
cp /usr/share/ipxe/undionly.kpxe /usr/share/ipxe/ipxe.efi /tftpboot/
RUN mkdir -p /tftpboot
COPY --from=builder /tmp/ipxe/src/bin/undionly.kpxe /tftpboot
COPY --from=builder /tmp/ipxe/src/bin-x86_64-efi/snponly.efi /tftpboot
COPY --from=builder /tmp/ipxe/src/bin-x86_64-efi/ipxe.efi /tftpboot

COPY ./ironic.conf /tmp/ironic.conf
RUN crudini --merge /etc/ironic/ironic.conf < /tmp/ironic.conf && \
Expand All @@ -25,13 +39,15 @@ COPY ./rundnsmasq.sh /bin/rundnsmasq
COPY ./runhttpd.sh /bin/runhttpd
COPY ./runmariadb.sh /bin/runmariadb
COPY ./configure-ironic.sh /bin/configure-ironic.sh
COPY ./ironic-common.sh /bin/ironic-common.sh

# TODO(dtantsur): remove these 2 scripts if we decide to
# stop supporting running all 2 processes via one entry point.
COPY ./runhealthcheck.sh /bin/runhealthcheck
COPY ./runironic.sh /bin/runironic

COPY ./dnsmasq.conf /etc/dnsmasq.conf
COPY ./dnsmasq.conf.ipv4 /etc/dnsmasq.conf.ipv4
COPY ./dnsmasq.conf.ipv6 /etc/dnsmasq.conf.ipv6
COPY ./inspector.ipxe /tmp/inspector.ipxe
COPY ./dualboot.ipxe /tmp/dualboot.ipxe

Expand Down
20 changes: 8 additions & 12 deletions configure-ironic.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
#!/usr/bin/bash

# Get environment settings and update ironic.conf
PROVISIONING_INTERFACE=${PROVISIONING_INTERFACE:-"provisioning"}
IRONIC_IP=$(ip -4 address show dev "$PROVISIONING_INTERFACE" | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -n 1)
until [ ! -z "${IRONIC_IP}" ]; do
echo "Waiting for ${PROVISIONING_INTERFACE} interface to be configured"
sleep 1
IRONIC_IP=$(ip -4 address show dev "$PROVISIONING_INTERFACE" | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -n 1)
done
. /bin/ironic-common.sh

HTTP_PORT=${HTTP_PORT:-"80"}
MARIADB_PASSWORD=${MARIADB_PASSWORD:-"change_me"}
NUMPROC=$(cat /proc/cpuinfo | grep "^processor" | wc -l)
Expand All @@ -16,28 +10,30 @@ NUMWORKERS=$(( NUMPROC < 12 ? NUMPROC : 12 ))
# Whether to enable fast_track provisioning or not
IRONIC_FAST_TRACK=${IRONIC_FAST_TRACK:-true}

wait_for_interface_or_ip

cp /etc/ironic/ironic.conf /etc/ironic/ironic.conf_orig

crudini --merge /etc/ironic/ironic.conf <<EOF
[DEFAULT]
my_ip = $IRONIC_IP
[api]
host_ip = ::
api_workers = $NUMWORKERS
[conductor]
api_url = http://${IRONIC_IP}:6385
api_url = http://${IRONIC_URL_HOST}:6385
[database]
connection = mysql+pymysql://ironic:${MARIADB_PASSWORD}@localhost/ironic?charset=utf8
[deploy]
http_url = http://${IRONIC_IP}:${HTTP_PORT}
http_url = http://${IRONIC_URL_HOST}:${HTTP_PORT}
fast_track = ${IRONIC_FAST_TRACK}
[inspector]
endpoint_override = http://${IRONIC_IP}:5050
endpoint_override = http://${IRONIC_URL_HOST}:5050
EOF

mkdir -p /shared/html
Expand Down
2 changes: 1 addition & 1 deletion dnsmasq.conf → dnsmasq.conf.ipv4
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ tftp-root=/shared/tftpboot

dhcp-match=ipxe,175
# Client is already running iPXE; move to next stage of chainloading
dhcp-boot=tag:ipxe,http://IRONIC_IP:HTTP_PORT/dualboot.ipxe
dhcp-boot=tag:ipxe,http://IRONIC_URL_HOST:HTTP_PORT/dualboot.ipxe

# Note: Need to test EFI booting
dhcp-match=set:efi,option:client-arch,7
Expand Down
21 changes: 21 additions & 0 deletions dnsmasq.conf.ipv6
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
interface=PROVISIONING_INTERFACE
bind-dynamic
enable-tftp
tftp-root=/shared/tftpboot
log-dhcp

enable-ra
ra-param=PROVISIONING_INTERFACE,10

dhcp-vendorclass=set:pxe6,enterprise:343,PXEClient
dhcp-range=DHCP_RANGE
dhcp-userclass=set:ipxe6,iPXE
dhcp-option=tag:pxe6,option6:bootfile-url,tftp://IRONIC_URL_HOST/snponly.efi
dhcp-option=tag:ipxe6,option6:bootfile-url,http://IRONIC_URL_HOST:HTTP_PORT/dualboot.ipxe

# Disable listening for DNS
port=0

# Disable default router(s) and DNS over provisioning network
dhcp-option=3
dhcp-option=6
32 changes: 32 additions & 0 deletions ironic-common.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
PROVISIONING_INTERFACE=${PROVISIONING_INTERFACE:-"provisioning"}

# Wait for the interface or IP to be up, sets $IRONIC_IP
function wait_for_interface_or_ip() {
# If $PROVISIONING_IP is specified, then we wait for that to become available on an interface, otherwise we look at $PROVISIONING_INTERFACE for an IP
if [ ! -z "${PROVISIONING_IP}" ];
then
IRONIC_IP=""
until [ ! -z "${IRONIC_IP}" ]; do
echo "Waiting for ${PROVISIONING_IP} to be configured on an interface"
IRONIC_IP=$(ip -br addr show | grep "${PROVISIONING_IP}" | grep -Po "[^\s]+/[0-9]+" | sed -e 's%/.*%%' | head -n 1)
sleep 1
done
else
until [ ! -z "${IRONIC_IP}" ]; do
echo "Waiting for ${PROVISIONING_INTERFACE} interface to be configured"
IRONIC_IP=$(ip -br addr show dev $PROVISIONING_INTERFACE | grep -Po "[^\s]+/[0-9]+" | grep -e "^fd" -e "\." | sed -e 's%/.*%%' | head -n 1)
sleep 1
done
fi

# If the IP contains a colon, then it's an IPv6 address, and the HTTP
# host needs surrounding with brackets
if [[ "$IRONIC_IP" =~ .*:.* ]]
then
IPV=6
IRONIC_URL_HOST="[$IRONIC_IP]"
else
IPV=4
IRONIC_URL_HOST=$IRONIC_IP
fi
}
17 changes: 7 additions & 10 deletions rundnsmasq.sh
Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
#!/usr/bin/bash

PROVISIONING_INTERFACE=${PROVISIONING_INTERFACE:-"provisioning"}
. /bin/ironic-common.sh

HTTP_PORT=${HTTP_PORT:-"80"}
DHCP_RANGE=${DHCP_RANGE:-"172.22.0.10,172.22.0.100"}
DNSMASQ_EXCEPT_INTERFACE=${DNSMASQ_EXCEPT_INTERFACE:-"lo"}

PROVISIONING_IP=$(ip -4 address show dev "$PROVISIONING_INTERFACE" | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -n 1)
until [ ! -z "${PROVISIONING_IP}" ]; do
echo "Waiting for ${PROVISIONING_INTERFACE} interface to be configured"
sleep 1
PROVISIONING_IP=$(ip -4 address show dev "$PROVISIONING_INTERFACE" | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -n 1)
done
wait_for_interface_or_ip

mkdir -p /shared/tftpboot
mkdir -p /shared/html/images
mkdir -p /shared/html/pxelinux.cfg
mkdir -p /shared/log/dnsmasq

# Copy files to shared mount
cp /usr/share/ipxe/undionly.kpxe /usr/share/ipxe/ipxe.efi /shared/tftpboot
cp /tftpboot/undionly.kpxe /tftpboot/ipxe.efi /tftpboot/snponly.efi /shared/tftpboot

# Copy IPv4 or IPv6 config
cp /etc/dnsmasq.conf.ipv$IPV /etc/dnsmasq.conf

# Use configured values
sed -i -e s/IRONIC_IP/${PROVISIONING_IP}/g -e s/HTTP_PORT/${HTTP_PORT}/g \
sed -i -e s/IRONIC_URL_HOST/${IRONIC_URL_HOST}/g -e s/HTTP_PORT/${HTTP_PORT}/g \
-e s/DHCP_RANGE/${DHCP_RANGE}/g -e s/PROVISIONING_INTERFACE/${PROVISIONING_INTERFACE}/g \
/etc/dnsmasq.conf
for iface in $( echo "$DNSMASQ_EXCEPT_INTERFACE" | tr ',' ' '); do
Expand All @@ -39,4 +37,3 @@ done
/usr/sbin/dnsmasq -d -q -C /etc/dnsmasq.conf 2>&1 | tee /shared/log/dnsmasq/dnsmasq.log &
/bin/runhealthcheck "dnsmasq" &>/dev/null &
sleep infinity

2 changes: 1 addition & 1 deletion runhealthcheck.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ while true ; do

elif [ $1 = "dnsmasq" ] ; then
DNSMASQPID=$(pidof dnsmasq)
fuser 67/udp |& grep -w "$DNSMASQPID"
fuser 67/udp 547/udp |& grep -w "$DNSMASQPID"

elif [ $1 = "ironic" ] ; then
curl -s http://localhost:6385 > /dev/null || ( echo "Can't contact ironic-api" && exit 1 )
Expand Down
16 changes: 6 additions & 10 deletions runhttpd.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
#!/usr/bin/bash

PROVISIONING_INTERFACE=${PROVISIONING_INTERFACE:-"provisioning"}
. /bin/ironic-common.sh

HTTP_PORT=${HTTP_PORT:-"80"}
HTTP_IP=$(ip -4 address show dev "$PROVISIONING_INTERFACE" | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -n 1)
until [ ! -z "${HTTP_IP}" ]; do
echo "Waiting for ${PROVISIONING_INTERFACE} interface to be configured"
sleep 1
HTTP_IP=$(ip -4 address show dev "$PROVISIONING_INTERFACE" | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -n 1)
done

wait_for_interface_or_ip

mkdir -p /shared/html
chmod 0777 /shared/html
Expand All @@ -17,9 +14,9 @@ cp /tmp/inspector.ipxe /shared/html/inspector.ipxe
cp /tmp/dualboot.ipxe /shared/html/dualboot.ipxe

# Use configured values
sed -i -e s/IRONIC_IP/${HTTP_IP}/g -e s/HTTP_PORT/${HTTP_PORT}/g /shared/html/inspector.ipxe
sed -i -e s/IRONIC_IP/${IRONIC_URL_HOST}/g -e s/HTTP_PORT/${HTTP_PORT}/g /shared/html/inspector.ipxe

sed -i 's/^Listen .*$/Listen '"$HTTP_PORT"'/' /etc/httpd/conf/httpd.conf
sed -i 's/^Listen .*$/Listen [::]:'"$HTTP_PORT"'/' /etc/httpd/conf/httpd.conf
sed -i -e 's|\(^[[:space:]]*\)\(DocumentRoot\)\(.*\)|\1\2 "/shared/html"|' \
-e 's|<Directory "/var/www/html">|<Directory "/shared/html">|' \
-e 's|<Directory "/var/www">|<Directory "/shared">|' /etc/httpd/conf/httpd.conf
Expand All @@ -44,4 +41,3 @@ fi

/bin/runhealthcheck "httpd" "$HTTP_PORT" &>/dev/null &
sleep infinity

0 comments on commit 2ad2b0d

Please sign in to comment.