diff --git a/Makefile b/Makefile index 5fc220e8..73f5a59f 100644 --- a/Makefile +++ b/Makefile @@ -5,10 +5,12 @@ all: warewulfd wwbuild wwclient files: all install -d -m 0755 /var/warewulf/ install -d -m 0755 /etc/warewulf/ - install -d -m 0755 /var/lib/tftpboot/warewulf/ipxe/ + install -d -m 0755 /etc/warewulf/ipxe + install -d -m 0755 /var/lib/tftpboot/warewulf/pxe/ install -m 0640 etc/dhcpd.conf /etc/dhcp/dhcpd.conf - install -m 0640 etc/nodes.conf /etc/warewulf/nodes.conf - install -m 0640 etc/warewulf.conf /etc/warewulf/warewulf.conf + install -m 0644 etc/nodes.conf /etc/warewulf/nodes.conf + install -m 0644 etc/warewulf.conf /etc/warewulf/warewulf.conf + install -m 0644 etc/ipxe/default.ipxe /etc/warewulf/ipxe/default.ipxe cp -r tftpboot/* /var/lib/tftpboot/warewulf/ipxe/ cp -r overlays /var/warewulf/ chmod +x /var/warewulf/overlays/system/default/init diff --git a/README.md b/README.md index ff374d5b..e0f49896 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,18 @@ -# warewulf +# warewulf v4 WIP This is built on CentOS-7. More needs to be done to make it work on other distributions and versions specifically with the system service -compoenents. +components. -In a nutshell, to use: +In a nutshell, to install and start provisioning nodes, do the following: -1. make install -2. build VNFS `sudo singularity build --sandbox /var/chroots/centos-7 centos-7.def` -3. Edit `/etc/warewulf/nodes.yaml` -4. Run the following commands: - a. `./wwbuild vnfs` - b. `./wwbuild kernel` - c. `./wwbuild overlay` - c. `./warewulfd` -5. Boot your node and watch the console and the output of the Warewulfd process +1. `make` +2. `sudo make install` +3. `vi /etc/warewulf/warewulf.conf` +4. `vi /etc/warewulf/nodes.conf` +5. `sudo singularity build --sandbox /var/chroots/centos-7 centos-7.def` +6. `sudo ./wwbuild vnfs` +7. `sudo ./wwbuild kernel` +8. `sudo ./wwbuild overlay` +9. `./warewulfd` +10. Boot your compute node \ No newline at end of file diff --git a/cmd/warewulfd/ipxe.go b/cmd/warewulfd/ipxe.go index e26ee84b..c3f7a0b1 100644 --- a/cmd/warewulfd/ipxe.go +++ b/cmd/warewulfd/ipxe.go @@ -1,10 +1,14 @@ package main import ( + "bufio" "fmt" "github.com/hpcng/warewulf/internal/pkg/assets" + "github.com/hpcng/warewulf/internal/pkg/config" "log" "net/http" + "os" + "strconv" "strings" ) @@ -25,17 +29,35 @@ func ipxe(w http.ResponseWriter, req *http.Request) { } if node.HostName != "" { - log.Printf("IPXE: %15s: hwaddr=%s\n", node.Fqdn, hwaddr) + replace := make(map[string]string) - fmt.Fprintf(w, "#!ipxe\n") + conf, err := config.New() + if err != nil { + log.Printf("Could not get config: %s\n", err) + return + } + + ipxeTemplate := fmt.Sprintf("/etc/warewulf/ipxe/%s.ipxe", node.Ipxe) + sourceFD, err := os.Open(ipxeTemplate) + if err != nil { + log.Printf("ERROR: Could not open iPXE Template: %s\n", err) + w.WriteHeader(404) + return + } + + scanner := bufio.NewScanner(sourceFD) + + for scanner.Scan() { + newLine := scanner.Text() + + newLine = strings.ReplaceAll(newLine, "@HWADDR@", url[2]) + newLine = strings.ReplaceAll(newLine, "@IPADDR@", conf.Ipaddr) + newLine = strings.ReplaceAll(newLine, "@HOSTNAME@", node.HostName) + newLine = strings.ReplaceAll(newLine, "@PORT@", strconv.Itoa(conf.Port)) + + fmt.Fprintln(w, newLine) + } - fmt.Fprintf(w, "echo Now booting Warewulf - v4 Proof of Concept\n") - fmt.Fprintf(w, "set base http://192.168.1.1:9873/\n") - fmt.Fprintf(w, "kernel ${base}/kernel/%s crashkernel=no quiet\n", url[2]) - fmt.Fprintf(w, "initrd ${base}/vnfs/%s\n", url[2]) - fmt.Fprintf(w, "initrd ${base}/kmods/%s\n", url[2]) - fmt.Fprintf(w, "initrd ${base}/overlay-system/%s\n", url[2]) - fmt.Fprintf(w, "boot\n") } else { log.Printf("ERROR: iPXE request from unknown Node (hwaddr=%s)\n", url[2]) } diff --git a/cmd/warewulfd/runtime.go b/cmd/warewulfd/runtime.go index 3ff885b5..0cc793f7 100644 --- a/cmd/warewulfd/runtime.go +++ b/cmd/warewulfd/runtime.go @@ -3,6 +3,7 @@ package main import ( "fmt" "github.com/hpcng/warewulf/internal/pkg/assets" + "github.com/hpcng/warewulf/internal/pkg/config" "log" "net/http" "strconv" @@ -10,7 +11,6 @@ import ( ) func runtimeOverlay(w http.ResponseWriter, req *http.Request) { - remote := strings.Split(req.RemoteAddr, ":") port, err := strconv.Atoi(remote[1]) if err != nil { @@ -19,12 +19,20 @@ func runtimeOverlay(w http.ResponseWriter, req *http.Request) { return } - if port >= 1024 { - log.Panicf("DENIED: Connection coming from non-privledged port: %s\n", req.RemoteAddr) - w.WriteHeader(401) + config, err := config.New() + if err != nil { + fmt.Printf("ERROR: Could not load configuration file: %s\n", err) return } + if config.InsecureRuntime == false { + if port >= 1024 { + log.Panicf("DENIED: Connection coming from non-privledged port: %s\n", req.RemoteAddr) + w.WriteHeader(401) + return + } + } + node, err := assets.FindByIpaddr(remote[0]) if err != nil { fmt.Printf("Could not find node by IP address: %s\n", remote[0]) diff --git a/cmd/wwbuild/overlay.go b/cmd/wwbuild/overlay.go index 8e711b4e..1ef294e7 100644 --- a/cmd/wwbuild/overlay.go +++ b/cmd/wwbuild/overlay.go @@ -99,6 +99,9 @@ func BuildOverlayDir(sourceDir string, destDir string, replace map[string]string return err } includeFD.Close() + } else if strings.HasPrefix(newLine, "#WW") { + // Anything else is a comment or to be ignored + continue } else { _, err := w.WriteString(newLine + "\n") if err != nil { diff --git a/cmd/wwclient/wwclient.go b/cmd/wwclient/wwclient.go index ebd26441..fab560f3 100644 --- a/cmd/wwclient/wwclient.go +++ b/cmd/wwclient/wwclient.go @@ -7,9 +7,9 @@ import ( "net/http" "os" "os/exec" - - // "os/exec" "time" + + "github.com/hpcng/warewulf/internal/pkg/config" ) func main() { @@ -24,9 +24,18 @@ func main() { os.Chdir("/warewulf/wwclient-test") } - // Setup local port to 987 - localTCPAddr := net.TCPAddr{ - Port: 987, + config, err := config.New() + if err != nil { + fmt.Printf("ERROR: Could not load configuration file: %s\n", err) + return + } + + localTCPAddr := net.TCPAddr{} + if config.InsecureRuntime == false { + // Setup local port to something privileged (<1024) + localTCPAddr.Port = 987 + } else { + fmt.Printf("INFO: Running from an insecure port\n") } webclient := &http.Client{ @@ -52,7 +61,8 @@ func main() { for true { var err error - resp, err = webclient.Get("http://192.168.1.1:9873/overlay-runtime") + getString := fmt.Sprintf("http://%s:%d/overlay-runtime", config.Ipaddr, config.Port) + resp, err = webclient.Get(getString) if err == nil { break } else { @@ -79,25 +89,7 @@ func main() { continue } -/* - // TODO: Turn all of this into a pipe instead of having to use a tmpfile which - // I tried to get working, but when running on a node, it always gave a - // trying to write on closed file descriptor... This maybe ugly, but it - // works. - tmpfile := fmt.Sprintf("/tmp/.wwclient-%s", util.RandomString(14)) - tmpFD, _ := os.Create(tmpfile) - defer tmpFD.Close() - io.Copy(tmpFD, resp.Body) - tmpFD.Close() - err := exec.Command("cpio", "-i", "-F", tmpfile).Run() - if err != nil { - fmt.Printf("%s", err) - } - - os.Remove(tmpfile) - -*/ log.Printf("Updating runtime system\n") command := exec.Command("/bin/cpio", "-iu") command.Stdin = resp.Body @@ -105,27 +97,6 @@ func main() { if err != nil { log.Printf("ERROR: Failed running CPIO: %s\n", err) } - /* - command.Wait() - stdin, err := command.StdinPipe() - if err != nil { - log.Println(err) - } - defer stdin.Close() - - go func() { - bytes, err := io.Copy(stdin, resp.Body) - if err != nil { - log.Printf("ERROR: io.Copy() failed: %s\n", err) - } else { - log.Printf("Updated the runtime overlay (recv: %d)\n", bytes) - } - - }() - command.Run() - */ -// defer webclient.CloseIdleConnections() - time.Sleep(30000 * time.Millisecond) } diff --git a/etc/ipxe/default.ipxe b/etc/ipxe/default.ipxe new file mode 100644 index 00000000..3220a5d2 --- /dev/null +++ b/etc/ipxe/default.ipxe @@ -0,0 +1,13 @@ +#!ipxe + +echo +echo Now booting Warewulf - v4 Proof of Concept +echo + +set base http://@IPADDR@:@PORT@/ + +kernel ${base}/kernel/@HWADDR@ crashkernel=no quiet +initrd ${base}/vnfs/@HWADDR@ +initrd ${base}/kmods/@HWADDR@ +initrd ${base}/overlay-system/@HWADDR@ +boot diff --git a/etc/warewulf.conf b/etc/warewulf.conf index 236fa86b..ae205e82 100644 --- a/etc/warewulf.conf +++ b/etc/warewulf.conf @@ -1,4 +1,4 @@ -Port: 9873 -Ipaddr: 192.168.1.1 -Secure: true -Debug: false +warewulfd ipaddr: 192.168.1.1 +warewulfd port: 9873 +insecure runtime: false +debug: false diff --git a/internal/pkg/assets/assets.go b/internal/pkg/assets/assets.go index 8f81d730..bcca7172 100644 --- a/internal/pkg/assets/assets.go +++ b/internal/pkg/assets/assets.go @@ -26,6 +26,7 @@ type nodeYaml struct { type nodeGroup struct { Comment string Vnfs string + Ipxe string `yaml:"ipxe template"` SystemOverlay string `yaml:"system overlay""` RuntimeOverlay string `yaml:"runtime overlay""` DomainSuffix string `yaml:"domain suffix"` @@ -36,6 +37,7 @@ type nodeGroup struct { type nodeEntry struct { Hostname string Vnfs string + Ipxe string `yaml:"ipxe template"` SystemOverlay string `yaml:"system overlay"` RuntimeOverlay string `yaml:"runtime overlay"` DomainSuffix string `yaml:"domain suffix"` @@ -58,6 +60,7 @@ type NodeInfo struct { DomainName string Fqdn string Vnfs string + Ipxe string SystemOverlay string RuntimeOverlay string KernelVersion string @@ -91,6 +94,7 @@ func FindAllNodes() ([]NodeInfo, error) { n.RuntimeOverlay = group.RuntimeOverlay n.KernelVersion = group.KernelVersion n.DomainName = group.DomainSuffix + n.Ipxe = group.Ipxe n.NetDevs = node.NetDevs @@ -109,6 +113,9 @@ func FindAllNodes() ([]NodeInfo, error) { if node.DomainSuffix != "" { n.DomainName = node.DomainSuffix } + if node.Ipxe != "" { + n.Ipxe = node.Ipxe + } if n.RuntimeOverlay == "" { @@ -117,6 +124,9 @@ func FindAllNodes() ([]NodeInfo, error) { if n.SystemOverlay == "" { n.SystemOverlay = "default" } + if n.Ipxe == "" { + n.Ipxe = "default" + } if n.DomainName != "" { n.Fqdn = node.Hostname + "." + n.DomainName diff --git a/internal/pkg/config/config.go b/internal/pkg/config/config.go index 63168025..887d46b3 100644 --- a/internal/pkg/config/config.go +++ b/internal/pkg/config/config.go @@ -1,22 +1,27 @@ package config import ( - "gopkg.in/yaml.v2" + "fmt" "github.com/kelseyhightower/envconfig" + "gopkg.in/yaml.v2" "io/ioutil" ) +// THIS IS NOT BEING USED YET AND IS THUS A WORK IN PROGRESS + +const ConfigFile = "/etc/warewulf/warewulf.conf" + type Config struct { - Port int `yaml:"port", envconfig:"WAREWULFD_PORT"` - Ipaddr string `yaml:"ipaddr", envconfig:"WAREWULFD_IPADDR"` - Secure bool `yaml:"secure port"` - Debug bool `yaml:"debug"` + Port int `yaml:"warewulfd port", envconfig:"WAREWULFD_PORT"` + Ipaddr string `yaml:"warewulfd ipaddr", envconfig:"WAREWULFD_IPADDR"` + InsecureRuntime bool `yaml:"insecure runtime"` + Debug bool `yaml:"debug"` } func New() (Config, error) { var c Config - fd, err := ioutil.ReadFile("/etc/warewulf/warewulf.conf") + fd, err := ioutil.ReadFile(ConfigFile) if err != nil { return c, err } @@ -31,5 +36,9 @@ func New() (Config, error) { return c, err } + if c.Ipaddr == "" { + fmt.Printf("ERROR: 'warewulf ipaddr' has not been set in %s\n", ConfigFile) + } + return c, nil } diff --git a/overlays/runtime/default/etc/group.in b/overlays/runtime/default/etc/group.in index da836ace..a16792ab 100644 --- a/overlays/runtime/default/etc/group.in +++ b/overlays/runtime/default/etc/group.in @@ -1 +1,2 @@ -#WWINCLUDE /etc/group +#WWINCLUDE @VNFS@/etc/group +#WWINCLUDE /etc/group \ No newline at end of file diff --git a/overlays/runtime/default/etc/passwd.in b/overlays/runtime/default/etc/passwd.in index ef9462c1..3e298b08 100644 --- a/overlays/runtime/default/etc/passwd.in +++ b/overlays/runtime/default/etc/passwd.in @@ -1,2 +1,3 @@ root::0:0:root:/root:/bin/bash -#WWINCLUDE /etc/passwd +#WWINCLUDE @VNFS@/etc/passwd +#WWINCLUDE /etc/passwd \ No newline at end of file diff --git a/overlays/system/default/etc/warewulf/warewulf.conf.in b/overlays/system/default/etc/warewulf/warewulf.conf.in new file mode 100644 index 00000000..f13f49de --- /dev/null +++ b/overlays/system/default/etc/warewulf/warewulf.conf.in @@ -0,0 +1 @@ +#WWINCLUDE /etc/warewulf/warewulf.conf