From ac2e41bd789a911df8ab8073d46d0ce92a09422e Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Thu, 18 Jun 2020 12:36:00 -0400 Subject: [PATCH] First pass at RHV4 support Derive from EL8 with some EL7 vintage accomodations --- .../initramfs/opt/confluent/bin/apiclient | 55 +++++++++++ .../lib/dracut/hooks/cmdline/01-confluent.sh | 15 +++ .../dracut/hooks/initqueue/01-confluent.sh | 97 +++++++++++++++++++ .../dracut/hooks/pre-pivot/01-confluent.sh | 23 +++++ .../rhvh4/profiles/default/initprofile.sh | 7 ++ .../rhvh4/profiles/default/kickstart | 72 ++++++++++++++ .../rhvh4/profiles/default/profile.yaml | 2 + .../default/scripts/firstboot.service | 11 +++ .../profiles/default/scripts/firstboot.sh | 24 +++++ .../rhvh4/profiles/default/scripts/functions | 14 +++ .../profiles/default/scripts/getinstalldisk | 88 +++++++++++++++++ .../rhvh4/profiles/default/scripts/post.sh | 21 ++++ .../rhvh4/profiles/default/scripts/pre.sh | 59 +++++++++++ .../profiles/default/scripts/prechroot.sh | 20 ++++ .../profiles/default/scripts/setupssh.sh | 23 +++++ .../profiles/default/scripts/tpm_luks.sh | 4 + confluent_server/confluent/osimage.py | 15 +++ 17 files changed, 550 insertions(+) create mode 100644 confluent_osdeploy/rhvh4/initramfs/opt/confluent/bin/apiclient create mode 100644 confluent_osdeploy/rhvh4/initramfs/usr/lib/dracut/hooks/cmdline/01-confluent.sh create mode 100644 confluent_osdeploy/rhvh4/initramfs/usr/lib/dracut/hooks/initqueue/01-confluent.sh create mode 100644 confluent_osdeploy/rhvh4/initramfs/usr/lib/dracut/hooks/pre-pivot/01-confluent.sh create mode 100644 confluent_osdeploy/rhvh4/profiles/default/initprofile.sh create mode 100644 confluent_osdeploy/rhvh4/profiles/default/kickstart create mode 100644 confluent_osdeploy/rhvh4/profiles/default/profile.yaml create mode 100644 confluent_osdeploy/rhvh4/profiles/default/scripts/firstboot.service create mode 100644 confluent_osdeploy/rhvh4/profiles/default/scripts/firstboot.sh create mode 100644 confluent_osdeploy/rhvh4/profiles/default/scripts/functions create mode 100644 confluent_osdeploy/rhvh4/profiles/default/scripts/getinstalldisk create mode 100644 confluent_osdeploy/rhvh4/profiles/default/scripts/post.sh create mode 100644 confluent_osdeploy/rhvh4/profiles/default/scripts/pre.sh create mode 100644 confluent_osdeploy/rhvh4/profiles/default/scripts/prechroot.sh create mode 100644 confluent_osdeploy/rhvh4/profiles/default/scripts/setupssh.sh create mode 100644 confluent_osdeploy/rhvh4/profiles/default/scripts/tpm_luks.sh diff --git a/confluent_osdeploy/rhvh4/initramfs/opt/confluent/bin/apiclient b/confluent_osdeploy/rhvh4/initramfs/opt/confluent/bin/apiclient new file mode 100644 index 00000000..df1ea217 --- /dev/null +++ b/confluent_osdeploy/rhvh4/initramfs/opt/confluent/bin/apiclient @@ -0,0 +1,55 @@ +#!/usr/bin/python +import httplib as client +import socket +import ssl +import sys + +class HTTPSClient(client.HTTPConnection, object): + def __init__(self, port=443): + self.stdheaders = {} + info = open('/etc/confluent/confluent.info').read().split('\n') + for line in info: + if line.startswith('NODENAME:'): + node = line.split(' ')[1] + self.stdheaders['CONFLUENT_NODENAME'] = node + if line.startswith('MANAGER:'): + host = line.split(' ')[1] + self.stdheaders['CONFLUENT_APIKEY'] = open('/etc/confluent/confluent.apikey').read().strip() + client.HTTPConnection.__init__(self, host, port) + self.connect() + + def set_header(self, key, val): + self.stdheaders[key] = val + + def connect(self): + addrinf = socket.getaddrinfo(self.host, self.port)[0] + psock = socket.socket(addrinf[0]) + psock.connect(addrinf[4]) + ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + ctx.load_verify_locations('/etc/confluent/ca.pem') + host = self.host.split('%', 1)[0] + if '[' not in host and ':' in host: + self.stdheaders['Host'] = '[{0}]'.format(host) + else: + self.stdheaders['Host'] = '{0}'.format(host) + ctx.verify_mode = ssl.CERT_REQUIRED + ctx.check_hostname = True + self.sock = ctx.wrap_socket(psock, server_hostname=host) + + def grab_url(self, url, data=None): + if data: + method = 'POST' + else: + method = 'GET' + self.request(method, url, headers=self.stdheaders) + rsp = self.getresponse() + body = rsp.read() + if rsp.status >= 200 and rsp.status < 300: + return body + raise Exception(body) + +if __name__ == '__main__': + data = None + if len(sys.argv) == 3: + data = open(sys.argv[2]).read() + print(HTTPSClient().grab_url(sys.argv[1], data).decode()) diff --git a/confluent_osdeploy/rhvh4/initramfs/usr/lib/dracut/hooks/cmdline/01-confluent.sh b/confluent_osdeploy/rhvh4/initramfs/usr/lib/dracut/hooks/cmdline/01-confluent.sh new file mode 100644 index 00000000..25ba8e61 --- /dev/null +++ b/confluent_osdeploy/rhvh4/initramfs/usr/lib/dracut/hooks/cmdline/01-confluent.sh @@ -0,0 +1,15 @@ +#!/bin/bash +echo -n "" >> /tmp/net.ifaces +cat /tls/*.0 >> /etc/pki/tls/certs/ca-bundle.crt +if ! grep console= /proc/cmdline >& /dev/null; then + autocons=$(/opt/confluent/bin/autocons) + if [ -n "$autocons" ]; then + echo console=$autocons |sed -e 's!/dev/!!' >> /tmp/01-autocons.conf + autocons=${autocons%,*} + echo $autocons > /tmp/01-autocons.devnode + echo "Detected firmware specified console at $(cat /tmp/01-autocons.conf)" > $autocons + echo "Initializing auto detected console when installer starts" > $autocons + fi +fi +. /lib/anaconda-lib.sh +wait_for_kickstart diff --git a/confluent_osdeploy/rhvh4/initramfs/usr/lib/dracut/hooks/initqueue/01-confluent.sh b/confluent_osdeploy/rhvh4/initramfs/usr/lib/dracut/hooks/initqueue/01-confluent.sh new file mode 100644 index 00000000..889468fc --- /dev/null +++ b/confluent_osdeploy/rhvh4/initramfs/usr/lib/dracut/hooks/initqueue/01-confluent.sh @@ -0,0 +1,97 @@ +#!/bin/sh +[ -e /tmp/confluent.initq ] && return 0 +mkdir -p /etc/confluent +cat /tls/*.pem > /etc/confluent/ca.pem +echo -n "" > /tmp/confluent.initq +cd /sys/class/net +for currif in *; do + ip link set $currif up +done +cd - +while ! grep MANAGER /etc/confluent/confluent.info >& /dev/null; do + /opt/confluent/bin/copernicus -t > /etc/confluent/confluent.info +done +read ifidx < /tmp/net.ifaces +nodename=$(grep ^NODENAME /etc/confluent/confluent.info|awk '{print $2}') +#TODO: blkid --label to find mounted api + +if [ -z "$apikey" ]; then + apikey=$(/opt/confluent/bin/clortho $nodename $mgr) +fi +oum=$(umask) +umask 0077 +echo $apikey > /etc/confluent/confluent.apikey +umask $oum +python /opt/confluent/bin/apiclient /confluent-api/self/deploycfg > /tmp/confluent.deploycfg + +dnsdomain=$(grep ^dnsdomain: /tmp/confluent.deploycfg) +dnsdomain=${dnsdomain#dnsdomain: } +hostname=$nodename +if [ ! -z "$dnsdomain" ] && [ "$dnsdomain" != "null" ]; then + hostname=$hostname.$dnsdomain +fi +mgr=$(grep ^deploy_server: /tmp/confluent.deploycfg) +mgr=${mgr#deploy_server: } +profilename=$(grep ^profile: /tmp/confluent.deploycfg) +profilename=${profilename#profile: } +proto=$(grep ^protocol: /tmp/confluent.deploycfg) +proto=${proto#protocol: } +textconsole=$(grep ^textconsole: /tmp/confluent.deploycfg) +textconsole=${textconsole#textconsole: } +if [ $textconsole = "true" ] && ! grep console= /proc/cmdline > /dev/null; then + autocons=$(cat /tmp/01-autocons.devnode) + if [ ! -z "$autocons" ]; then + echo Auto-configuring installed system to use text console + echo Auto-configuring installed system to use text console > $autocons + cp /tmp/01-autocons.conf /etc/cmdline.d/ + else + echo "Unable to automatically detect requested text console" + fi +fi + +echo inst.repo=$proto://$mgr/confluent-public/os/$profilename/distribution >> /etc/cmdline.d/01-confluent.conf +echo inst.ks=$proto://$mgr/confluent-public/os/$profilename/kickstart >> /etc/cmdline.d/01-confluent.conf +kickstart=$proto://$mgr/confluent-public/os/$profilename/kickstart +root=anaconda-net:$proto://$mgr/confluent-public/os/$profilename/distribution +export kickstart +export root +autoconfigmethod=$(grep ipv4_method /tmp/confluent.deploycfg) +autoconfigmethod=${autoconfigmethod#ipv4_method: } +if [ "$autoconfigmethod" = "dhcp" ]; then + echo ip=$ifname:dhcp >> /etc/cmdline.d/01-confluent.conf +else + v4addr=$(grep ^ipv4_address: /tmp/confluent.deploycfg) + v4addr=${v4addr#ipv4_address: } + v4gw=$(grep ^ipv4_gateway: /tmp/confluent.deploycfg) + v4gw=${v4gw#ipv4_gateway: } + if [ "$v4gw" = "null" ]; then + v4gw="" + fi + v4nm=$(grep ipv4_netmask: /tmp/confluent.deploycfg) + v4nm=${v4nm#ipv4_netmask: } + echo ip=$v4addr::$v4gw:$v4nm:$hostname:$ifname:none >> /etc/cmdline.d/01-confluent.conf +fi +nameserversec=0 +while read -r entry; do + if [ $nameserversec = 1 ]; then + if [[ $entry == "-"* ]] && [[ $entry != "- ''" ]]; then + echo nameserver=${entry#- } >> /etc/cmdline.d/01-confluent.conf + continue + fi + fi + nameserversec=0 + if [ "${entry%:*}" = "nameservers" ]; then + nameserversec=1 + continue + fi +done < /tmp/confluent.deploycfg + diff --git a/confluent_osdeploy/rhvh4/initramfs/usr/lib/dracut/hooks/pre-pivot/01-confluent.sh b/confluent_osdeploy/rhvh4/initramfs/usr/lib/dracut/hooks/pre-pivot/01-confluent.sh new file mode 100644 index 00000000..63bf8f55 --- /dev/null +++ b/confluent_osdeploy/rhvh4/initramfs/usr/lib/dracut/hooks/pre-pivot/01-confluent.sh @@ -0,0 +1,23 @@ +#!/bin/bash +BUNDLENAME=/sysroot/etc/pki/tls/certs/ca-bundle.crt +while [ -h $BUNDLENAME ]; do + BUNDLENAME=/sysroot/$(readlink $BUNDLENAME) +done + +cat /etc/pki/tls/certs/ca-bundle.crt > $BUNDLENAME +mkdir -p /sysroot/etc/confluent/ +cp -a /tls /sysroot/etc/confluent +sed -i 's/install::/install:*:/' /sysroot/etc/shadow +sed -i 's/root::/root:*:/' /sysroot/etc/shadow +mkdir -p /sysroot/root/.ssh +chmod 700 /sysroot/root/.ssh +cat /ssh/*.rootpubkey > /sysroot/root/.ssh/authorized_keys +chmod 600 /sysroot/root/.ssh/authorized_keys +mkdir -p /sysroot/etc/ssh/ +for i in /ssh/*.ca; do + echo '@cert-authority *' $(cat $i) >> /sysroot/etc/ssh/ssh_known_hosts +done +cp /etc/confluent.apikey /sysroot/etc/ +cp /etc/confluent.apikey /sysroot/etc/confluent/ +cp /opt/confluent/bin/apiclient /sysroot/etc/confluent +cp /tmp/confluent.deploycfg /etc/confluent/* /sysroot/etc/confluent diff --git a/confluent_osdeploy/rhvh4/profiles/default/initprofile.sh b/confluent_osdeploy/rhvh4/profiles/default/initprofile.sh new file mode 100644 index 00000000..fdea9df3 --- /dev/null +++ b/confluent_osdeploy/rhvh4/profiles/default/initprofile.sh @@ -0,0 +1,7 @@ +#!/bin/sh +sed -i 's/centos/CentOS/; s/rhel/Red Hat Enterprise Linux/' $2/profile.yaml +ln -s $1/images/pxeboot/vmlinuz $2/boot/kernel && \ +ln -s $1/images/pxeboot/initrd.img $2/boot/initramfs/distribution +mkdir -p $2/boot/efi/boot && \ +ln -s $1/EFI/BOOT/BOOTX64.EFI $1/EFI/BOOT/grubx64.efi $2/boot/efi/boot/ + diff --git a/confluent_osdeploy/rhvh4/profiles/default/kickstart b/confluent_osdeploy/rhvh4/profiles/default/kickstart new file mode 100644 index 00000000..c9080ce7 --- /dev/null +++ b/confluent_osdeploy/rhvh4/profiles/default/kickstart @@ -0,0 +1,72 @@ +# In this OS profile, data is largely filled in during the %pre +# phase, rather than the kickstart actually having the content. +# None of the files shall be replaced during an upgrade in +# /var/lib/confluent/public/os/, so customization should +# be done by modifying files in /var/lib/confluent/public/os/ + +# /tmp/rootpw will provide a 'rootpw' line, either locking password if not configured +# or the crypted form. +%include /tmp/rootpw + +# timezone is fetched from confluent server, which provides the +# timezone that the management server itself is in by default. +%include /tmp/timezone + +# similar to timezone, confluent is asked to provide the +# deployment servers language info and replicate that +# to the deployment target. +%include /tmp/langinfo + +# bootloader may be specified if crypted.grubpassword is set on +# a node. This will become a bootloader line if a password +# was specified +%include /tmp/grubpw + +# The default partition scheme is applied to a single drive, using +# the getinstalldisk script to make a best guess as to the most +# appropriate device. See pre.sh and getinstalldisk to customize +# the automatic behavior, or comment out/delete the +# following line and provide your own manual partition plan +# instead +%include /tmp/partitioning + +reboot + +%packages +@^minimal-environment +clevis-dracut +chrony +rsync +python3 +%end + +%pre +profile=$(grep ^profile: /etc/confluent.deploycfg |awk '{print $2}') +mgr=$(grep deploy_server /etc/confluent.deploycfg |awk '{print $2}') +curl -f https://$mgr/confluent-public/os/$profile/scripts/pre.sh > /tmp/preinst.sh +. /tmp/preinst.sh +%end + +%post --nochroot +mkdir -p /mnt/sysimage/etc/confluent +profile=$(grep ^profile: /etc/confluent.deploycfg |awk '{print $2}') +mgr=$(grep deploy_server /etc/confluent.deploycfg |awk '{print $2}') +curl -f https://$mgr/confluent-public/os/$profile/scripts/prechroot.sh > /tmp/postinst.sh +. /tmp/postinst.sh + +# Hook firstboot.sh +curl -f https://$mgr/confluent-public/os/$profile/scripts/firstboot.service > /mnt/sysimage/etc/systemd/system/firstboot.service +curl -f https://$mgr/confluent-public/os/$profile/scripts/firstboot.sh > /mnt/sysimage/etc/confluent/firstboot.sh +chmod +x /mnt/sysimage/etc/confluent/firstboot.sh +%end + +%post +cat /etc/confluent/tls/*.pem >> /etc/pki/tls/certs/ca-bundle.crt +systemctl enable firstboot +chgrp ssh_keys /etc/ssh/ssh*key +restorecon /etc/ssh/ssh*key /root/.shosts /etc/ssh/shosts.equiv /etc/ssh/ssh_config.d/* /etc/confluent/firstboot.sh +profile=$(grep ^profile: /etc/confluent/confluent.deploycfg |awk '{print $2}') +mgr=$(grep deploy_server /etc/confluent/confluent.deploycfg |awk '{print $2}') +curl -f https://$mgr/confluent-public/os/$profile/scripts/post.sh > /tmp/postinst.sh +. /tmp/postinst.sh +%end diff --git a/confluent_osdeploy/rhvh4/profiles/default/profile.yaml b/confluent_osdeploy/rhvh4/profiles/default/profile.yaml new file mode 100644 index 00000000..a582ad16 --- /dev/null +++ b/confluent_osdeploy/rhvh4/profiles/default/profile.yaml @@ -0,0 +1,2 @@ +label: %%DISTRO%% %%VERSION%% %%ARCH%% (Default Profile) +kernelargs: quiet diff --git a/confluent_osdeploy/rhvh4/profiles/default/scripts/firstboot.service b/confluent_osdeploy/rhvh4/profiles/default/scripts/firstboot.service new file mode 100644 index 00000000..0fefec09 --- /dev/null +++ b/confluent_osdeploy/rhvh4/profiles/default/scripts/firstboot.service @@ -0,0 +1,11 @@ +[Unit] +Description=First Boot Process +Requires=network-online.target +After=network-online.target + +[Service] +ExecStart=/etc/confluent/firstboot.sh + +[Install] +WantedBy=multi-user.target + diff --git a/confluent_osdeploy/rhvh4/profiles/default/scripts/firstboot.sh b/confluent_osdeploy/rhvh4/profiles/default/scripts/firstboot.sh new file mode 100644 index 00000000..986ef719 --- /dev/null +++ b/confluent_osdeploy/rhvh4/profiles/default/scripts/firstboot.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +# This script is executed on the first boot after install has +# completed. It is best to edit the middle of the file as +# noted below so custom commands are executed before +# the script notifies confluent that install is fully complete. + +nodename=$(grep ^NODENAME /etc/confluent/confluent.info|awk '{print $2}') +apikey=$(cat /etc/confluent/confluent.apikey) +mgr=$(grep deploy_server /etc/confluent/confluent.deploycfg|awk '{print $2}') +profile=$(grep ^profile: /etc/confluent/confluent.deploycfg|awk '{print $2}') +cat /etc/confluent/tls/*.pem >> /etc/pki/tls/certs/ca-bundle.crt +export nodename mgr profile +. /etc/confluent/functions + + +# Here is the most appropriate place to customize, for example: +#run_remote script.sh +#run_remote_python script.py + + +curl -X POST -d 'status: complete' -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_APIKEY: $apikey" https://$mgr/confluent-api/self/updatestatus +systemctl disable firstboot +rm /etc/systemd/system/firstboot.service diff --git a/confluent_osdeploy/rhvh4/profiles/default/scripts/functions b/confluent_osdeploy/rhvh4/profiles/default/scripts/functions new file mode 100644 index 00000000..c5b9a992 --- /dev/null +++ b/confluent_osdeploy/rhvh4/profiles/default/scripts/functions @@ -0,0 +1,14 @@ +run_remote() { + cd $(mktemp -d) + curl -f https://$mgr/confluent-public/os/$profile/scripts/$1 > $1 + chmod +x $1 + ./$1 + cd - +} + +run_remote_python() { + cd $(mktemp -d) + curl -f https://$mgr/confluent-public/os/$profile/scripts/$1 > $1 + /usr/libexec/platform-python $1 + cd - +} diff --git a/confluent_osdeploy/rhvh4/profiles/default/scripts/getinstalldisk b/confluent_osdeploy/rhvh4/profiles/default/scripts/getinstalldisk new file mode 100644 index 00000000..e4755444 --- /dev/null +++ b/confluent_osdeploy/rhvh4/profiles/default/scripts/getinstalldisk @@ -0,0 +1,88 @@ +import subprocess +import os + +class DiskInfo(object): + def __init__(self, devname): + self.name = devname + self.wwn = None + self.path = None + self.model = '' + self.size = 0 + self.driver = None + self.mdcontainer = '' + devnode = '/dev/{0}'.format(devname) + qprop = subprocess.check_output( + ['udevadm', 'info', '--query=property', devnode]) + if not isinstance(qprop, str): + qprop = qprop.decode('utf8') + for prop in qprop.split('\n'): + if '=' not in prop: + continue + k, v = prop.split('=', 1) + if k == 'DEVTYPE' and v != 'disk': + raise Exception('Not a disk') + elif k == 'DM_NAME': + raise Exception('Device Mapper') + elif k == 'ID_MODEL': + self.model = v + elif k == 'DEVPATH': + self.path = v + elif k == 'ID_WWN': + self.wwn = v + elif k == 'MD_CONTAINER': + self.mdcontainer = v + attrs = subprocess.check_output(['udevadm', 'info', '-a', devnode]) + if not isinstance(attrs, str): + attrs = attrs.decode('utf8') + for attr in attrs.split('\n'): + if '==' not in attr: + continue + k, v = attr.split('==', 1) + k = k.strip() + if k == 'ATTRS{size}': + self.size = v.replace('"', '') + elif (k == 'DRIVERS' and not self.driver + and v not in ('"sd"', '""')): + self.driver = v.replace('"', '') + if not self.driver and 'imsm' not in self.mdcontainer: + raise Exception("No driver detected") + + @property + def priority(self): + if self.model.lower() in ('thinksystem_m.2_vd', 'thinksystem m.2'): + return 0 + if 'imsm' in self.mdcontainer: + return 1 + if self.driver == 'ahci': + return 2 + if self.driver.startswith('megaraid'): + return 3 + if self.driver.startswith('mpt'): + return 4 + return 99 + + def __repr__(self): + return repr({ + 'name': self.name, + 'path': self.path, + 'wwn': self.wwn, + 'driver': self.driver, + 'size': self.size, + 'model': self.model, + }) + + +def main(): + disks = [] + for disk in sorted(os.listdir('/sys/class/block')): + try: + disk = DiskInfo(disk) + disks.append(disk) + except Exception as e: + print("Skipping {0}: {1}".format(disk, str(e))) + nd = [x.name for x in sorted(disks, key=lambda x: x.priority)] + if nd: + open('/tmp/installdisk', 'w').write(nd[0]) + +if __name__ == '__main__': + main() diff --git a/confluent_osdeploy/rhvh4/profiles/default/scripts/post.sh b/confluent_osdeploy/rhvh4/profiles/default/scripts/post.sh new file mode 100644 index 00000000..f258b4b1 --- /dev/null +++ b/confluent_osdeploy/rhvh4/profiles/default/scripts/post.sh @@ -0,0 +1,21 @@ +#!/bin/sh +# need to copy over ssh key info +nodename=$(grep ^NODENAME /etc/confluent/confluent.info|awk '{print $2}') +export mgr profile nodename +. /etc/confluent/functions + +if [ -f /tmp/cryptboot ]; then + run_remote tpm_luks.sh +fi +# This script will execute in the installed system, but using the installer kernel prior to reboot. +# This is an appropriate place to run post install activities that do not require the actual installed +# kernel to run. For example adding drivers that would be needed for first boot to run cleanly. +# If, for example, there is a post script that has a dependency on a driver or filesystem that +# cannot work until booting into the installer, use firstboot.sh instead + +# run_remote will download and execute from /var/lib/confluent/public//scripts/ directory +# run_remote_python will use the appropriate python interpreter path to run the specified script + +# Add content as below: +# run_remote example.sh +# run_remote_python example.py diff --git a/confluent_osdeploy/rhvh4/profiles/default/scripts/pre.sh b/confluent_osdeploy/rhvh4/profiles/default/scripts/pre.sh new file mode 100644 index 00000000..8ee8a8a4 --- /dev/null +++ b/confluent_osdeploy/rhvh4/profiles/default/scripts/pre.sh @@ -0,0 +1,59 @@ +#!/bin/sh + +# This runs prior to the installer beginning. This is used to rewrite the +# scripted install file, merging data from confluennt and identifying +# the most appropriate install source. + +# If you want to use a more custom partition plan, the easiest +# method is to edit the kicktstart file and comment out or +# delete %include /tmp/partitioning + +nodename=$(grep ^NODENAME /etc/confluent.info|awk '{print $2}') +locale=$(grep ^locale: /etc/confluent.deploycfg) +locale=${locale#locale: } +keymap=$(grep ^keymap: /etc/confluent.deploycfg) +keymap=${keymap#keymap: } +echo lang $locale > /tmp/langinfo +echo keyboard --vckeymap=$keymap >> /tmp/langinfo +tz=$(grep ^timezone: /etc/confluent.deploycfg) +tz=${tz#timezone: } +echo timezone $tz --utc > /tmp/timezone +rootpw=$(grep ^rootpassword /etc/confluent.deploycfg | awk '{print $2}') +if [ "$rootpw" = null ]; then + echo "rootpw --lock" > /tmp/rootpw +else + echo "rootpw --iscrypted $rootpw" > /tmp/rootpw +fi +grubpw=$(grep ^grubpassword /etc/confluent.deploycfg | awk '{print $2}') +if [ "$grubpw" = "null" ]; then + touch /tmp/grubpw +else + echo "bootloader --iscrypted --password=$grubpw" > /tmp/grubpw +fi +for pubkey in /etc/ssh/ssh_host*key.pub; do + certfile=${pubkey/.pub/-cert.pub} + curl -f -X POST -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_APIKEY: $(cat /etc/confluent.apikey)" -d @$pubkey https://$mgr/confluent-api/self/sshcert > $certfile + echo HostCertificate $certfile >> /etc/ssh/sshd_config.anaconda +done +/usr/sbin/sshd -f /etc/ssh/sshd_config.anaconda +if [ -f "/run/install/cmdline.d/01-autocons.conf" ]; then + consoledev=$(cat /run/install/cmdline.d/01-autocons.conf | sed -e 's!console=!/dev/!' -e 's/,.*//') + tmux a <> $consoledev >&0 2>&1 & +fi +cryptboot=$(grep ^encryptboot: /etc/confluent.deploycfg | awk '{print $2}') +LUKSPARTY='' +if [ "$cryptboot" == "bound" ]; then + LUKSPARTY="--encrypted --passphrase=$(cat /etc/confluent.apikey)" + echo $cryptboot >> /tmp/cryptboot +fi + + +export mgr profile nodename +curl -f https://$mgr/confluent-public/os/$profile/scripts/functions > /tmp/functions +. /tmp/functions +run_remote_python getinstalldisk +if [ -e /tmp/installdisk ]; then + echo clearpart --all --initlabel >> /tmp/partitioning + echo ignoredisk --only-use $(cat /tmp/installdisk) >> /tmp/partitioning + echo autopart --nohome $LUKSPARTY >> /tmp/partitioning +fi diff --git a/confluent_osdeploy/rhvh4/profiles/default/scripts/prechroot.sh b/confluent_osdeploy/rhvh4/profiles/default/scripts/prechroot.sh new file mode 100644 index 00000000..e4a319cb --- /dev/null +++ b/confluent_osdeploy/rhvh4/profiles/default/scripts/prechroot.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +# This script runs after install is complete, but inside the installer +# environment. This is useful for carrying work done in pre/during the +# installer into the installed environment. + +# It is almost certainly more useful to use post.sh or firstboot.sh +# for customization, which will run in a more normal mechanism + +nodename=$(grep ^NODENAME /etc/confluent.info|awk '{print $2}') +export mgr profile nodename +cp -a /etc/confluent /mnt/sysimage/etc +cp /tmp/functions /mnt/sysimage/etc/confluent/ +. /tmp/functions +cp /tmp/cryptboot /mnt/sysimage/tmp/ + +# Preserve the ssh setup work done for the installer +# by copying into the target system and setting up +# host based authentication +run_remote setupssh.sh diff --git a/confluent_osdeploy/rhvh4/profiles/default/scripts/setupssh.sh b/confluent_osdeploy/rhvh4/profiles/default/scripts/setupssh.sh new file mode 100644 index 00000000..92689c1c --- /dev/null +++ b/confluent_osdeploy/rhvh4/profiles/default/scripts/setupssh.sh @@ -0,0 +1,23 @@ +#!/bin/sh +grep HostCert /etc/ssh/sshd_config.anaconda >> /mnt/sysimage/etc/ssh/sshd_config +echo HostbasedAuthentication yes >> /mnt/sysimage/etc/ssh/sshd_config +echo HostbasedUsesNameFromPacketOnly yes >> /mnt/sysimage/etc/ssh/sshd_config +echo IgnoreRhosts no >> /mnt/sysimage/etc/ssh/sshd_config +sshconf=/etc/ssh/ssh_config +if [ -d /mnt/sysimage/etc/ssh/ssh_config.d/ ]; then + sshconf=/mnt/sysimage/etc/ssh/ssh_config.d/01-confluent.conf +fi +echo 'Host *' >> $sshconf +echo ' HostbasedAuthentication yes' >> $sshconf +echo ' EnableSSHKeysign yes' >> $sshconf +echo ' HostbasedKeyTypes *ed25519*' >> $sshconf + +cp /etc/ssh/ssh_host_* /mnt/sysimage/etc/ssh/ +mkdir /mnt/sysimage/root/.ssh/ +chmod 700 /mnt/sysimage/root/.ssh/ +cp /root/.ssh/authorized_keys /mnt/sysimage/root/.ssh/ +chmod 600 /mnt/sysimage/root/.ssh/authorized_keys +cp /etc/ssh/ssh_known_hosts /mnt/sysimage/etc/ssh/ +curl -f -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_APIKEY: $(cat /etc/confluent.apikey)" https://$mgr/confluent-api/self/nodelist > /tmp/allnodes +cp /tmp/allnodes /mnt/sysimage/etc/ssh/shosts.equiv +cp /tmp/allnodes /mnt/sysimage/root/.shosts diff --git a/confluent_osdeploy/rhvh4/profiles/default/scripts/tpm_luks.sh b/confluent_osdeploy/rhvh4/profiles/default/scripts/tpm_luks.sh new file mode 100644 index 00000000..df9c857f --- /dev/null +++ b/confluent_osdeploy/rhvh4/profiles/default/scripts/tpm_luks.sh @@ -0,0 +1,4 @@ +#!/bin/sh +cryptdisk=$(blkid -t TYPE="crypto_LUKS"|sed -e s/:.*//) +clevis luks bind -f -d $cryptdisk -k - tpm2 '{}' < /etc/confluent/confluent.apikey +cryptsetup luksRemoveKey $cryptdisk < /etc/confluent/confluent.apikey diff --git a/confluent_server/confluent/osimage.py b/confluent_server/confluent/osimage.py index a366cf10..e96f9863 100644 --- a/confluent_server/confluent/osimage.py +++ b/confluent_server/confluent/osimage.py @@ -334,6 +334,21 @@ def check_rhel(isoinfo): arch = entry.split('.')[-2] break else: + if '.discinfo' in isoinfo[1]: + prodinfo = isoinfo[1]['.discinfo'] + if not isinstance(prodinfo, str): + prodinfo = prodinfo.decode('utf8') + prodinfo = prodinfo.split('\n') + if len(prodinfo) < 3: + return None + arch = prodinfo[2] + prodinfo = prodinfo[1].split(' ') + if len(prodinfo) < 2 or prodinfo[0] != 'RHVH': + return None + major = prodinfo[1].split('.')[0] + cat = 'rhvh{0}'.format(major) + return {'name': 'rhvh-{0}-{1}'.format(prodinfo[1], arch), + 'method': EXTRACT, 'category': cat} return None major = ver.split('.', 1)[0] return {'name': 'rhel-{0}-{1}'.format(ver, arch), 'method': EXTRACT, 'category': 'el{0}'.format(major)}