From 78de883339c9ac7542dd936486348a2983599130 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Tue, 3 Nov 2020 17:58:41 -0800 Subject: [PATCH] Lots of updates... --- Makefile | 8 +- cmd/warewulfd/ipxe.go | 10 +- cmd/warewulfd/kernel.go | 10 +- cmd/warewulfd/kmods.go | 10 +- cmd/warewulfd/overlay.go | 31 -- cmd/warewulfd/runtime.go | 40 ++- cmd/warewulfd/system.go | 33 ++ cmd/warewulfd/vnfs.go | 10 +- cmd/warewulfd/warewulfd.go | 153 +++------ cmd/wwbuild/overlay-runtime.go | 58 ++++ cmd/wwbuild/overlay-system.go | 60 ++++ cmd/wwbuild/{overlay-utils.go => overlay.go} | 9 +- cmd/wwbuild/wwbuild.go | 260 +++++++------- cmd/wwclient/wwclient.go | 69 ++-- internal/pkg/assets/assets.go | 335 +++++++++++-------- internal/pkg/errors/errors.go | 1 - internal/pkg/util/util.go | 90 +++-- nodes.yaml | 11 +- 18 files changed, 692 insertions(+), 506 deletions(-) delete mode 100644 cmd/warewulfd/overlay.go create mode 100644 cmd/warewulfd/system.go create mode 100644 cmd/wwbuild/overlay-runtime.go create mode 100644 cmd/wwbuild/overlay-system.go rename cmd/wwbuild/{overlay-utils.go => overlay.go} (85%) diff --git a/Makefile b/Makefile index 79c6e110..644ff606 100644 --- a/Makefile +++ b/Makefile @@ -12,10 +12,10 @@ files: all sudo install -m 0644 dhcpd.conf /etc/dhcp/dhcpd.conf sudo install -m 0644 nodes.yaml /etc/warewulf/nodes.yaml sudo cp -r tftpboot/* /var/lib/tftpboot/warewulf/ipxe/ - sudo cp -r overlays /etc/warewulf/ - sudo chmod +x /etc/warewulf/overlays/generic/init - sudo mkdir -p /etc/warewulf/overlays/generic/warewulf/bin/ - sudo cp wwclient /etc/warewulf/overlays/generic/warewulf/bin/ + sudo cp -r overlays /var/warewulf/ + sudo chmod +x /var/warewulf/overlays/system/default/init + sudo mkdir -p /var/warewulf/overlays/system/default/warewulf/bin/ + sudo cp wwclient /var/warewulf/overlays/system/default/warewulf/bin/ services: files sudo systemctl enable tftp diff --git a/cmd/warewulfd/ipxe.go b/cmd/warewulfd/ipxe.go index cb44feec..430b2930 100644 --- a/cmd/warewulfd/ipxe.go +++ b/cmd/warewulfd/ipxe.go @@ -12,7 +12,7 @@ func ipxe(w http.ResponseWriter, req *http.Request) { url := strings.Split(req.URL.Path, "/") if url[2] == "" { - fmt.Printf("ERROR: Bad iPXE request from %s\n", req.RemoteAddr) + log.Printf("ERROR: Bad iPXE request from %s\n", req.RemoteAddr) return } @@ -25,7 +25,7 @@ func ipxe(w http.ResponseWriter, req *http.Request) { } if node.HostName != "" { - fmt.Printf("IPXE: %15s: hwaddr=%s\n", node.Fqdn, hwaddr) + log.Printf("IPXE: %15s: hwaddr=%s\n", node.Fqdn, hwaddr) fmt.Fprintf(w, "#!ipxe\n") @@ -34,10 +34,10 @@ func ipxe(w http.ResponseWriter, req *http.Request) { 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/%s\n", url[2]) + fmt.Fprintf(w, "initrd ${base}/overlay-system/%s\n", url[2]) fmt.Fprintf(w, "boot\n") } else { - fmt.Printf("ERROR: iPXE request from unknown Node (hwaddr=%s)\n", url[2]) + log.Printf("ERROR: iPXE request from unknown Node (hwaddr=%s)\n", url[2]) } return -} \ No newline at end of file +} diff --git a/cmd/warewulfd/kernel.go b/cmd/warewulfd/kernel.go index 652415ff..10a5477b 100644 --- a/cmd/warewulfd/kernel.go +++ b/cmd/warewulfd/kernel.go @@ -16,17 +16,19 @@ func kernel(w http.ResponseWriter, req *http.Request) { } if node.KernelVersion != "" { - fileName := fmt.Sprintf("%s/provision/kernels/vmlinuz-%s", LocalStateDir, node.KernelVersion) + fileName := fmt.Sprintf("%s/provision/kernel/vmlinuz-%s", LocalStateDir, node.KernelVersion) err := sendFile(w, fileName, node.Fqdn) if err != nil { - log.Println(err) + log.Printf("ERROR: %s\n", err) + } else { + log.Printf("SEND: %15s: %s\n", node.Fqdn, fileName) } } else { w.WriteHeader(503) - log.Printf("No kernel version set for node %s\n", node.Fqdn) + log.Printf("ERROR: No 'kernel version' set for node %s\n", node.Fqdn) } return -} \ No newline at end of file +} diff --git a/cmd/warewulfd/kmods.go b/cmd/warewulfd/kmods.go index ac416af2..0a090811 100644 --- a/cmd/warewulfd/kmods.go +++ b/cmd/warewulfd/kmods.go @@ -15,17 +15,19 @@ func kmods(w http.ResponseWriter, req *http.Request) { return } if node.KernelVersion != "" { - fileName := fmt.Sprintf("%s/provision/kernels/kmods-%s.img", LocalStateDir, node.KernelVersion) + fileName := fmt.Sprintf("%s/provision/kernel/kmods-%s.img", LocalStateDir, node.KernelVersion) err := sendFile(w, fileName, node.Fqdn) if err != nil { - log.Println(err) + log.Printf("ERROR: %s\n", err) + } else { + log.Printf("SEND: %15s: %s\n", node.Fqdn, fileName) } } else { w.WriteHeader(503) - log.Printf("No kernel version set for node %s\n", node.Fqdn) + log.Printf("ERROR: No 'kernel version' set for node %s\n", node.Fqdn) } return -} \ No newline at end of file +} diff --git a/cmd/warewulfd/overlay.go b/cmd/warewulfd/overlay.go deleted file mode 100644 index b36159fc..00000000 --- a/cmd/warewulfd/overlay.go +++ /dev/null @@ -1,31 +0,0 @@ -package main - -import ( - "fmt" - "log" - "net/http" -) - -func overlay(w http.ResponseWriter, req *http.Request) { - - node, err := getSanity(req) - if err != nil { - w.WriteHeader(404) - log.Println(err) - return - } - - if node.Overlay!= "" { - fileName := fmt.Sprintf("%s/provision/overlays/%s.img", LocalStateDir, node.Fqdn) - - err := sendFile(w, fileName, node.Fqdn) - if err != nil { - log.Println(err) - } - } else { - w.WriteHeader(503) - log.Printf("No Overlay set for node %s\n", node.Fqdn) - } - - return -} \ No newline at end of file diff --git a/cmd/warewulfd/runtime.go b/cmd/warewulfd/runtime.go index b74cd21a..3ff885b5 100644 --- a/cmd/warewulfd/runtime.go +++ b/cmd/warewulfd/runtime.go @@ -2,45 +2,57 @@ package main import ( "fmt" + "github.com/hpcng/warewulf/internal/pkg/assets" "log" "net/http" "strconv" "strings" ) -func runtime(w http.ResponseWriter, req *http.Request) { - - node, err := getSanity(req) - if err != nil { - w.WriteHeader(404) - log.Println(err) - return - } +func runtimeOverlay(w http.ResponseWriter, req *http.Request) { remote := strings.Split(req.RemoteAddr, ":") port, err := strconv.Atoi(remote[1]) if err != nil { - w.WriteHeader(404) log.Printf("Could not convert port to integer: %s\n", remote[1]) + w.WriteHeader(503) return } if port >= 1024 { log.Panicf("DENIED: Connection coming from non-privledged port: %s\n", req.RemoteAddr) + w.WriteHeader(401) return } - if node.Overlay!= "" { - fileName := fmt.Sprintf("%s/provision/runtime/%s.img", LocalStateDir, node.Fqdn) + node, err := assets.FindByIpaddr(remote[0]) + if err != nil { + fmt.Printf("Could not find node by IP address: %s\n", remote[0]) + w.WriteHeader(404) + return + } + + if node.Fqdn == "" { + log.Printf("UNKNOWN: %15s: %s\n", remote[0], req.URL.Path) + w.WriteHeader(404) + return + } else { + log.Printf("REQ: %15s: %s\n", node.Fqdn, req.URL.Path) + } + + if node.RuntimeOverlay != "" { + fileName := fmt.Sprintf("%s/provision/overlays/runtime/%s.img", LocalStateDir, node.Fqdn) err := sendFile(w, fileName, node.Fqdn) if err != nil { - log.Println(err) + log.Printf("ERROR: %s\n", err) + } else { + log.Printf("SEND: %15s: %s\n", node.Fqdn, fileName) } } else { w.WriteHeader(503) - log.Printf("No Overlay set for node %s\n", node.Fqdn) + log.Printf("ERROR: No 'runtime overlay' set for node %s\n", node.Fqdn) } return -} \ No newline at end of file +} diff --git a/cmd/warewulfd/system.go b/cmd/warewulfd/system.go new file mode 100644 index 00000000..3f3f6ea9 --- /dev/null +++ b/cmd/warewulfd/system.go @@ -0,0 +1,33 @@ +package main + +import ( + "fmt" + "log" + "net/http" +) + +func systemOverlay(w http.ResponseWriter, req *http.Request) { + + node, err := getSanity(req) + if err != nil { + w.WriteHeader(404) + log.Println(err) + return + } + + if node.SystemOverlay != "" { + fileName := fmt.Sprintf("%s/provision/overlays/system/%s.img", LocalStateDir, node.Fqdn) + + err := sendFile(w, fileName, node.Fqdn) + if err != nil { + log.Printf("ERROR: %s\n", err) + } else { + log.Printf("SEND: %15s: %s\n", node.Fqdn, fileName) + } + } else { + w.WriteHeader(503) + log.Printf("ERROR: No 'system overlay' set for node %s\n", node.Fqdn) + } + + return +} diff --git a/cmd/warewulfd/vnfs.go b/cmd/warewulfd/vnfs.go index d03535a2..b7747a2a 100644 --- a/cmd/warewulfd/vnfs.go +++ b/cmd/warewulfd/vnfs.go @@ -17,16 +17,18 @@ func vnfs(w http.ResponseWriter, req *http.Request) { } if node.Vnfs != "" { - fileName := fmt.Sprintf("%s/provision/bases/%s.img.gz", LocalStateDir, path.Base(node.Vnfs)) + fileName := fmt.Sprintf("%s/provision/vnfs/%s.img.gz", LocalStateDir, path.Base(node.Vnfs)) err := sendFile(w, fileName, node.Fqdn) if err != nil { - log.Println(err) + log.Printf("ERROR: %s\n", err) + } else { + log.Printf("SEND: %15s: %s\n", node.Fqdn, fileName) } } else { w.WriteHeader(503) - log.Printf("No VNFS set for node %s\n", node.Fqdn) + log.Printf("ERROR: No VNFS set for node %s\n", node.Fqdn) } return -} \ No newline at end of file +} diff --git a/cmd/warewulfd/warewulfd.go b/cmd/warewulfd/warewulfd.go index 0122a13d..912c1516 100644 --- a/cmd/warewulfd/warewulfd.go +++ b/cmd/warewulfd/warewulfd.go @@ -1,136 +1,73 @@ - package main import ( - "fmt" - "io" - "log" - "os" - "strconv" - "strings" + "io" + "log" + "os" + "strconv" + "strings" - "github.com/hpcng/warewulf/internal/pkg/assets" - "github.com/hpcng/warewulf/internal/pkg/errors" - "net/http" + "github.com/hpcng/warewulf/internal/pkg/assets" + "github.com/hpcng/warewulf/internal/pkg/errors" + "net/http" ) + // TODO: https://github.com/danderson/netboot/blob/master/pixiecore/dhcp.go // TODO: https://github.com/pin/tftp - const LocalStateDir = "/var/warewulf" func getSanity(req *http.Request) (assets.NodeInfo, error) { - url := strings.Split(req.URL.Path, "/") + url := strings.Split(req.URL.Path, "/") - hwaddr := strings.ReplaceAll(url[2], "-", ":") - node, err := assets.FindByHwaddr(hwaddr) - log.Printf("REQ: %s: %s\n", hwaddr, req.URL.Path) - if err != nil { - return node, errors.New("Could not find HW address") - } + hwaddr := strings.ReplaceAll(url[2], "-", ":") + node, err := assets.FindByHwaddr(hwaddr) + if err != nil { + return node, errors.New("Could not find node by HW address") + } - if node.Fqdn == "" { - fmt.Printf("UNKNOWN: %15s: %s\n", node.Fqdn, req.URL.Path) - return node, errors.New("Unknown Node: "+ hwaddr) - } - fmt.Printf("GET: %15s: %s\n", node.Fqdn, req.URL.Path) + if node.Fqdn == "" { + log.Printf("UNKNOWN: %15s: %s\n", hwaddr, req.URL.Path) + return node, errors.New("Unknown node HW address: " + hwaddr) + } else { + log.Printf("REQ: %15s: %s\n", node.Fqdn, req.URL.Path) + } - return node, nil + return node, nil } -/* -func files(w http.ResponseWriter, req *http.Request) { - url := strings.Split(req.URL.Path, "/") - - node := assets.FindByHwaddr(strings.ReplaceAll(url[3], "-", ":")) - - if node.Fqdn == "" { - fmt.Printf("UNKNOWN: %15s: %s\n", node.Fqdn, req.URL.Path) - } - fmt.Printf("GET: %15s: %s\n", node.Fqdn, req.URL.Path) - - if url[2] == "kernel" { - if node.KernelVersion != "" { - kernelFile := fmt.Sprintf("%s/provision/kernels/vmlinuz-%s", LocalStateDir, node.KernelVersion) - - sendFile(w, kernelFile, node.Fqdn) - } - } else if url[2] == "kmods" { - if node.KernelVersion != "" { - kmodsFile := fmt.Sprintf("%s/provision/kernels/kmods-%s.img", LocalStateDir, node.KernelVersion) - - sendFile(w, kmodsFile, node.Fqdn) - } - } else if url[2] == "vnfs" { - if node.Vnfs != "" { - vnfsFile := fmt.Sprintf("%s/provision/bases/%s.img.gz", LocalStateDir, path.Base(node.Vnfs)) - - sendFile(w, vnfsFile, node.Fqdn) - } - } else if url[2] == "overlay" { - if node.Overlay!= "" { - overlayFile := fmt.Sprintf("%s/provision/overlays/%s.img", LocalStateDir, node.Fqdn) - - sendFile(w, overlayFile, node.Fqdn) - } - } else if url[2] == "runtime" { - fmt.Printf("FROM: %s\n", req.RemoteAddr) - - remote := strings.Split(req.RemoteAddr, ":") - port, _ := strconv.Atoi(remote[1]) - - if port >= 1024 { - fmt.Printf("DENIED: Connection coming from non-privledged port: %s\n", req.RemoteAddr) - return - } - - if node.Overlay!= "" { - overlayFile := fmt.Sprintf("%s/provision/runtime/%s.img", LocalStateDir, node.Fqdn) - - sendFile(w, overlayFile, node.Fqdn) - } - } - - return -} - */ - func sendFile(w http.ResponseWriter, filename string, sendto string) error { - fmt.Printf("SEND: %15s: %s\n", sendto, filename) + fd, err := os.Open(filename) + if err != nil { + return err + } - fd, err := os.Open(filename) - if err != nil { - fmt.Printf("ERROR: %s\n", err) - return err - } + FileHeader := make([]byte, 512) + fd.Read(FileHeader) + FileContentType := http.DetectContentType(FileHeader) + FileStat, _ := fd.Stat() + FileSize := strconv.FormatInt(FileStat.Size(), 10) - FileHeader := make([]byte, 512) - fd.Read(FileHeader) - FileContentType := http.DetectContentType(FileHeader) - FileStat, _ := fd.Stat() - FileSize := strconv.FormatInt(FileStat.Size(), 10) + w.Header().Set("Content-Disposition", "attachment; filename=kernel") + w.Header().Set("Content-Type", FileContentType) + w.Header().Set("Content-Length", FileSize) - w.Header().Set("Content-Disposition", "attachment; filename=kernel") - w.Header().Set("Content-Type", FileContentType) - w.Header().Set("Content-Length", FileSize) + fd.Seek(0, 0) + io.Copy(w, fd) - fd.Seek(0, 0) - io.Copy(w, fd) - - fd.Close() - return nil + fd.Close() + return nil } - func main() { - http.HandleFunc("/ipxe/", ipxe) - http.HandleFunc("/kernel/", kernel) - http.HandleFunc("/kmods/", kmods) - http.HandleFunc("/vnfs/", vnfs) - http.HandleFunc("/overlay/", overlay) - http.HandleFunc("/runtime/", runtime) + http.HandleFunc("/ipxe/", ipxe) + http.HandleFunc("/kernel/", kernel) + http.HandleFunc("/kmods/", kmods) + http.HandleFunc("/vnfs/", vnfs) + http.HandleFunc("/overlay-system/", systemOverlay) + http.HandleFunc("/overlay-runtime", runtimeOverlay) - http.ListenAndServe(":9873", nil) + http.ListenAndServe(":9873", nil) } diff --git a/cmd/wwbuild/overlay-runtime.go b/cmd/wwbuild/overlay-runtime.go new file mode 100644 index 00000000..48c3f858 --- /dev/null +++ b/cmd/wwbuild/overlay-runtime.go @@ -0,0 +1,58 @@ +package main + +import ( + "fmt" + "github.com/hpcng/warewulf/internal/pkg/assets" + "github.com/hpcng/warewulf/internal/pkg/util" + "os" + "os/exec" + "path" + "sync" +) + +func overlayRuntime(node assets.NodeInfo, replace map[string]string, wg *sync.WaitGroup) { + defer wg.Done() + + OverlayDir := fmt.Sprintf("%s/overlays/runtime/%s", LocalStateDir, node.RuntimeOverlay) + OverlayFile := fmt.Sprintf("%s/provision/overlays/runtime/%s.img", LocalStateDir, node.Fqdn) +/* + destModTime := time.Time{} + destMod, err := os.Stat(OverlayFile) + if err == nil { + destModTime = destMod.ModTime() + } + configMod, err := os.Stat("/etc/warewulf/nodes.yaml") + if err != nil { + fmt.Printf("ERROR: could not find node file: /etc/warewulf/nodes.yaml") + os.Exit(1) + } + configModTime := configMod.ModTime() + sourceModTime, _ := util.DirModTime(OverlayDir) +*/ + err := os.MkdirAll(path.Dir(OverlayFile), 0755) + if err != nil { + fmt.Printf("ERROR: %s\n", err) + return + } + err = os.MkdirAll(OverlayDir, 0755) + if err != nil { + fmt.Printf("ERROR: %s\n", err) + return + } +// if sourceModTime.After(destModTime) || configModTime.After(destModTime) { + fmt.Printf("RUNTIME: %s\n", node.Fqdn) + + overlayDest := "/tmp/.overlay-" + util.RandomString(16) + BuildOverlayDir(OverlayDir, overlayDest, replace) + + cmd := fmt.Sprintf("cd %s && find . | cpio --quiet -o -H newc -F \"%s\"", overlayDest, OverlayFile) + err = exec.Command("/bin/sh", "-c", cmd).Run() + if err != nil { + fmt.Printf("%s", err) + } + + os.RemoveAll(overlayDest) +// } else { +// fmt.Printf("RUNTIME: %s (skipped no changes)\n", node.Fqdn) +// } +} diff --git a/cmd/wwbuild/overlay-system.go b/cmd/wwbuild/overlay-system.go new file mode 100644 index 00000000..39863f37 --- /dev/null +++ b/cmd/wwbuild/overlay-system.go @@ -0,0 +1,60 @@ +package main + +import ( + "fmt" + "github.com/hpcng/warewulf/internal/pkg/assets" + "github.com/hpcng/warewulf/internal/pkg/util" + "os" + "os/exec" + "path" + "sync" +) + +func overlaySystem(node assets.NodeInfo, replace map[string]string, wg *sync.WaitGroup) { + defer wg.Done() + + OverlayDir := fmt.Sprintf("%s/overlays/system/%s", LocalStateDir, node.SystemOverlay) + OverlayFile := fmt.Sprintf("%s/provision/overlays/system/%s.img", LocalStateDir, node.Fqdn) +/* + destModTime := time.Time{} + destMod, err := os.Stat(OverlayFile) + if err == nil { + destModTime = destMod.ModTime() + } + configMod, err := os.Stat("/etc/warewulf/nodes.yaml") + if err != nil { + fmt.Printf("ERROR: could not find node file: /etc/warewulf/nodes.yaml") + os.Exit(1) + } + configModTime := configMod.ModTime() + sourceModTime, _ := util.DirModTime(OverlayDir) +*/ + err := os.MkdirAll(path.Dir(OverlayFile), 0755) + if err != nil { + fmt.Printf("ERROR: %s\n", err) + return + } + err = os.MkdirAll(OverlayDir, 0755) + if err != nil { + fmt.Printf("ERROR: %s\n", err) + return + } + +// if sourceModTime.After(destModTime) || configModTime.After(destModTime) { + fmt.Printf("SYSTEM: %s\n", node.Fqdn) + + overlayDest := "/tmp/.overlay-" + util.RandomString(16) + BuildOverlayDir(OverlayDir, overlayDest, replace) + + cmd := fmt.Sprintf("cd %s && find . | cpio --quiet -o -H newc -F \"%s\"", overlayDest, OverlayFile) + err = exec.Command("/bin/sh", "-c", cmd).Run() + if err != nil { + fmt.Printf("%s", err) + } + + os.RemoveAll(overlayDest) + +// } else { +// fmt.Printf("SYSTEM: %s (skipped no changes)\n", node.Fqdn) +// } +} diff --git a/cmd/wwbuild/overlay-utils.go b/cmd/wwbuild/overlay.go similarity index 85% rename from cmd/wwbuild/overlay-utils.go rename to cmd/wwbuild/overlay.go index 5f5632fb..78d9a733 100644 --- a/cmd/wwbuild/overlay-utils.go +++ b/cmd/wwbuild/overlay.go @@ -9,7 +9,6 @@ import ( "strings" ) - func BuildOverlayDir(sourceDir string, destDir string, replace map[string]string) error { err := os.Chdir(sourceDir) if err != nil { @@ -23,7 +22,7 @@ func BuildOverlayDir(sourceDir string, destDir string, replace map[string]string } if info.IsDir() { - err := os.MkdirAll(destDir + "/" + path, info.Mode()) + err := os.MkdirAll(destDir+"/"+path, info.Mode()) if err != nil { fmt.Println(err) } @@ -36,7 +35,7 @@ func BuildOverlayDir(sourceDir string, destDir string, replace map[string]string return err } - destFD, err :=os.OpenFile(destDir + "/" + destFile, os.O_RDWR|os.O_CREATE, info.Mode()) + destFD, err := os.OpenFile(destDir+"/"+destFile, os.O_RDWR|os.O_CREATE, info.Mode()) if err != nil { return err } @@ -60,7 +59,7 @@ func BuildOverlayDir(sourceDir string, destDir string, replace map[string]string sourceFD.Close() destFD.Close() } else { - err := util.CopyFile(sourceDir + "/" + path, destDir + "/" + path) + err := util.CopyFile(sourceDir+"/"+path, destDir+"/"+path) if err != nil { return err @@ -76,4 +75,4 @@ func BuildOverlayDir(sourceDir string, destDir string, replace map[string]string } return nil -} \ No newline at end of file +} diff --git a/cmd/wwbuild/wwbuild.go b/cmd/wwbuild/wwbuild.go index 92274706..0d7b20ea 100644 --- a/cmd/wwbuild/wwbuild.go +++ b/cmd/wwbuild/wwbuild.go @@ -1,151 +1,183 @@ - package main import ( "fmt" "github.com/hpcng/warewulf/internal/pkg/assets" - "github.com/hpcng/warewulf/internal/pkg/util" - "log" "os" "os/exec" "path" "strings" - "time" + "sync" ) - const LocalStateDir = "/var/warewulf" -func vnfsBuild(vnfsPath string) { - fmt.Printf("BUILDING VNFS: %s\n", vnfsPath) - if _, err := os.Stat(vnfsPath); err == nil { - // TODO: Build VNFS to temporary file and move to real location when complete atomically - // TODO: Check time stamps of sourcedir and build file to see if we need to rebuild or skip - cmd := fmt.Sprintf("cd %s; find . | cpio --quiet -o -H newc | gzip -c > \"%s/provision/bases/%s.img.gz\"", vnfsPath, LocalStateDir, path.Base(vnfsPath)) - err := exec.Command("/bin/sh", "-c", cmd).Run() - if err != nil { - fmt.Printf("%s", err) - } - } else { - fmt.Printf("SKIPPING VNFS: (bad path) %s\n", vnfsPath) - } +func vnfsBuild(vnfsPath string, wg *sync.WaitGroup) { + defer wg.Done() + if _, err := os.Stat(vnfsPath); err == nil { + // TODO: Build VNFS to temporary file and move to real location when complete atomically + // TODO: Check time stamps of sourcedir and build file to see if we need to rebuild or skip + vnfsDestination := fmt.Sprintf("%s/provision/vnfs/%s.img.gz", LocalStateDir, path.Base(vnfsPath)) + + err := os.MkdirAll(path.Dir(vnfsDestination), 0755) + if err != nil { + fmt.Printf("ERROR: %s\n", err) + return + } + + fmt.Printf("BUILDING VNFS: %s\n", vnfsPath) + + cmd := fmt.Sprintf("cd %s; find . | cpio --quiet -o -H newc | gzip -c > \"%s\"", vnfsPath, vnfsDestination) + err = exec.Command("/bin/sh", "-c", cmd).Run() + if err != nil { + fmt.Printf("ERROR: %s\n", err) + os.Exit(1) + } + fmt.Printf("BUILD DONE: %s\n", vnfsPath) + + } else { + fmt.Printf("SKIPPING VNFS: (bad path) %s\n", vnfsPath) + } } +func main() { + if len(os.Args) < 2 { + fmt.Printf("USAGE: %s [vnfs/kernel/overlay/all]\n", os.Args[0]) + return + } -func main(){ + if os.Args[1] == "vnfs" { + var nodeList []assets.NodeInfo + set := make(map[string]bool) + var wg sync.WaitGroup - if len(os.Args) < 2 { - fmt.Printf("USAGE: %s [vnfs/kernel/overlays/all]\n", os.Args[0]) - return - } + if len(os.Args) < 3 { + fmt.Printf("USAGE: %s vnfs [node name pattern/ALL]\n", os.Args[0]) + return + } + if os.Args[2] == "ALL" { + nodeList, _ = assets.FindAllNodes() + } else { + nodeList, _ = assets.SearchByName(os.Args[2]) + } - if os.Args[1] == "vnfs" { - if len(os.Args) >= 3 { - vnfsBuild(os.Args[3]) - } else { - nodeList, err := assets.FindAllVnfs() - if err != nil { - log.Panicf("Could not locate VNFS images: %s\n", err) - os.Exit(1) - } + if len(nodeList) == 0 { + fmt.Printf("ERROR: No nodes found\n") + return + } - for _, vnfs := range nodeList { - vnfsBuild(vnfs) - } - } - } else if os.Args[1] == "kernel" { - nodeList, err := assets.FindAllKernels() - if err != nil { - log.Panicf("Could not locate Kernel Versions: %s\n", err) - os.Exit(1) - } + for _, node := range nodeList { + if node.Vnfs != "" { + set[node.Vnfs] = true + } + } + for entry := range set { + wg.Add(1) + go vnfsBuild(entry, &wg) + } + wg.Wait() - for _, kernelVers := range nodeList { - kernelSource := fmt.Sprintf("/boot/vmlinuz-%s", kernelVers) - // TODO: Check time stamps of source and dests to see if we need to rebuild or skip - if _, err := os.Stat(kernelSource); err == nil { - kernelDestination := fmt.Sprintf("%s/provision/kernels/vmlinuz-%s", LocalStateDir, kernelVers) - fmt.Printf("SETUP KERNEL: %s (%s)\n", kernelSource, kernelDestination) - err := exec.Command("cp", kernelSource, kernelDestination).Run() - if err != nil { - fmt.Printf("%s", err) - } + } else if os.Args[1] == "kernel" { + var nodeList []assets.NodeInfo + set := make(map[string]bool) - kernelMods := fmt.Sprintf("/lib/modules/%s", kernelVers) - if _, err := os.Stat(kernelMods); err == nil { - fmt.Printf("BUILDING MODS: %s\n", kernelMods) - cmd := fmt.Sprintf("find %s | cpio --quiet -o -H newc -F \"%s/provision/kernels/kmods-%s.img\"", kernelMods, LocalStateDir, kernelVers) - err := exec.Command("/bin/sh", "-c", cmd).Run() - if err != nil { - fmt.Printf("OUTPUT: %s", err) - } + if len(os.Args) < 3 { + fmt.Printf("USAGE: %s vnfs [node name pattern/ALL]\n", os.Args[0]) + return + } - } - } - } - } else if os.Args[1] == "overlay" { - //TODO: Move this all to warewulfd and generate on demand when needed - nodeList, err := assets.FindAllNodes() - if err != nil { - log.Panicf("Could not identify nodes: %s\n", err) - os.Exit(1) - } + if os.Args[2] == "ALL" { + nodeList, _ = assets.FindAllNodes() + } else { + nodeList, _ = assets.SearchByName(os.Args[2]) + } - for _, node := range nodeList { + if len(nodeList) == 0 { + fmt.Printf("ERROR: No nodes found\n") + return + } - overlayDir := fmt.Sprintf("/etc/warewulf/overlays/%s", node.Overlay) + for _, node := range nodeList { + if node.KernelVersion != "" { + set[node.KernelVersion] = true + } + } - //TODO: Move this all to the Asset package - replace := make(map[string]string) - replace["HOSTNAME"] = node.HostName - replace["FQDN"] = node.Fqdn - replace["VNFS"] = node.Vnfs - replace["KERNELVERSION"] = node.KernelVersion - replace["GROUPNAME"] = node.GroupName - replace["DOMAIN"] = node.DomainName - for key, dev := range node.NetDevs { - replace[fmt.Sprintf("%s:NAME", key)] = key - replace[fmt.Sprintf("%s:HWADDR", key)] = strings.ReplaceAll(dev.Hwaddr, "-", ":") - replace[fmt.Sprintf("%s:IPADDR", key)] = dev.Ipaddr - replace[fmt.Sprintf("%s:NETMASK", key)] = dev.Netmask - replace[fmt.Sprintf("%s:GATEWAY", key)] = dev.Gateway - } + for kernelVers := range set { + kernelSource := fmt.Sprintf("/boot/vmlinuz-%s", kernelVers) + // TODO: Check time stamps of source and dests to see if we need to rebuild or skip + if _, err := os.Stat(kernelSource); err == nil { + kernelDestination := fmt.Sprintf("%s/provision/kernel/vmlinuz-%s", LocalStateDir, kernelVers) + kmodsDestination := fmt.Sprintf("%s/provision/kernel/kmods-%s.img", LocalStateDir, kernelVers) - destFile := fmt.Sprintf("%s/provision/overlays/%s.img", LocalStateDir, node.Fqdn) + err := os.MkdirAll(path.Dir(kernelDestination), 0755) + if err != nil { + fmt.Printf("ERROR: %s\n", err) + return + } - destModTime := time.Time{} - destMod, err := os.Stat(destFile) - if err == nil { - destModTime = destMod.ModTime() - } + fmt.Printf("SETUP KERNEL: %s (%s)\n", kernelSource, kernelDestination) + err = exec.Command("cp", kernelSource, kernelDestination).Run() + if err != nil { + fmt.Printf("%s", err) + } - configMod, err := os.Stat("/etc/warewulf/nodes.yaml") - if err != nil { - fmt.Printf("ERROR: could not find node file: /etc/warewulf/nodes.yaml") - os.Exit(1) - } - configModTime := configMod.ModTime() + kernelMods := fmt.Sprintf("./lib/modules/%s", kernelVers) + if _, err := os.Stat(kernelMods); err == nil { + fmt.Printf("BUILDING MODS: %s\n", kernelMods) + cmd := fmt.Sprintf("cd /; find %s | cpio --quiet -o -H newc -F \"%s\"", kernelMods, kmodsDestination) + err := exec.Command("/bin/sh", "-c", cmd).Run() + if err != nil { + fmt.Printf("OUTPUT: %s", err) + } - sourceModTime, _ := util.DirModTime(overlayDir) + } + } + } + } else if os.Args[1] == "overlay" { + var nodeList []assets.NodeInfo + var wg sync.WaitGroup - if sourceModTime.After(destModTime) || configModTime.After(destModTime) { - fmt.Printf("BUILDING OVERLAY: %s\n", node.Fqdn) + if len(os.Args) < 3 { + fmt.Printf("USAGE: %s vnfs [node name pattern/ALL]\n", os.Args[0]) + return + } - overlayDest := "/tmp/.overlay-" + util.RandomString(16) - BuildOverlayDir(overlayDir, overlayDest, replace) + if os.Args[2] == "ALL" { + nodeList, _ = assets.FindAllNodes() + } else { + nodeList, _ = assets.SearchByName(os.Args[2]) + } - cmd := fmt.Sprintf("cd %s; find . | cpio --quiet -o -H newc -F \"%s\"", overlayDest, destFile) - err := exec.Command("/bin/sh", "-c", cmd).Run() - if err != nil { - fmt.Printf("%s", err) - } + if len(nodeList) == 0 { + fmt.Printf("ERROR: No nodes found\n") + return + } + + for _, node := range nodeList { + + replace := make(map[string]string) + replace["HOSTNAME"] = node.HostName + replace["FQDN"] = node.Fqdn + replace["VNFS"] = node.Vnfs + replace["KERNELVERSION"] = node.KernelVersion + replace["GROUPNAME"] = node.GroupName + replace["DOMAIN"] = node.DomainName + for key, dev := range node.NetDevs { + replace[fmt.Sprintf("%s:NAME", key)] = key + replace[fmt.Sprintf("%s:HWADDR", key)] = strings.ReplaceAll(dev.Hwaddr, "-", ":") + replace[fmt.Sprintf("%s:IPADDR", key)] = dev.Ipaddr + replace[fmt.Sprintf("%s:NETMASK", key)] = dev.Netmask + replace[fmt.Sprintf("%s:GATEWAY", key)] = dev.Gateway + } + + wg.Add(2) + overlayRuntime(node, replace, &wg) + overlaySystem(node, replace, &wg) + } + wg.Wait() - os.RemoveAll(overlayDest) - } else { - fmt.Printf("Skipping overlay (nothing changed): %s\n", node.Fqdn) - } - } } } diff --git a/cmd/wwclient/wwclient.go b/cmd/wwclient/wwclient.go index 8b0112ee..71b80a2e 100644 --- a/cmd/wwclient/wwclient.go +++ b/cmd/wwclient/wwclient.go @@ -11,20 +11,20 @@ import ( "time" ) - - - func main() { - os.Chdir("/") - - // Setting up the connection manually so we can ensure a low port - localAddr, err := net.ResolveIPAddr("ip", "localhost") - if err != nil { - panic(err) + if os.Args[0] == "/warewulf/bin/wwclient" { + os.Chdir("/") + log.Printf("Updating live file system LIVE, cancel now if this is in error") + time.Sleep(5000 * time.Millisecond) + } else { + fmt.Printf("Called via: %s\n", os.Args[0]) + fmt.Printf("Runtime overlay is being put in '/warewulf/wwclient-test' rather than '/'\n") + os.MkdirAll("/warewulf/wwclient-test", 0755) + os.Chdir("/warewulf/wwclient-test") } + // Setup local port to 987 localTCPAddr := net.TCPAddr{ - IP: localAddr.IP, Port: 987, } @@ -46,34 +46,57 @@ func main() { for true { var resp *http.Response + counter := 0 for true { var err error - fmt.Printf("Connecting ....\n") - resp, err = webclient.Get("http://192.168.1.1:9873/runtime/xx-xx-xx-xx-xx") + + resp, err = webclient.Get("http://192.168.1.1:9873/overlay-runtime") if err == nil { break } else { - fmt.Println(err) + if counter > 60 { + counter = 0 + } + if counter == 0 { + log.Println(err) + } + counter++ } + time.Sleep(1000 * time.Millisecond) } - fmt.Printf("Connection accepted to remote host\n") - command := exec.Command("cpio", "-i") - stdin, err := command.StdinPipe() - if err != nil { - log.Fatal(err) + defer resp.Body.Close() + + if resp.StatusCode != 200 { + log.Printf("Not updating runtime overlay, got status code: %d\n", resp.StatusCode) + time.Sleep(60000 * time.Millisecond) + continue } + command := exec.Command("cpio", "-i") + command.Wait() + stdin, err := command.StdinPipe() + if err != nil { + log.Println(err) + } + defer stdin.Close() + go func() { - defer stdin.Close() - io.Copy(stdin, resp.Body) + 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() - resp.Body.Close() - time.Sleep(5000 * time.Millisecond) +// defer webclient.CloseIdleConnections() + + + time.Sleep(30000 * time.Millisecond) } } diff --git a/internal/pkg/assets/assets.go b/internal/pkg/assets/assets.go index d94eaae9..c9968803 100644 --- a/internal/pkg/assets/assets.go +++ b/internal/pkg/assets/assets.go @@ -1,204 +1,261 @@ - package assets import ( - "gopkg.in/yaml.v2" - "io/ioutil" + "gopkg.in/yaml.v2" + "io/ioutil" + "regexp" - "github.com/hpcng/warewulf/internal/pkg/errors" + "github.com/hpcng/warewulf/internal/pkg/errors" ) - const ConfigFile = "/etc/warewulf/nodes.yaml" - func init() { - + //TODO: Check to make sure nodes.yaml is found } type nodeYaml struct { - NodeGroups map[string]nodeGroup //`yaml:"nodegroups"` + NodeGroups map[string]nodeGroup //`yaml:"nodegroups"` } type nodeGroup struct { - Comment string - Vnfs string - Overlay string - DomainSuffix string `yaml:"domain suffix"` - KernelVersion string `yaml:"kernel version"` - Nodes map[string]nodeEntry + Comment string + Vnfs string + SystemOverlay string `yaml:"system overlay""` + RuntimeOverlay string `yaml:"runtime overlay""` + DomainSuffix string `yaml:"domain suffix"` + KernelVersion string `yaml:"kernel version"` + Nodes map[string]nodeEntry } type nodeEntry struct { - Hostname string - Vnfs string - Overlay string - DomainSuffix string `yaml:"domain suffix"` - KernelVersion string `yaml:"kernel version"` - IpmiIpaddr string `yaml:"ipmi ipaddr"` - NetDevs map[string]netDevs + Hostname string + Vnfs string + SystemOverlay string `yaml:"system overlay"` + RuntimeOverlay string `yaml:"runtime overlay"` + DomainSuffix string `yaml:"domain suffix"` + KernelVersion string `yaml:"kernel version"` + IpmiIpaddr string `yaml:"ipmi ipaddr"` + NetDevs map[string]netDevs } type netDevs struct { - Type string - Hwaddr string - Ipaddr string - Netmask string - Gateway string + Type string + Hwaddr string + Ipaddr string + Netmask string + Gateway string } type NodeInfo struct { - GroupName string - HostName string - Fqdn string - Vnfs string - Overlay string - KernelVersion string - DomainName string - NetDevs map[string]netDevs + GroupName string + HostName string + DomainName string + Fqdn string + Vnfs string + SystemOverlay string + RuntimeOverlay string + KernelVersion string + NetDevs map[string]netDevs } - func FindAllNodes() ([]NodeInfo, error) { - var c nodeYaml - var ret []NodeInfo + var c nodeYaml + var ret []NodeInfo - fd, err := ioutil.ReadFile(ConfigFile) - if err != nil { - return nil, err - } + fd, err := ioutil.ReadFile(ConfigFile) + if err != nil { + return nil, err + } - err = yaml.Unmarshal(fd, &c) - if err != nil { - return nil, err - } + err = yaml.Unmarshal(fd, &c) + if err != nil { + return nil, err + } - for groupname, group := range c.NodeGroups { - for _, node := range group.Nodes { - var n NodeInfo + for groupname, group := range c.NodeGroups { + for _, node := range group.Nodes { + var n NodeInfo - n.GroupName = groupname - n.HostName = node.Hostname + n.GroupName = groupname + n.HostName = node.Hostname - n.Vnfs = group.Vnfs - n.Overlay = group.Overlay - n.KernelVersion = group.KernelVersion - n.DomainName = group.DomainSuffix - n.NetDevs = node.NetDevs + n.Vnfs = group.Vnfs + n.SystemOverlay = group.SystemOverlay + n.RuntimeOverlay = group.RuntimeOverlay + n.KernelVersion = group.KernelVersion + n.DomainName = group.DomainSuffix + n.NetDevs = node.NetDevs - if group.DomainSuffix != "" { - n.Fqdn = node.Hostname + "." + group.DomainSuffix - } else { - n.Fqdn = node.Hostname - } - if node.KernelVersion != "" { - n.KernelVersion = node.KernelVersion - } - if node.Vnfs != "" { - n.Vnfs = node.Vnfs - } - if node.Overlay != "" { - n.Overlay = node.Overlay - } - if node.DomainSuffix != "" { - n.DomainName = node.DomainSuffix - } - ret = append(ret, n) - } - } + if group.DomainSuffix != "" { + n.Fqdn = node.Hostname + "." + group.DomainSuffix + } else { + n.Fqdn = node.Hostname + } + if node.KernelVersion != "" { + n.KernelVersion = node.KernelVersion + } + if node.Vnfs != "" { + n.Vnfs = node.Vnfs + } + if node.SystemOverlay != "" { + n.SystemOverlay = node.SystemOverlay + } + if node.RuntimeOverlay != "" { + n.RuntimeOverlay = node.RuntimeOverlay + } + if node.DomainSuffix != "" { + n.DomainName = node.DomainSuffix + } - return ret, nil + ret = append(ret, n) + } + } + + return ret, nil } - func FindByHwaddr(hwa string) (NodeInfo, error) { - var ret NodeInfo + var ret NodeInfo - nodeList, err := FindAllNodes() - if err != nil { - return ret, err - } + nodeList, err := FindAllNodes() + if err != nil { + return ret, err + } - for _, node := range nodeList { - for _, dev := range node.NetDevs { - if dev.Hwaddr == hwa { - return node, nil - } - } - } + for _, node := range nodeList { + for _, dev := range node.NetDevs { + if dev.Hwaddr == hwa { + return node, nil + } + } + } - return ret, errors.New("No nodes found with HW Addr: " + hwa) + return ret, errors.New("No nodes found with HW Addr: " + hwa) } +func FindByIpaddr(ipaddr string) (NodeInfo, error) { + var ret NodeInfo + + nodeList, err := FindAllNodes() + if err != nil { + return ret, err + } + + for _, node := range nodeList { + for _, dev := range node.NetDevs { + if dev.Ipaddr == ipaddr { + return node, nil + } + } + } + + return ret, errors.New("No nodes found with IP Addr: " + ipaddr) +} + +func SearchByName(search string) ([]NodeInfo, error) { + var ret []NodeInfo + + nodeList, err := FindAllNodes() + if err != nil { + return ret, err + } + + for _, node := range nodeList { + b, _ := regexp.MatchString(search, node.Fqdn) + if b == true { + ret = append(ret, node) + } + } + + return ret, nil +} func FindAllVnfs() ([]string, error) { - var ret []string - set := make(map[string]bool) + var ret []string + set := make(map[string]bool) - nodeList, err := FindAllNodes() - if err != nil { - return ret, err - } + nodeList, err := FindAllNodes() + if err != nil { + return ret, err + } - for _, node := range nodeList { - if node.Vnfs != "" { - set[node.Vnfs] = true - } - } + for _, node := range nodeList { + if node.Vnfs != "" { + set[node.Vnfs] = true + } + } - for entry := range set { - ret = append(ret, entry) - } + for entry := range set { + ret = append(ret, entry) + } - return ret, nil + return ret, nil } - - func FindAllKernels() ([]string, error) { - var ret []string - set := make(map[string]bool) + var ret []string + set := make(map[string]bool) - nodeList, err := FindAllNodes() - if err != nil { - return ret, err - } + nodeList, err := FindAllNodes() + if err != nil { + return ret, err + } - for _, node := range nodeList { - if node.KernelVersion != "" { - set[node.KernelVersion] = true - } - } + for _, node := range nodeList { + if node.KernelVersion != "" { + set[node.KernelVersion] = true + } + } - for entry := range set { - ret = append(ret, entry) - } + for entry := range set { + ret = append(ret, entry) + } - return ret, nil + return ret, nil } -//FindAllOverlays -func FindAllOverlays() ([]string, error) { - var ret []string - set := make(map[string]bool) +func ListSystemOverlays() ([]string, error) { + var ret []string + set := make(map[string]bool) - nodeList, err := FindAllNodes() - if err != nil { - return ret, err - } + nodeList, err := FindAllNodes() + if err != nil { + return ret, err + } - for _, node := range nodeList { - if node.Overlay != "" { - set[node.Overlay] = true - } - } + for _, node := range nodeList { + if node.SystemOverlay != "" { + set[node.SystemOverlay] = true + } + } - for entry := range set { - ret = append(ret, entry) - } + for entry := range set { + ret = append(ret, entry) + } - return ret, nil + return ret, nil } +func ListRuntimeOverlays() ([]string, error) { + var ret []string + set := make(map[string]bool) + nodeList, err := FindAllNodes() + if err != nil { + return ret, err + } + + for _, node := range nodeList { + if node.RuntimeOverlay != "" { + set[node.RuntimeOverlay] = true + } + } + + for entry := range set { + ret = append(ret, entry) + } + + return ret, nil +} diff --git a/internal/pkg/errors/errors.go b/internal/pkg/errors/errors.go index 10ca912d..2cf7c75d 100644 --- a/internal/pkg/errors/errors.go +++ b/internal/pkg/errors/errors.go @@ -1,6 +1,5 @@ package errors - type error interface { Error() string } diff --git a/internal/pkg/util/util.go b/internal/pkg/util/util.go index 9bcc8c41..0fdfca2d 100644 --- a/internal/pkg/util/util.go +++ b/internal/pkg/util/util.go @@ -1,67 +1,65 @@ - package util import ( - "io" - "math/rand" - "os" - "path/filepath" - "time" + "io" + "math/rand" + "os" + "path/filepath" + "time" - // "strings" + // "strings" ) +func DirModTime(path string) (time.Time, error) { -func DirModTime (path string) (time.Time, error) { + var lastTime time.Time + err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } - var lastTime time.Time - err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } + cur := info.ModTime() + if cur.After(lastTime) { + lastTime = info.ModTime() + } - cur := info.ModTime() - if cur.After(lastTime) { - lastTime = info.ModTime() - } - - return nil - }) - if err != nil { - return time.Time{}, err - } - return lastTime, nil + return nil + }) + if err != nil { + return time.Time{}, err + } + return lastTime, nil } func RandomString(n int) string { - var letter = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") + var letter = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") - b := make([]rune, n) - for i := range b { - b[i] = letter[rand.Intn(len(letter))] - } - return string(b) + b := make([]rune, n) + for i := range b { + b[i] = letter[rand.Intn(len(letter))] + } + return string(b) } func CopyFile(source string, dest string) error { - sourceFD, err := os.Open(source) - if err != nil { - return err - } + sourceFD, err := os.Open(source) + if err != nil { + return err + } - finfo, err := sourceFD.Stat() + finfo, err := sourceFD.Stat() - destFD, err := os.OpenFile(dest, os.O_RDWR|os.O_CREATE, finfo.Mode()) - if err != nil { - return err - } + destFD, err := os.OpenFile(dest, os.O_RDWR|os.O_CREATE, finfo.Mode()) + if err != nil { + return err + } - _, err = io.Copy(destFD, sourceFD) - if err != nil { - return err - } + _, err = io.Copy(destFD, sourceFD) + if err != nil { + return err + } - sourceFD.Close() + sourceFD.Close() - return destFD.Close() -} \ No newline at end of file + return destFD.Close() +} diff --git a/nodes.yaml b/nodes.yaml index 223a4120..b5a10c32 100644 --- a/nodes.yaml +++ b/nodes.yaml @@ -2,22 +2,25 @@ nodegroups: group_1: comment: This is the group 1 vnfs: /var/chroots/test - overlay: generic + system overlay: default + runtime overlay: default domain suffix: group1 nodes: n0000: - hostname: n0000 + hostname: localtest kernel version: 3.10.0-1127.el7.x86_64 + system overlay: test netdevs: eth0: hwaddr: xx:xx:xx:xx:aa - ipaddr: 192.168.0.101 + ipaddr: 192.168.1.1 netmask: 255.255.255.0 gateway: 192.168.1.1 group_2: comment: This is the group 2 vnfs: /var/chroots/centos-7 - overlay: generic + system overlay: default + runtime overlay: default domain suffix: group2 kernel version: 3.10.0-1127.el7.x86_64 nodes: