Lots of updates...

This commit is contained in:
Gregory Kurtzer
2020-11-03 17:58:41 -08:00
parent 5f866c0111
commit 78de883339
18 changed files with 692 additions and 506 deletions

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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
}

View File

@@ -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
}
}

33
cmd/warewulfd/system.go Normal file
View File

@@ -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
}

View File

@@ -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
}
}

View File

@@ -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)
}

View File

@@ -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)
// }
}

View File

@@ -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)
// }
}

View File

@@ -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
}
}

View File

@@ -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)
}
}
}
}

View File

@@ -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)
}
}