From 521190c075b74beb183b42d7202103a5d52c5206 Mon Sep 17 00:00:00 2001 From: kkalev Date: Mon, 11 Dec 2023 17:21:41 +0200 Subject: [PATCH 1/3] update: support non-interactive setup --- Dockerfile | 27 +++++++++++++++++- README.md | 13 ++++++--- gunet/preseed.cfg | 23 +++++++++++++++- helper_functions.sh | 67 +++++++++++++++++++++++++++++++++++++++++++++ mkiso.sh | 49 +++++++++++++++++++++++++++++++++ 5 files changed, 173 insertions(+), 6 deletions(-) create mode 100755 helper_functions.sh diff --git a/Dockerfile b/Dockerfile index 8eb4bff..619e76d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,7 +24,7 @@ ARG DEBIAN_REPO=https://cdimage.debian.org/mirror/cdimage/archive/${DEBIAN_VERSI ARG DEBIAN_ISO=debian-${DEBIAN_VERSION}-amd64-netinst.iso RUN curl -L ${DEBIAN_REPO}/${DEBIAN_ISO} > ${JEOS_DIR}/debian/${DEBIAN_ISO} -COPY mkiso.sh ${JEOS_DIR}/ +COPY mkiso.sh helper_functions.sh ${JEOS_DIR}/ COPY gunet/ ${JEOS_DIR}/gunet/ RUN chmod 0755 ${JEOS_DIR}/mkiso.sh && \ @@ -35,6 +35,31 @@ WORKDIR ${JEOS_DIR} ENV TZ=Europe/Athens ENV DEBIAN_ISO=${DEBIAN_ISO} +# Network settings which can be passed along in the command-line if DHCP does not return something +# NET_IP: CIDR format for the IP +# NET_GATEWAY: The gateway to setup +# NET_NAMESERVERS: a list of nameservers (separated by space) +# NET_HOSTNAME: The hostname +# NET_DOMAIN: The domain +# +# Actual working example: +# ENV NET_IP="195.134.100.24/24" +# ENV NET_GATEWAY="195.134.100.1" +# ENV NET_NAMESERVERS="8.8.8.8 4.4.4.4" +# ENV NET_HOSTNAME="sso.gunet.gr" +# ENV NET_DOMAIN="gunet.gr" + +ENV NET_IP="notset" +ENV NET_GATEWAY="notset" +ENV NET_NAMESERVERS="notset" +ENV NET_HOSTNAME="notset" +ENV NET_DOMAIN="notset" + +# We can accept the root password from the command-line as an environment +# variable + +ENV ROOT_PASSWORD="notset" + ENTRYPOINT [ "/var/jeos/mkiso.sh" ] CMD ["${DEBIAN_ISO}"] \ No newline at end of file diff --git a/README.md b/README.md index fc84274..4e0369c 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,15 @@ the Docker container has finished. The recommened way to run the container is: `docker run --rm -v ${PWD}/final:/var/jeos/final --privileged ghcr.io/gunet/jeos-builder:` +### Environment variables +The following environment variables are available. For network configuration, the general path is to use DHCP provided ones and *only* if these are not available, then use the ones in environment variables (if they are provided): +* `NET_IP`: The static IP in CIDR form (ie `192.168.2.1/24`). +* `NET_GATEWAY`: The gateway IP. Only if IP has already been passed. +* `NET_NAMESERVERS`: Nameserver IPs to use, separated by space (ie `8.8.8.8 4.4.4.4`) +* `NET_HOSTNAME`: The hostname to set (ie `sso.gunet.gr`) +* `NET_DOMAIN`: The domain to set (ie `gunet.gr`) +* `ROOT_PASSWORD`: The (plaintext) root password + ### Available versions * `latest`: `11.8.0` @@ -22,10 +31,6 @@ In order to produce a Just Enough Operating System iso image, we need to run the The `` file is a Debian ISO file from the Debian project. An archive of ISO images for previous Debian versions can be found [here](https://cdimage.debian.org/mirror/cdimage/archive/) -***Notes***: -* The script will produce the ***JeOS iso file*** _gunet-jeos.iso_ into the ***Working Directory***. -* We must run the script with ***sudo*** privileges. - ### Configuration The produced .iso file installs a Debian OS, by requesting only the root password and the network configuration paramenters, in case DHCP fails, during the installation. All the configuration must be located into _gunet/_ folder. In the current configuration, _gunet/_ folder contains the follwing: * _preseed.cfg_: This file contains all the configuration of d-i installer that automates the installation procedure. The parameters are set to produce an as minimal as possible installation. During the _late_command_ step, we add further configuration and run scripts that we want to include in the installation procedure. diff --git a/gunet/preseed.cfg b/gunet/preseed.cfg index 185a1b2..62ad405 100644 --- a/gunet/preseed.cfg +++ b/gunet/preseed.cfg @@ -10,14 +10,35 @@ d-i keyboard-configuration/xkb-keymap select us d-i netcfg/choose_interface select auto +## Network setup +# +# Use DHCP, otherwise manual setup +# + d-i netcfg/dhcp_failed note d-i netcfg/dhcp_options select Configure network manually +# But if we are passed the IP/gateway configuration then we set it up statically, *only* if DHCP does not work + +#NET#d-i netcfg/get_ipaddress string __IP__ +#NET#d-i netcfg/get_netmask string __NETMASK__ +#NET#d-i netcfg/get_gateway string __GATEWAY__ +#NET#d-i netcfg/get_nameservers string __NAMESERVERS__ +#NET#d-i netcfg/confirm_static boolean true + +# The same about hostname and domain (if DHCP returns values use them, otherwise use static configuration) +#HOST#d-i netcfg/get_hostname string __HOSTNAME__ +#HOST#d-i netcfg/get_domain string __DOMAIN__ + d-i apt-setup/use_mirror boolean false ## Account setup d-i passwd/make-user boolean false +## Root password if it is passed in the command-line +#ROOT#d-i passwd/root-password password __ROOT_PASSWORD__ +#ROOT#d-i passwd/root-password-again password __ROOT_PASSWORD__ + d-i clock-setup/utc boolean false d-i clock-setup/ntp boolean true @@ -47,7 +68,7 @@ popularity-contest popularity-contest/participate boolean false tasksel tasksel/first multiselect minimal -d-i grub-installer/bootdev string /dev/sda +d-i grub-installer/bootdev string default d-i finish-install/reboot_in_progress note diff --git a/helper_functions.sh b/helper_functions.sh new file mode 100755 index 0000000..e0f67e6 --- /dev/null +++ b/helper_functions.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +# converts IPv4 as "A.B.C.D" to integer +# ip4_to_int 192.168.0.1 +# => 3232235521 +ip4_to_int() { + IFS=. read -r i j k l < 192.168.0.1 +int_to_ip4() { + echo "$(( ($1 >> 24) % 256 )).$(( ($1 >> 16) % 256 )).$(( ($1 >> 8) % 256 )).$(( $1 % 256 ))" +} + +# returns the ip part of an CIDR +# +# cidr_ip "172.16.0.10/22" +# => 172.16.0.10 +cidr_ip() { + IFS=/ read -r ip _ < 22 +cidr_prefix() { + IFS=/ read -r _ prefix < 4278190080 +int_netmask_of_prefix() { + netmask_int=$((4294967295 ^ (1 << (32 - $1)) - 1)) + echo $netmask_int +} + +# returns net mask in IPv4 format from prefix size +# +# netmask_of_prefix 24 +# => 255.255.255.0 +netmask_of_prefix() { + netmask_int=$(int_netmask_of_prefix $1) + netmask=$(int_to_ip4 $netmask_int) + echo $netmask +} + +# IP=$1 +# echo "IP/net is ${IP}" +# echo "IP is $(cidr_ip ${IP})" +# prefix=$(cidr_prefix ${IP}) +# echo "Prefix is ${prefix}" +# echo "Netmask is $(netmask_of_prefix ${prefix})" \ No newline at end of file diff --git a/mkiso.sh b/mkiso.sh index 5ab68d0..fbed4ec 100755 --- a/mkiso.sh +++ b/mkiso.sh @@ -1,4 +1,7 @@ #!/bin/bash +# Include the helper functions +source $(dirname "$0")/helper_functions.sh + set -e set -u @@ -22,6 +25,52 @@ ISODIR=${PROJECT_DIR}/isofiles ISODIR_WRITE=${ISODIR}-rw PRESEED_DIR=${PROJECT_DIR}/gunet +# check for environment variables +if [[ ${NET_IP} != "notset" ]]; then + if [[ ${NET_GATEWAY} == "notset" || ${NET_NAMESERVERS} == "notset" ]]; then + echo "Environment variable NET_IP is set but NET_GATEWAY or NET_NAMESERVERS are not!" + exit 1 + fi + NET_IP_PLAIN=$(cidr_ip ${NET_IP}) + NET_PREFIX=$(cidr_prefix ${NET_IP}) + if [[ ${NET_PREFIX} == "" ]]; then + echo "NET_IP should be of CIDR form" + exit 1 + fi + NET_NETMASK=$(netmask_of_prefix ${NET_PREFIX}) + + echo "Network configuration:" + echo "IP (CIDR): ${NET_IP}" + echo "IP (plain): ${NET_IP_PLAIN}" + echo "IP Prefix: ${NET_PREFIX}" + echo "Netmask: ${NET_NETMASK}" + echo "IP gateway: ${NET_GATEWAY}" + echo "Nameservers: ${NET_NAMESERVERS}" + echo "-------------------------------" + + sed -i'' -e "s/^#NET#//g" -e "s/__IP__/${NET_IP_PLAIN}/" -e "s/__NETMASK__/${NET_NETMASK}/" \ + -e "s/__GATEWAY__/${NET_GATEWAY}/" -e "s/__NAMESERVERS__/${NET_NAMESERVERS}/" ${PRESEED_DIR}/preseed.cfg +fi + +if [[ ${NET_HOSTNAME} != "notset" ]]; then + if [[ ${NET_DOMAIN} == "notset" ]]; then + echo "Environment variable NET_HOSTNAME is set but NET_DOMAIN is not!" + exit 1 + fi + echo "Hostname configuration:" + echo "Hostname: ${NET_HOSTNAME}" + echo "Domain: ${NET_DOMAIN}" + echo "----------------------------" + + sed -i'' -e "s/^#HOST#//g" \ + -e "s/__HOSTNAME__/${NET_HOSTNAME}/" -e "s/__DOMAIN__/${NET_DOMAIN}/" ${PRESEED_DIR}/preseed.cfg +fi + +if [[ ${ROOT_PASSWORD} != "notset" ]]; then + echo "Root passwd: ${ROOT_PASSWORD}" + sed -i'' -e "s/^#ROOT#//g" -e "s/__ROOT_PASSWORD__/${ROOT_PASSWORD}/" ${PRESEED_DIR}/preseed.cfg +fi + sed -i "s/^M//" $PRESEED_DIR/custom_script.sh echo 'mounting ISO9660 filesystem...' From 49a242bd471d70051edd81b66194edeb4159f87c Mon Sep 17 00:00:00 2001 From: kkalev Date: Mon, 11 Dec 2023 18:48:12 +0200 Subject: [PATCH 2/3] update: also support completely static net config --- Dockerfile | 1 + README.md | 1 + gunet/preseed.cfg | 3 +++ mkiso.sh | 12 ++++++++++++ 4 files changed, 17 insertions(+) diff --git a/Dockerfile b/Dockerfile index 619e76d..f5d6ed9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -49,6 +49,7 @@ ENV DEBIAN_ISO=${DEBIAN_ISO} # ENV NET_HOSTNAME="sso.gunet.gr" # ENV NET_DOMAIN="gunet.gr" +ENV NET_STATIC="no" ENV NET_IP="notset" ENV NET_GATEWAY="notset" ENV NET_NAMESERVERS="notset" diff --git a/README.md b/README.md index 4e0369c..1b0dae3 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ The following environment variables are available. For network configuration, th * `NET_NAMESERVERS`: Nameserver IPs to use, separated by space (ie `8.8.8.8 4.4.4.4`) * `NET_HOSTNAME`: The hostname to set (ie `sso.gunet.gr`) * `NET_DOMAIN`: The domain to set (ie `gunet.gr`) +* `NET_STATIC`: If set to `yes` then we only perform static network configuration and **all** the above variables **must** be set * `ROOT_PASSWORD`: The (plaintext) root password ### Available versions diff --git a/gunet/preseed.cfg b/gunet/preseed.cfg index 62ad405..83de6d0 100644 --- a/gunet/preseed.cfg +++ b/gunet/preseed.cfg @@ -14,6 +14,8 @@ d-i netcfg/choose_interface select auto # # Use DHCP, otherwise manual setup # +# Unless we have been configured to only make static network config +#STATIC#d-i netcfg/disable_autoconfig boolean true d-i netcfg/dhcp_failed note d-i netcfg/dhcp_options select Configure network manually @@ -29,6 +31,7 @@ d-i netcfg/dhcp_options select Configure network manually # The same about hostname and domain (if DHCP returns values use them, otherwise use static configuration) #HOST#d-i netcfg/get_hostname string __HOSTNAME__ #HOST#d-i netcfg/get_domain string __DOMAIN__ +#STATIC#d-i netcfg/hostname string __HOSTNAME__ d-i apt-setup/use_mirror boolean false diff --git a/mkiso.sh b/mkiso.sh index fbed4ec..627f7ec 100755 --- a/mkiso.sh +++ b/mkiso.sh @@ -26,6 +26,15 @@ ISODIR_WRITE=${ISODIR}-rw PRESEED_DIR=${PROJECT_DIR}/gunet # check for environment variables +if [[ ${NET_STATIC} == "yes" ]]; then + if [[ ${NET_IP} == "notset" || ${NET_GATEWAY} == "notset" || \ + ${NET_NAMESERVERS} == "notset" || ${NET_HOSTNAME} == "notset" || \ + ${NET_DOMAIN} == "notset" ]]; then + echo "Environment variable NET_STATIC is yes but some NET_* variables are not set!" + exit 1 + fi + sed -i'' -e "s/^#STATIC#//g" ${PRESEED_DIR}/preseed.cfg +fi if [[ ${NET_IP} != "notset" ]]; then if [[ ${NET_GATEWAY} == "notset" || ${NET_NAMESERVERS} == "notset" ]]; then echo "Environment variable NET_IP is set but NET_GATEWAY or NET_NAMESERVERS are not!" @@ -71,6 +80,9 @@ if [[ ${ROOT_PASSWORD} != "notset" ]]; then sed -i'' -e "s/^#ROOT#//g" -e "s/__ROOT_PASSWORD__/${ROOT_PASSWORD}/" ${PRESEED_DIR}/preseed.cfg fi +cat ${PRESEED_DIR}/preseed.cfg +exit + sed -i "s/^M//" $PRESEED_DIR/custom_script.sh echo 'mounting ISO9660 filesystem...' From 00787585bb404084be3d0410684d518414b67527 Mon Sep 17 00:00:00 2001 From: kkalev Date: Mon, 11 Dec 2023 22:59:51 +0200 Subject: [PATCH 3/3] make iso burning less verbose --- mkiso.sh | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/mkiso.sh b/mkiso.sh index 627f7ec..7058d8a 100755 --- a/mkiso.sh +++ b/mkiso.sh @@ -80,9 +80,6 @@ if [[ ${ROOT_PASSWORD} != "notset" ]]; then sed -i'' -e "s/^#ROOT#//g" -e "s/__ROOT_PASSWORD__/${ROOT_PASSWORD}/" ${PRESEED_DIR}/preseed.cfg fi -cat ${PRESEED_DIR}/preseed.cfg -exit - sed -i "s/^M//" $PRESEED_DIR/custom_script.sh echo 'mounting ISO9660 filesystem...' @@ -93,7 +90,7 @@ mount -o loop $ISOFILE $ISODIR echo 'copying to writable dir...' rm -rf $ISODIR_WRITE || true [ -d $ISODIR_WRITE ] || mkdir -p $ISODIR_WRITE -rsync -a -H --exclude=TRANS.TBL $ISODIR/ $ISODIR_WRITE +rsync --info=progress2 -a -H --exclude=TRANS.TBL $ISODIR/ $ISODIR_WRITE echo 'unmount iso dir' umount $ISODIR @@ -106,6 +103,7 @@ cp -r $PRESEED_DIR/ $ISODIR_WRITE/ echo 'edit isolinux/txt.cfg...' sed 's/initrd.gz/initrd.gz file=\/cdrom\/gunet\/preseed.cfg/' -i $ISODIR_WRITE/isolinux/txt.cfg +echo 'creating initrd.gz..' mkdir -p irmod cd irmod gzip -d < $ISODIR_WRITE/install.amd/initrd.gz | \ @@ -127,7 +125,7 @@ popd echo 'making ISO...' genisoimage -o $ISOFILE_FINAL \ -r -J -no-emul-boot -boot-load-size 4 \ - -boot-info-table \ + -boot-info-table -quiet \ -b isolinux/isolinux.bin \ -c isolinux/boot.cat $ISODIR_WRITE