From a5d085b125fd7cca7eb0ac72fa3ba4e880da2e67 Mon Sep 17 00:00:00 2001 From: George T Kramer Date: Fri, 3 Mar 2017 11:19:57 -0800 Subject: [PATCH] Creating install scripts for PXE and ICIS These install scripts set up a PXE server with the ICIS service. They automate the configuration of Clear Linux for baremetal installations of Clear Linux. They assume a dedicated machine and a clean install is the starting point. They also assume that a NAT network topology is used for PXE booting. They create parameters which users can modify prior to installation. The built-in parameterized systemd service and socket for uwsgi applications is being used to deploy ICIS on Clear Linux. --- icis_uwsgi.ini | 22 ------ icis_uwsgi.service | 13 --- install-icis.sh | 115 +++++++++++++++++++++++++++ install-pxe.sh | 191 +++++++++++++++++++++++++++++++++++++++++++++ nginx.conf | 18 ----- requirements.txt | 1 - 6 files changed, 306 insertions(+), 54 deletions(-) delete mode 100644 icis_uwsgi.ini delete mode 100644 icis_uwsgi.service create mode 100755 install-icis.sh create mode 100755 install-pxe.sh delete mode 100644 nginx.conf diff --git a/icis_uwsgi.ini b/icis_uwsgi.ini deleted file mode 100644 index 0d47d95..0000000 --- a/icis_uwsgi.ini +++ /dev/null @@ -1,22 +0,0 @@ -[uwsgi] -#application's base folder -base = /var/www/ister-cloud-init-svc - -#python module to import -app = app -module = %(app) - -home = %(base) -pythonpath = %(base) - -#socket file's location -socket = /var/www/ister-cloud-init-svc/%n.sock - -#permissions for the socket file -chmod-socket = 666 - -#the variable that holds a flask application inside the module imported at line #6 -callable = app - -#location of log files -logto = /var/log/uwsgi/%n.log diff --git a/icis_uwsgi.service b/icis_uwsgi.service deleted file mode 100644 index 4f6d75f..0000000 --- a/icis_uwsgi.service +++ /dev/null @@ -1,13 +0,0 @@ -[Unit] -Description=ISTER uWSGI service - -[Service] -Type=notify -ExecStart=/usr/bin/uwsgi --ini /var/www/ister-cloud-init-svc/icis_uwsgi.ini \ - -H /var/www/ister-cloud-init-svc/.venv/ -Restart=always -KillSignal=SIGQUIT -NotifyAccess=all - -[Install] -WantedBy=multi-user.target diff --git a/install-icis.sh b/install-icis.sh new file mode 100755 index 0000000..d0a67de --- /dev/null +++ b/install-icis.sh @@ -0,0 +1,115 @@ +#!/bin/bash +web_root=/var/www +pxe_root=$web_root/pxe-images +icis_root=$web_root/ister-cloud-init-svc + +uwsgi_app_dir=/usr/share/uwsgi +uwsgi_socket_dir=/run/uwsgi +icis_app_name=icis + +main() { + install_dependencies + configure_web_server +} + +install_dependencies() { + swupd bundle-add pxe-server python-basic-dev dev-utils + pip install uwsgi +} + +configure_web_server() { + stop_web_services + populate_web_content + generate_web_configuration + start_web_services +} + +stop_web_services() { + systemctl stop nginx + systemctl stop uwsgi@$icis_app_name.socket + systemctl stop uwsgi@$icis_app_name.service +} + +populate_web_content() { + rm -rf $web_root + populate_pxe_content + populate_icis_content +} + +populate_pxe_content() { + mkdir -p $pxe_root + curl -o /tmp/clear-pxe.tar.xz https://download.clearlinux.org/current/clear-$(curl https://download.clearlinux.org/latest)-pxe.tar.xz + tar -xJf /tmp/clear-pxe.tar.xz -C $pxe_root + ln -sf $(ls $pxe_root | grep 'org.clearlinux.*') $pxe_root/linux + cat > $pxe_root/ipxe_boot_script.txt << EOF +#!ipxe +kernel linux quiet init=/usr/lib/systemd/systemd-bootchart initcall_debug tsc=reliable no_timer_check noreplace-smp rw initrd=initrd isterconf=http://192.168.1.1/icis/static/ister/ister.conf +initrd initrd +boot +EOF +} + +populate_icis_content() { + # Reference: http://uwsgi-docs.readthedocs.io/en/latest/Systemd.html#one-service-per-app-in-systemd + # Reference: https://www.dabapps.com/blog/introduction-to-pip-and-virtualenv-python/ + mkdir -p $icis_root + cp -rf $(dirname ${0})/bin/* $icis_root + + local icis_venv_dir=$icis_root/env + virtualenv $icis_venv_dir + $icis_venv_dir/bin/pip install -r $(dirname ${0})/requirements.txt + + rm -rf $uwsgi_app_dir + mkdir -p $uwsgi_app_dir + cat > $uwsgi_app_dir/$icis_app_name.ini << EOF +[uwsgi] +# App configurations +module = app +callable = app +chdir = $icis_root +home = $icis_venv_dir + +# Init system configurations +master = true +cheap = true +idle = 600 +die-on-idle = true +manage-script-name = true +EOF +} + +generate_web_configuration() { + rm -rf /etc/nginx + mkdir -p /etc/nginx + cat > /etc/nginx/nginx.conf << EOF +server { + listen 80; + server_name localhost; + location / { + root $pxe_root; + autoindex on; + index index.html index.htm; + } + location /icis/static/ { + root $icis_root/static; + rewrite ^/icis/static(/.*)$ $1 break; + } + location /icis/ { + uwsgi_pass unix://$uwsgi_socket_dir/$icis_app_name.sock; + include uwsgi_params; + } +} +EOF +} + +start_web_services() { + systemctl enable uwsgi@$icis_app_name.service + systemctl enable uwsgi@$icis_app_name.socket + systemctl restart uwsgi@$icis_app_name.socket + + systemctl enable nginx + systemctl restart nginx +} + +main + diff --git a/install-pxe.sh b/install-pxe.sh new file mode 100755 index 0000000..7f84d00 --- /dev/null +++ b/install-pxe.sh @@ -0,0 +1,191 @@ +#!/bin/bash +external_iface=eno1 +internal_iface=eno2 +pxe_subnet=192.168.1 +pxe_internal_ip=$pxe_subnet.1 +pxe_subnet_mask_ip=255.255.255.0 +tftp_root=/srv/tftp + +main() { + install_dependencies + configure_network + configure_nat + configure_tftp_server + configure_dhcp_server +} + +install_dependencies() { + swupd bundle-add pxe-server +} + +configure_network() { + rm -rf /etc/systemd/network + mkdir -p /etc/systemd/network + + ln -sf /dev/null /etc/systemd/network/80-dhcp.network + + cat > /etc/systemd/network/80-external-dynamic.network << EOF +[Match] +Name=$external_iface +[Network] +DHCP=yes +EOF + + local bitmask + convert_ip_address_to_bitmask $pxe_subnet_mask_ip bitmask + cat > /etc/systemd/network/80-internal-static.network << EOF +[Match] +Name=$internal_iface +[Network] +Address=$pxe_internal_ip/$bitmask +EOF + + systemctl restart systemd-networkd +} + +convert_ip_address_to_bitmask() { + local binary='' + local D2B=({0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}) + local decimals=($(tr '.' ' ' <<< $1)) + local decimal + for decimal in "${decimals[@]}"; do + binary=$binary${D2B[$decimal]} + done + eval "$2=$(grep -o 1 <<< $binary | wc -l)" +} + +configure_nat() { + iptables -t nat -F POSTROUTING + iptables -t nat -A POSTROUTING -o $external_iface -j MASQUERADE + iptables -t filter -F FORWARD + iptables -t filter -A FORWARD -i $external_iface -o $internal_iface -m state --state RELATED,ESTABLISHED -j ACCEPT + iptables -t filter -A FORWARD -i $internal_iface -o $external_iface -j ACCEPT + iptables_save_units=($(ls /usr/lib/systemd/system | egrep 'ip6?tables-save')) + systemctl enable ${iptables_save_units[@]} + systemctl restart ${iptables_save_units[@]} + iptables_restore_units=($(ls /usr/lib/systemd/system | egrep 'ip6?tables-restore')) + systemctl enable ${iptables_restore_units[@]} + systemctl restart ${iptables_restore_units[@]} + + rm -rf /etc/sysctl.d + mkdir -p /etc/sysctl.d + echo net.ipv4.ip_forward=1 > /etc/sysctl.d/80-nat-forwarding.conf + echo 1 > /proc/sys/net/ipv4/ip_forward +} + +configure_tftp_server() { + rm -rf $tftp_root + mkdir -p $tftp_root + ln -sf /usr/share/ipxe/ipxe-x86_64.efi $tftp_root/ipxe-x86_64.efi + ln -sf /usr/share/ipxe/undionly.kpxe $tftp_root/undionly.kpxe + + cat > /etc/systemd/resolved.conf << EOF +[Resolve] +DNSStubListener=no +EOF + systemctl restart systemd-resolved + + cat > /etc/dnsmasq.conf << EOF +interface=$internal_iface +enable-tftp +tftp-root=$tftp_root +EOF + systemctl enable dnsmasq + systemctl restart dnsmasq +} + +configure_dhcp_server() { + local host_dns_servers=($(grep -Po '(?<=nameserver )(\d+\.?){4}' /etc/resolv.conf)) + local dns_server_list=$(echo ${host_dns_servers[@]} | sed 's/ /, /g') + + cat > /etc/dhcpd.conf << EOF +DHCPDARGS="$internal_iface"; +# iPXE-specific options +# Source: http://www.ipxe.org/howto/dhcpd +option space ipxe; +option ipxe-encap-opts code 175 = encapsulate ipxe; +option ipxe.priority code 1 = signed integer 8; +option ipxe.keep-san code 8 = unsigned integer 8; +option ipxe.skip-san-boot code 9 = unsigned integer 8; +option ipxe.syslogs code 85 = string; +option ipxe.cert code 91 = string; +option ipxe.privkey code 92 = string; +option ipxe.crosscert code 93 = string; +option ipxe.no-pxedhcp code 176 = unsigned integer 8; +option ipxe.bus-id code 177 = string; +option ipxe.bios-drive code 189 = unsigned integer 8; +option ipxe.username code 190 = string; +option ipxe.password code 191 = string; +option ipxe.reverse-username code 192 = string; +option ipxe.reverse-password code 193 = string; +option ipxe.version code 235 = string; +option iscsi-initiator-iqn code 203 = string; +option ipxe.pxeext code 16 = unsigned integer 8; +option ipxe.iscsi code 17 = unsigned integer 8; +option ipxe.aoe code 18 = unsigned integer 8; +option ipxe.http code 19 = unsigned integer 8; +option ipxe.https code 20 = unsigned integer 8; +option ipxe.tftp code 21 = unsigned integer 8; +option ipxe.ftp code 22 = unsigned integer 8; +option ipxe.dns code 23 = unsigned integer 8; +option ipxe.bzimage code 24 = unsigned integer 8; +option ipxe.multiboot code 25 = unsigned integer 8; +option ipxe.slam code 26 = unsigned integer 8; +option ipxe.srp code 27 = unsigned integer 8; +option ipxe.nbi code 32 = unsigned integer 8; +option ipxe.pxe code 33 = unsigned integer 8; +option ipxe.elf code 34 = unsigned integer 8; +option ipxe.comboot code 35 = unsigned integer 8; +option ipxe.efi code 36 = unsigned integer 8; +option ipxe.fcoe code 37 = unsigned integer 8; +option ipxe.vlan code 38 = unsigned integer 8; +option ipxe.menu code 39 = unsigned integer 8; +option ipxe.sdi code 40 = unsigned integer 8; +option ipxe.nfs code 41 = unsigned integer 8; + +subnet $pxe_subnet.0 netmask $pxe_subnet_mask_ip { + option broadcast-address $pxe_subnet.255; + option routers $pxe_internal_ip; + option domain-name-servers $dns_server_list, $pxe_internal_ip; + + class "PXE-Chainload" { + match if substring(option vendor-class-identifier, 0, 9) = "PXEClient"; + + next-server $pxe_internal_ip; + if exists user-class and option user-class = "iPXE" { + filename "http://$pxe_internal_ip/ipxe_boot_script.txt"; + } + elsif substring(option vendor-class-identifier, 0, 20) = "PXEClient:Arch:00007" or substring(option vendor-class-identifier, 0, 20) = "PXEClient:Arch:00008" or substring(option vendor-class-identifier, 0, 20) = "PXEClient:Arch:00009" { + filename "ipxe-x86_64.efi"; + } + elsif substring(option vendor-class-identifier, 0, 20) = "PXEClient:Arch:00000" { + filename "undionly.kpxe"; + } + } + + pool { + allow members of "PXE-Chainload"; + range $pxe_subnet.128 $pxe_subnet.253; + default-lease-time 600; + max-lease-time 3600; + } + + pool { + deny members of "PXE-Chainload"; + range $pxe_subnet.2 $pxe_subnet.127; + default-lease-time 3600; + max-lease-time 21600; + } +} +EOF + + rm -rf /var/db + mkdir -p /var/db + touch /var/db/dhcpd.leases + + systemctl enable dhcp4 + systemctl restart dhcp4 +} + +main + diff --git a/nginx.conf b/nginx.conf deleted file mode 100644 index 8b8df70..0000000 --- a/nginx.conf +++ /dev/null @@ -1,18 +0,0 @@ -server { - listen 80; - server_name hostname; - server_name_in_redirect off; - location / { - root /var/www/pxe; - autoindex on; - index index.html index.htm; - } - location /icis/static/ { - rewrite ^/icis/static(/.*)$ $1 break; - root /var/www/ister-cloud-init-svc/static/; - } - location /icis/ { - uwsgi_pass unix:///var/www/ister-cloud-init-svc/icis_uwsgi.sock; - include uwsgi_params; - } -} diff --git a/requirements.txt b/requirements.txt index 5307ad6..4cb5dab 100644 --- a/requirements.txt +++ b/requirements.txt @@ -38,7 +38,6 @@ sphinx-rtd-theme==0.1.9 tornado==4.3 urllib3==1.14 urwid==1.3.1 -virtualenv==14.0.1 watchdog==0.8.3 Werkzeug==0.11.3 wrapt==1.10.6