diff --git a/Makefile b/Makefile index bed8b130..d635833d 100644 --- a/Makefile +++ b/Makefile @@ -52,7 +52,7 @@ files: all # cp -r tftpboot/* /var/lib/tftpboot/warewulf/ipxe/ # restorecon -r /var/lib/tftpboot/warewulf cp -r overlays /var/warewulf/ - chmod +x /var/warewulf/overlays/system/default/init.ww + chmod +x /var/warewulf/overlays/system/default/init chmod 600 /var/warewulf/overlays/system/default/etc/ssh/ssh* chmod 644 /var/warewulf/overlays/system/default/etc/ssh/ssh*.pub.ww mkdir -p /var/warewulf/overlays/system/default/warewulf/bin/ diff --git a/README.md b/README.md index 622465d7..c9d011b3 100644 --- a/README.md +++ b/README.md @@ -174,7 +174,7 @@ sudo ./wwctl overlay list -ls sudo EDITOR=vim ./wwctl overlay edit default /etc/hello_world.ww sudo ./wwctl overlay build -a ``` - + #### Start the Warewulf daemon: Once the above provisioning images are built, you can check the provisioning "rediness" 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/overlay/edit/main.go b/internal/app/wwctl/overlay/edit/main.go index 1ede83ae..269815ff 100644 --- a/internal/app/wwctl/overlay/edit/main.go +++ b/internal/app/wwctl/overlay/edit/main.go @@ -17,6 +17,10 @@ func CobraRunE(cmd *cobra.Command, args []string) error { editor := os.Getenv("EDITOR") var overlaySourceDir string + if editor == "" { + editor = "vi" + } + if SystemOverlay == true { overlaySourceDir = config.SystemOverlaySource(args[0]) } else { 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 b/overlays/system/default/init new file mode 100755 index 00000000..58c60bfb --- /dev/null +++ b/overlays/system/default/init @@ -0,0 +1,56 @@ +#!/bin/sh +# +# This is one of those types of files that you shouldn't edit unless you really +# know what you are doing and even then you should make a backup. +# +# Edit at your own risk! DANGER DANGER. + + +if test -f "/warewulf/config"; then + . /warewulf/config +else + echo "ERROR: Warewulf configuration file not found... rebooting in 1 minute" + sleep 60 + /sbin/reboot +fi + +echo "Warewulf v4 is now booting: $WWHOSTNAME" +echo + +echo "Mounting up kernel file systems" +mkdir /proc /dev /sys /run 2>/dev/null +mount -t proc proc /proc +mount -t devtmpfs devtmpfs /dev +mount -t sysfs sysfs /sys +mount -t tmpfs tmpfs /run + +chmod 755 /warewulf/wwinit + +echo "Checking Rootfs type" +ROOTFSTYPE=`stat -f -c "%T" /` + +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 +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/init.ww b/overlays/system/default/init.ww deleted file mode 100755 index a05f3148..00000000 --- a/overlays/system/default/init.ww +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/sh -# -# This is one of those types of files that you shouldn't edit unless you really -# know what you are doing and even then you should make a backup. -# -# Edit at your own risk! DANGER DANGER. - - -echo "Warewulf v4 is now booting" - -chmod 755 /warewulf/wwinit - -echo "Mounting up kernel file systems" -mkdir /proc /dev /sys /run 2>/dev/null -mount -t proc proc /proc -mount -t devtmpfs devtmpfs /dev -mount -t sysfs sysfs /sys -mount -t tmpfs tmpfs /run - -echo "Checking for 'rootfstype=ramfs'" -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" - echo "Calling WW Init" - exec /warewulf/wwinit -fi - -echo "We should never ever get here, but since we did, it means something went wrong so rebooting" -/sbin/reboot \ No newline at end of file diff --git a/overlays/system/default/warewulf/config.ww b/overlays/system/default/warewulf/config.ww new file mode 100644 index 00000000..5a33472a --- /dev/null +++ b/overlays/system/default/warewulf/config.ww @@ -0,0 +1,9 @@ +WWCONTAINER={{$.Container}} +WWHOSTNAME={{$.Id}} +WWROOT={{$.Root}} +WWINIT={{$.Init}} +WWIPMI_IPADDR="{{$.IpmiIpaddr}}" +WWIPMI_NETMASK="{{$.IpmiNetmask}}" +WWIPMI_GATEWAY="{{$.IpmiGateway}}" +WWIPMI_USER="{{$.IpmiUserName}}" +WWIPMI_PASSWORD="{{$.IpmiPassword}}" diff --git a/overlays/system/default/warewulf/init.d/20-localhost b/overlays/system/default/warewulf/init.d/20-loopback similarity index 78% rename from overlays/system/default/warewulf/init.d/20-localhost rename to overlays/system/default/warewulf/init.d/20-loopback index 5c000de3..01791174 100644 --- a/overlays/system/default/warewulf/init.d/20-localhost +++ b/overlays/system/default/warewulf/init.d/20-loopback @@ -1,4 +1,6 @@ #!/bin/sh +. /warewulf/config + echo "Bringing up lo:127.0.0.1" /sbin/ip link set dev lo up diff --git a/overlays/system/default/warewulf/init.d/50-ipmi.ww b/overlays/system/default/warewulf/init.d/50-ipmi similarity index 62% rename from overlays/system/default/warewulf/init.d/50-ipmi.ww rename to overlays/system/default/warewulf/init.d/50-ipmi index 39dbafc2..0a2b3c88 100755 --- a/overlays/system/default/warewulf/init.d/50-ipmi.ww +++ b/overlays/system/default/warewulf/init.d/50-ipmi @@ -1,28 +1,26 @@ #!/bin/bash -error_exit() { - echo "ERROR: $*" - exit 1 -} +. /warewulf/config 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 +if [ -z "$WWIPMI_NETMASK" ]; then + echo "No IPMI netmask 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 +44,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/75-vnfs_fixes b/overlays/system/default/warewulf/init.d/75-vnfs_fixes index 1674d8d8..5ce5b735 100644 --- a/overlays/system/default/warewulf/init.d/75-vnfs_fixes +++ b/overlays/system/default/warewulf/init.d/75-vnfs_fixes @@ -1,6 +1,6 @@ #!/bin/sh - +. /warewulf/config # This will eventually be optional if true; then diff --git a/overlays/system/default/warewulf/init.d/80-wwclient b/overlays/system/default/warewulf/init.d/80-wwclient index 0563a5b9..184dac4e 100644 --- a/overlays/system/default/warewulf/init.d/80-wwclient +++ b/overlays/system/default/warewulf/init.d/80-wwclient @@ -1,4 +1,6 @@ #!/bin/sh +. /warewulf/config + echo "Starting wwclient" nohup /warewulf/bin/wwclient >/var/log/wwclient.log 2>&1