From e5be3d8182c42dd71c387c32a55e55388291e3c5 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Sun, 20 Dec 2020 22:41:02 -0800 Subject: [PATCH] Cleaned init subsystem, Ipmi, SELinux, added Root option, and fixed defaults --- internal/app/wwctl/node/list/main.go | 1 + internal/app/wwctl/node/set/main.go | 10 ++++ internal/app/wwctl/node/set/root.go | 3 ++ internal/app/wwctl/profile/list/main.go | 1 + internal/app/wwctl/profile/set/main.go | 10 ++++ internal/app/wwctl/profile/set/root.go | 2 + internal/pkg/node/constructors.go | 5 ++ internal/pkg/node/datastructure.go | 3 +- internal/pkg/node/modifiers.go | 2 + internal/pkg/overlay/overlay.go | 2 + overlays/system/default/init.ww | 49 ++++++++++++------ .../warewulf/init.d/{50-ipmi.ww => 50-ipmi} | 50 ++++++++----------- .../system/default/warewulf/init.d/90-selinux | 37 ++++++++++---- overlays/system/default/warewulf/wwinit.ww | 8 +++ 14 files changed, 128 insertions(+), 55 deletions(-) rename overlays/system/default/warewulf/init.d/{50-ipmi.ww => 50-ipmi} (65%) diff --git a/internal/app/wwctl/node/list/main.go b/internal/app/wwctl/node/list/main.go index 342e672e..26cd4e59 100644 --- a/internal/app/wwctl/node/list/main.go +++ b/internal/app/wwctl/node/list/main.go @@ -60,6 +60,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "SystemOverlay", node.SystemOverlay.Source(), node.SystemOverlay.Print()) fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "Ipxe", node.Ipxe.Source(), node.Ipxe.Print()) fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "Init", node.Init.Source(), node.Init.Print()) + fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "Root", node.Root.Source(), node.Root.Print()) fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "IpmiIpaddr", node.IpmiIpaddr.Source(), node.IpmiIpaddr.Print()) fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "IpmiNetmask", node.IpmiNetmask.Source(), node.IpmiNetmask.Print()) fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "IpmiGateway", node.IpmiGateway.Source(), node.IpmiGateway.Print()) diff --git a/internal/app/wwctl/node/set/main.go b/internal/app/wwctl/node/set/main.go index f8641b24..53dc56c7 100644 --- a/internal/app/wwctl/node/set/main.go +++ b/internal/app/wwctl/node/set/main.go @@ -94,6 +94,16 @@ func CobraRunE(cmd *cobra.Command, args []string) error { os.Exit(1) } } + if SetRoot != "" { + wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting root to: %s\n", n.Id.Get(), SetRoot) + + n.Root.Set(SetRoot) + err := nodeDB.NodeUpdate(n) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } if SetKernel != "" { wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting kernel to: %s\n", n.Id.Get(), SetKernel) diff --git a/internal/app/wwctl/node/set/root.go b/internal/app/wwctl/node/set/root.go index 47e9b32e..baca87eb 100644 --- a/internal/app/wwctl/node/set/root.go +++ b/internal/app/wwctl/node/set/root.go @@ -35,6 +35,7 @@ var ( SetInit string SetDiscoverable bool SetUndiscoverable bool + SetRoot string ) func init() { @@ -44,6 +45,8 @@ func init() { baseCmd.PersistentFlags().StringVarP(&SetClusterName, "cluster", "c", "", "Set the node's cluster group") baseCmd.PersistentFlags().StringVarP(&SetIpxe, "ipxe", "P", "", "Set the node's iPXE template name") baseCmd.PersistentFlags().StringVarP(&SetInit, "init", "i", "", "Define the init process to boot the container") + baseCmd.PersistentFlags().StringVar(&SetRoot, "root", "", "Define the rootfs") + baseCmd.PersistentFlags().StringVarP(&SetRuntimeOverlay, "runtime", "R", "", "Set the node's runtime overlay") baseCmd.PersistentFlags().StringVarP(&SetSystemOverlay, "system", "S", "", "Set the node's system overlay") baseCmd.PersistentFlags().StringVar(&SetIpmiIpaddr, "ipmi", "", "Set the node's IPMI IP address") diff --git a/internal/app/wwctl/profile/list/main.go b/internal/app/wwctl/profile/list/main.go index 950ca775..fb3527f7 100644 --- a/internal/app/wwctl/profile/list/main.go +++ b/internal/app/wwctl/profile/list/main.go @@ -41,6 +41,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "KernelVersion", profile.KernelVersion.Print()) fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "KernelArgs", profile.KernelArgs.Print()) fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "Init", profile.Init.Print()) + fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "Root", profile.Root.Print()) fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "RuntimeOverlay", profile.RuntimeOverlay.Print()) fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "SystemOverlay", profile.SystemOverlay.Print()) diff --git a/internal/app/wwctl/profile/set/main.go b/internal/app/wwctl/profile/set/main.go index af3305d3..90c420be 100644 --- a/internal/app/wwctl/profile/set/main.go +++ b/internal/app/wwctl/profile/set/main.go @@ -108,6 +108,16 @@ func CobraRunE(cmd *cobra.Command, args []string) error { os.Exit(1) } } + if SetRoot != "" { + wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting root to: %s\n", p.Id, SetRoot) + + p.Root.Set(SetRoot) + err := nodeDB.ProfileUpdate(p) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } if SetKernel != "" { wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting Kernel version to: %s\n", p.Id, SetKernel) diff --git a/internal/app/wwctl/profile/set/root.go b/internal/app/wwctl/profile/set/root.go index aec9a78f..733685c6 100644 --- a/internal/app/wwctl/profile/set/root.go +++ b/internal/app/wwctl/profile/set/root.go @@ -29,6 +29,7 @@ var ( SetHwaddr string SetNetDevDel bool SetInit string + SetRoot string ) func init() { @@ -38,6 +39,7 @@ func init() { baseCmd.PersistentFlags().StringVarP(&SetClusterName, "cluster", "c", "", "Set the node's cluster group") baseCmd.PersistentFlags().StringVarP(&SetIpxe, "ipxe", "P", "", "Set the node's iPXE template name") baseCmd.PersistentFlags().StringVarP(&SetInit, "init", "i", "", "Define the init process to boot the container") + baseCmd.PersistentFlags().StringVar(&SetRoot, "root", "", "Define the rootfs") baseCmd.PersistentFlags().StringVarP(&SetRuntimeOverlay, "runtime", "R", "", "Set the node's runtime overlay") baseCmd.PersistentFlags().StringVarP(&SetSystemOverlay, "system", "S", "", "Set the node's system overlay") diff --git a/internal/pkg/node/constructors.go b/internal/pkg/node/constructors.go index 4dbd2e1c..aeb3113e 100644 --- a/internal/pkg/node/constructors.go +++ b/internal/pkg/node/constructors.go @@ -47,6 +47,8 @@ func (self *nodeYaml) FindAllNodes() ([]NodeInfo, error) { n.RuntimeOverlay.SetDefault("default") n.Ipxe.SetDefault("default") n.Init.SetDefault("/sbin/init") + n.Root.SetDefault("tmpfs") + n.KernelArgs.SetDefault("rootfstype=ramfs crashkernel=no vga=791 quiet") fullname := strings.SplitN(nodename, ".", 2) if len(fullname) > 1 { @@ -74,6 +76,7 @@ func (self *nodeYaml) FindAllNodes() ([]NodeInfo, error) { n.IpmiPassword.Set(node.IpmiPassword) n.SystemOverlay.Set(node.SystemOverlay) n.RuntimeOverlay.Set(node.RuntimeOverlay) + n.Root.Set(node.Root) n.Discoverable.SetB(node.Discoverable) n.Disabled.SetB(node.Disabled) @@ -116,6 +119,7 @@ func (self *nodeYaml) FindAllNodes() ([]NodeInfo, error) { n.IpmiPassword.SetAlt(self.NodeProfiles[p].IpmiPassword, pstring) n.SystemOverlay.SetAlt(self.NodeProfiles[p].SystemOverlay, pstring) n.RuntimeOverlay.SetAlt(self.NodeProfiles[p].RuntimeOverlay, pstring) + n.Root.SetAlt(self.NodeProfiles[p].Root, pstring) n.Disabled.SetAltB(self.NodeProfiles[p].Disabled, pstring) n.Discoverable.SetAltB(self.NodeProfiles[p].Discoverable, pstring) @@ -163,6 +167,7 @@ func (self *nodeYaml) FindAllProfiles() ([]NodeInfo, error) { p.IpmiPassword.Set(profile.IpmiPassword) p.RuntimeOverlay.Set(profile.RuntimeOverlay) p.SystemOverlay.Set(profile.SystemOverlay) + p.Root.Set(profile.Root) p.Disabled.SetB(profile.Disabled) p.Discoverable.SetB(profile.Discoverable) diff --git a/internal/pkg/node/datastructure.go b/internal/pkg/node/datastructure.go index df9765c3..2e914b02 100644 --- a/internal/pkg/node/datastructure.go +++ b/internal/pkg/node/datastructure.go @@ -32,6 +32,7 @@ type NodeConf struct { RuntimeOverlay string `yaml:"runtime overlay,omitempty"` SystemOverlay string `yaml:"system overlay,omitempty"` Init string `yaml:"init,omitempty"` + Root string `yaml:"root,omitempty"` Discoverable bool `yaml:"discoverable,omitempty"` Profiles []string `yaml:"profiles,omitempty"` NetDevs map[string]*NetDevs `yaml:"network devices,omitempty"` @@ -75,6 +76,7 @@ type NodeInfo struct { IpmiPassword Entry RuntimeOverlay Entry SystemOverlay Entry + Root Entry Discoverable Entry Disabled Entry Init Entry //TODO: Finish adding this... @@ -104,7 +106,6 @@ func init() { fmt.Fprintf(c, "nodeprofiles:\n") fmt.Fprintf(c, " default:\n") fmt.Fprintf(c, " comment: This profile is automatically included for each node\n") - fmt.Fprintf(c, " kernel args: crashkernel=no vga=791 rootfstype=ramfs quiet\n") fmt.Fprintf(c, "nodes: {}\n") c.Close() diff --git a/internal/pkg/node/modifiers.go b/internal/pkg/node/modifiers.go index 2eeaef69..102488bf 100644 --- a/internal/pkg/node/modifiers.go +++ b/internal/pkg/node/modifiers.go @@ -67,6 +67,7 @@ func (self *nodeYaml) NodeUpdate(node NodeInfo) error { self.Nodes[nodeID].IpmiPassword = node.IpmiPassword.GetReal() self.Nodes[nodeID].RuntimeOverlay = node.RuntimeOverlay.GetReal() self.Nodes[nodeID].SystemOverlay = node.SystemOverlay.GetReal() + self.Nodes[nodeID].Root = node.Root.GetReal() self.Nodes[nodeID].Disabled = node.Disabled.GetRealB() self.Nodes[nodeID].Discoverable = node.Discoverable.GetRealB() @@ -144,6 +145,7 @@ func (self *nodeYaml) ProfileUpdate(profile NodeInfo) error { self.NodeProfiles[profileID].IpmiPassword = profile.IpmiPassword.GetReal() self.NodeProfiles[profileID].RuntimeOverlay = profile.RuntimeOverlay.GetReal() self.NodeProfiles[profileID].SystemOverlay = profile.SystemOverlay.GetReal() + self.NodeProfiles[profileID].Root = profile.Root.GetReal() self.NodeProfiles[profileID].Disabled = profile.Disabled.GetRealB() self.NodeProfiles[profileID].Discoverable = profile.Discoverable.GetRealB() diff --git a/internal/pkg/overlay/overlay.go b/internal/pkg/overlay/overlay.go index 419d8a57..3bbe5bc0 100644 --- a/internal/pkg/overlay/overlay.go +++ b/internal/pkg/overlay/overlay.go @@ -23,6 +23,7 @@ type TemplateStruct struct { GroupName string Container string Init string + Root string IpmiIpaddr string IpmiNetmask string IpmiGateway string @@ -139,6 +140,7 @@ func buildOverlay(nodeList []node.NodeInfo, overlayType string) error { t.Hostname = n.Id.Get() t.Container = n.ContainerName.Get() t.Init = n.Init.Get() + t.Root = n.Root.Get() t.IpmiIpaddr = n.IpmiIpaddr.Get() t.IpmiNetmask = n.IpmiNetmask.Get() t.IpmiGateway = n.IpmiGateway.Get() diff --git a/overlays/system/default/init.ww b/overlays/system/default/init.ww index a05f3148..cd231ee7 100755 --- a/overlays/system/default/init.ww +++ b/overlays/system/default/init.ww @@ -5,10 +5,19 @@ # # Edit at your own risk! DANGER DANGER. +WWCONTAINER={{$.Container}} +WWHOSTNAME={{$.Id}} +WWROOT={{$.Root}} +WWIPMI_IPADDR="{{$.IpmiIpaddr}}" +WWIPMI_NETMASK="{{$.IpmiNetmask}}" +WWIPMI_GATEWAY="{{$.IpmiGateway}}" +WWIPMI_USER="{{$.IpmiUserName}}" +WWIPMI_PASSWORD="{{$.IpmiPassword}}" -echo "Warewulf v4 is now booting" +export WWCONTAINER WWHOSTNAME WWROOT -chmod 755 /warewulf/wwinit +echo "Warewulf v4 is now booting: $WWHOSTNAME" +echo echo "Mounting up kernel file systems" mkdir /proc /dev /sys /run 2>/dev/null @@ -17,23 +26,33 @@ mount -t devtmpfs devtmpfs /dev mount -t sysfs sysfs /sys mount -t tmpfs tmpfs /run -echo "Checking for 'rootfstype=ramfs'" +chmod 755 /warewulf/wwinit + +echo "Checking Rootfs type" ROOTFSTYPE=`stat -f -c "%T" /` -if test "$ROOTFSTYPE" == "ramfs"; then - echo "Running on ramfs, setting up tmpfs" - mkdir /newroot - mount wwroot /newroot -t tmpfs - echo "Moving RAMFS to TMPFS" - tar -cf - --exclude ./proc --exclude ./sys --exclude ./dev --exclude ./newroot . | tar -xf - -C /newroot - mkdir /newroot/proc /newroot/dev /newroot/sys /newroot/run 2>/dev/null - echo "Calling switch_root() and invoking WW Init" - exec /sbin/switch_root /newroot /warewulf/wwinit -else - echo "Running on tmpfs" +if test "$WWROOT" == "initramfs"; then + echo "Provisioned to Rootfs type: $ROOTFSTYPE" echo "Calling WW Init" exec /warewulf/wwinit +elif test "$WWROOT" == "tmpfs"; then + if test "$ROOTFSTYPE" == "tmpfs"; then + echo "ERROR: Switching the root file system requires the kernel argument: 'rootfstype=ramfs'" + else + echo "Setting up tmpfs root file system" + mkdir /newroot + mount wwroot /newroot -t tmpfs + echo "Moving RAMFS to TMPFS" + tar -cf - --exclude ./proc --exclude ./sys --exclude ./dev --exclude ./newroot . | tar -xf - -C /newroot + mkdir /newroot/proc /newroot/dev /newroot/sys /newroot/run 2>/dev/null + echo "Calling switch_root and invoking WW Init" + exec /sbin/switch_root /newroot /warewulf/wwinit + fi +else + echo "ERROR: Unknown Warewulf Root file system: $WWROOT" fi -echo "We should never ever get here, but since we did, it means something went wrong so rebooting" +echo +echo "There was a problem with the provisioning process, rebooting in 1 minute..." +sleep 60 /sbin/reboot \ No newline at end of file diff --git a/overlays/system/default/warewulf/init.d/50-ipmi.ww b/overlays/system/default/warewulf/init.d/50-ipmi similarity index 65% rename from overlays/system/default/warewulf/init.d/50-ipmi.ww rename to overlays/system/default/warewulf/init.d/50-ipmi index 39dbafc2..ee6596e7 100755 --- a/overlays/system/default/warewulf/init.d/50-ipmi.ww +++ b/overlays/system/default/warewulf/init.d/50-ipmi @@ -1,28 +1,20 @@ #!/bin/bash -error_exit() { - echo "ERROR: $*" - exit 1 -} - export PATH=/usr/bin:/bin:/usr/sbin:/sbin -IP="{{$.IpmiIpaddr}}" -NETMASK="{{$.IpmiNetmask}}" -[ -z "$NETMASK" ] && NETMASK="{{$.NetDevs.eth0.Netmask}}" -GATEWAY="{{$.IpmiGateway}}" -[ -z "$GATEWAY" ] && GATEWAY="{{$.NetDevs.eth0.Gateway}}" -USER="{{$.IpmiUserName}}" -PASS="{{$.IpmiPassword}}" +if [ -z "$WWIPMI_IPADDR" ]; then + echo "No IPMI IP address supplied, skipping IPMI configuration" + exit +fi -echo IP is $IP -echo NETMASK is $NETMASK -echo GATEWAY is $GATEWAY -echo USER is $USER -echo PASS is $PASS - -if [ -z "$IP" ]; then - error_exit "No IPMI IP address supplied, skipping IPMI configuration" +echo "IPMI IP address: $WWIPMI_IPADDR" +echo "IPMI netmask: $WWIPMI_NETMASK" +echo "IPMI gateway: $WWIPMI_GATEWAY" +echo "IPMI username: $WWIPMI_USER" +if test -n "$WWIPMI_PASSWORD"; then + echo "IPMI password is defined" +else + echo "IPMI password is undefined" fi modprobe ipmi_si @@ -46,21 +38,21 @@ echo PREV_NETMASK is $PREV_NETMASK echo PREV_GATEWAY is $PREV_GATEWAY # Network -if [ "$PREV_IP" != "$IP" -o "$PREV_NETMASK" != "$NETMASK" -o "$PREV_GATEWAY" != "$GATEWAY" ]; then +if [ "$PREV_IP" != "$WWIPMI_IPADDR" -o "$PREV_NETMASK" != "$WWIPMI_NETMASK" -o "$PREV_GATEWAY" != "$WWIPMI_GATEWAY" ]; then ipmitool lan set 1 access on ipmitool lan set 1 ipsrc static - ipmitool lan set 1 ipaddr $IP - ipmitool lan set 1 netmask $NETMASK - ipmitool lan set 1 defgw ipaddr $GATEWAY + ipmitool lan set 1 ipaddr $WWIPMI_IPADDR + ipmitool lan set 1 netmask $WWIPMI_NETMASK + ipmitool lan set 1 defgw ipaddr $WWIPMI_GATEWAY fi # User -if [ "$USER" != "" ]; then +if [ "$WWIPMI_USER" != "" ]; then PREV_USER=$(ipmitool user list | grep "^2 " | awk '{ print $2; }') - TEST_PASSWORD=$(ipmitool user test 2 20 $PASS) - if [ "$USER" != "$PREV_USER" -o "$TEST_PASSWORD" != "Success" ]; then - ipmitool user set name 2 $USER - ipmitool user set password 2 $PASS + TEST_PASSWORD=$(ipmitool user test 2 20 $WWIPMI_PASSWORD) + if [ "$WWIPMI_USER" != "$PREV_USER" -o "$TEST_PASSWORD" != "Success" ]; then + ipmitool user set name 2 $WWIPMI_USER + ipmitool user set password 2 $WWIPMI_PASSWORD sleep 1 ipmitool user priv 2 4 1 ipmitool user enable 2 diff --git a/overlays/system/default/warewulf/init.d/90-selinux b/overlays/system/default/warewulf/init.d/90-selinux index 9154c545..5d9280aa 100644 --- a/overlays/system/default/warewulf/init.d/90-selinux +++ b/overlays/system/default/warewulf/init.d/90-selinux @@ -1,17 +1,34 @@ #!/bin/bash +if test -z "$WWROOT"; then + echo "Skipping SELinux configuration: Warewulf Root device not set" + exit +fi + if test -f "/etc/sysconfig/selinux"; then . /etc/sysconfig/selinux - if test "\$SELINUX" == "disabled"; then - echo "Skipping SELinux setup per /etc/sysconfig/selinux" - elif grep -q "selinux=0" /proc/cmdline; then - echo "Skipping SELinux setup per kernel command line" - else - echo "Setting up SELinux" - /sbin/load_policy -i - /sbin/restorecon -r / - fi else - echo "Skipping SELinux setup" + echo "Skipping SELinux configuration: Host config not found: /etc/sysconfig/selinux" + exit +fi + +if test "$WWROOT" == "initramfs"; then + echo "Skipping SELinux configuration: 'Root=initramfs'" + if test "$SELINUX" != "disabled"; then + echo "WARNING: SELinux prep is being skipped, but SELinux is enabled on host! This may" + echo "WARNING: cause the system to not work properly. Try setting 'Root=tmpfs'" + sleep 5 + fi + exit +fi + +if test "$SELINUX" == "disabled"; then + echo "Skipping SELinux setup per /etc/sysconfig/selinux" +elif grep -q "selinux=0" /proc/cmdline; then + echo "Skipping SELinux setup per kernel command line" +else + echo "Setting up SELinux" + /sbin/load_policy -i + /sbin/restorecon -r / fi diff --git a/overlays/system/default/warewulf/wwinit.ww b/overlays/system/default/warewulf/wwinit.ww index 2b2c728e..0a8c94fa 100644 --- a/overlays/system/default/warewulf/wwinit.ww +++ b/overlays/system/default/warewulf/wwinit.ww @@ -11,6 +11,14 @@ done /bin/bash echo "Cleaning up" +unset WWCONTAINER +unset WWHOSTNAME +unset WWROOT +unset WWIPMI_IPADDR +unset WWIPMI_NETMASK +unset WWIPMI_GATEWAY +unset WWIPMI_USER +unset WWIPMI_PASSWORD echo "Calling {{$.Init}}..." echo