263 lines
7.3 KiB
Go
263 lines
7.3 KiB
Go
package overlay
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/hpcng/warewulf/internal/pkg/config"
|
|
"github.com/hpcng/warewulf/internal/pkg/errors"
|
|
"github.com/hpcng/warewulf/internal/pkg/node"
|
|
"github.com/hpcng/warewulf/internal/pkg/util"
|
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
|
"io/ioutil"
|
|
"os"
|
|
"os/exec"
|
|
"path"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
"text/template"
|
|
)
|
|
|
|
type TemplateStruct struct {
|
|
Id string
|
|
Hostname string
|
|
GroupName string
|
|
Container string
|
|
Init string
|
|
IpmiIpaddr string
|
|
IpmiNetmask string
|
|
IpmiGateway string
|
|
IpmiUserName string
|
|
IpmiPassword string
|
|
NetDevs map[string]*node.NetDevs
|
|
AllNodes []node.NodeInfo
|
|
}
|
|
|
|
func BuildSystemOverlay(nodeList []node.NodeInfo) error {
|
|
return buildOverlay(nodeList, "system")
|
|
}
|
|
|
|
func BuildRuntimeOverlay(nodeList []node.NodeInfo) error {
|
|
return buildOverlay(nodeList, "runtime")
|
|
}
|
|
|
|
func FindSystemOverlays() ([]string, error) {
|
|
return findAllOverlays("system")
|
|
}
|
|
|
|
func FindRuntimeOverlays() ([]string, error) {
|
|
return findAllOverlays("system")
|
|
}
|
|
|
|
func SystemOverlayInit(name string) error {
|
|
return overlayInit(name, "system")
|
|
}
|
|
|
|
func RuntimeOverlayInit(name string) error {
|
|
return overlayInit(name, "runtime")
|
|
}
|
|
|
|
func findAllOverlays(overlayType string) ([]string, error) {
|
|
var ret []string
|
|
var files []os.FileInfo
|
|
var err error
|
|
|
|
if overlayType == "system" {
|
|
wwlog.Printf(wwlog.DEBUG, "Looking for system overlays...")
|
|
files, err = ioutil.ReadDir(config.SystemOverlayDir())
|
|
} else if overlayType == "runtime" {
|
|
wwlog.Printf(wwlog.DEBUG, "Looking for runtime overlays...")
|
|
files, err = ioutil.ReadDir(config.RuntimeOverlayDir())
|
|
} else {
|
|
wwlog.Printf(wwlog.ERROR, "overlayType requested is not supported: %s\n", overlayType)
|
|
os.Exit(1)
|
|
}
|
|
|
|
if err != nil {
|
|
return ret, err
|
|
}
|
|
|
|
for _, file := range files {
|
|
wwlog.Printf(wwlog.DEBUG, "Evaluating overlay source: %s\n", file.Name())
|
|
if file.IsDir() == true {
|
|
ret = append(ret, file.Name())
|
|
}
|
|
}
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
func overlayInit(name string, overlayType string) error {
|
|
var path string
|
|
|
|
if overlayType == "system" {
|
|
wwlog.Printf(wwlog.DEBUG, "Looking for system overlays...")
|
|
path = config.SystemOverlaySource(name)
|
|
} else if overlayType == "runtime" {
|
|
wwlog.Printf(wwlog.DEBUG, "Looking for runtime overlays...")
|
|
path = config.RuntimeOverlaySource(name)
|
|
} else {
|
|
wwlog.Printf(wwlog.ERROR, "overlayType requested is not supported: %s\n", overlayType)
|
|
os.Exit(1)
|
|
}
|
|
|
|
if util.IsDir(path) == true {
|
|
return errors.New("Overlay already exists: " + name)
|
|
}
|
|
|
|
err := os.MkdirAll(path, 0755)
|
|
|
|
return err
|
|
}
|
|
|
|
func buildOverlay(nodeList []node.NodeInfo, overlayType string) error {
|
|
nodeDB, _ := node.New()
|
|
allNodes, _ := nodeDB.FindAllNodes()
|
|
|
|
for _, n := range nodeList {
|
|
var t TemplateStruct
|
|
var OverlayDir string
|
|
var OverlayFile string
|
|
|
|
if overlayType == "runtime" {
|
|
OverlayDir = config.RuntimeOverlaySource(n.RuntimeOverlay.Get())
|
|
OverlayFile = config.RuntimeOverlayImage(n.Id.Get())
|
|
} else if overlayType == "system" {
|
|
OverlayDir = config.SystemOverlaySource(n.RuntimeOverlay.Get())
|
|
OverlayFile = config.SystemOverlayImage(n.Id.Get())
|
|
} else {
|
|
wwlog.Printf(wwlog.ERROR, "overlayType requested is not supported: %s\n", overlayType)
|
|
os.Exit(1)
|
|
}
|
|
|
|
wwlog.Printf(wwlog.DEBUG, "Processing overlay for node: %s\n", n.Id.Get())
|
|
|
|
t.Id = n.Id.Get()
|
|
t.Hostname = n.Id.Get()
|
|
t.Container = n.ContainerName.Get()
|
|
t.Init = n.Init.Get()
|
|
t.IpmiIpaddr = n.IpmiIpaddr.Get()
|
|
t.IpmiNetmask = n.IpmiNetmask.Get()
|
|
t.IpmiGateway = n.IpmiGateway.Get()
|
|
t.IpmiUserName = n.IpmiUserName.Get()
|
|
t.IpmiPassword = n.IpmiPassword.Get()
|
|
t.NetDevs = make(map[string]*node.NetDevs)
|
|
for devname, netdev := range n.NetDevs {
|
|
var nd node.NetDevs
|
|
t.NetDevs[devname] = &nd
|
|
t.NetDevs[devname].Hwaddr = netdev.Hwaddr.Get()
|
|
t.NetDevs[devname].Ipaddr = netdev.Ipaddr.Get()
|
|
t.NetDevs[devname].Netmask = netdev.Netmask.Get()
|
|
t.NetDevs[devname].Gateway = netdev.Gateway.Get()
|
|
t.NetDevs[devname].Type = netdev.Type.Get()
|
|
}
|
|
t.AllNodes = allNodes
|
|
|
|
if overlayType == "runtime" && n.RuntimeOverlay.Defined() == false {
|
|
wwlog.Printf(wwlog.WARN, "Undefined runtime overlay, skipping node: %s\n", n.Id.Get())
|
|
}
|
|
if overlayType == "system" && n.SystemOverlay.Defined() == false {
|
|
wwlog.Printf(wwlog.WARN, "Undefined system overlay, skipping node: %s\n", n.Id.Get())
|
|
}
|
|
|
|
wwlog.Printf(wwlog.DEBUG, "Checking to see if overlay directory exists: %s\n", OverlayDir)
|
|
if util.IsDir(OverlayDir) == false {
|
|
wwlog.Printf(wwlog.WARN, "%-35s: Skipped (runtime overlay template not found)\n", n.Id.Get())
|
|
continue
|
|
}
|
|
|
|
wwlog.Printf(wwlog.DEBUG, "Creating parent directory for OverlayFile: %s\n", path.Dir(OverlayFile))
|
|
err := os.MkdirAll(path.Dir(OverlayFile), 0755)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
wwlog.Printf(wwlog.DEBUG, "Changing directory to OverlayDir: %s\n", OverlayDir)
|
|
err = os.Chdir(OverlayDir)
|
|
if err != nil {
|
|
wwlog.Printf(wwlog.ERROR, "Could not chdir() to OverlayDir: %s\n", OverlayDir)
|
|
continue
|
|
}
|
|
|
|
wwlog.Printf(wwlog.DEBUG, "Creating temporary directory for overlay files\n")
|
|
tmpDir, err := ioutil.TempDir(os.TempDir(), ".wwctl-overlay-")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
wwlog.Printf(wwlog.DEBUG, "Walking the file system: %s\n", OverlayDir)
|
|
err = filepath.Walk(".", func(location string, info os.FileInfo, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if info.IsDir() {
|
|
wwlog.Printf(wwlog.DEBUG, "Found directory: %s\n", location)
|
|
|
|
err := os.MkdirAll(path.Join(tmpDir, location), info.Mode())
|
|
if err != nil {
|
|
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
|
return err
|
|
}
|
|
|
|
} else if filepath.Ext(location) == ".ww" {
|
|
wwlog.Printf(wwlog.DEBUG, "Found template file: %s\n", location)
|
|
|
|
destFile := strings.TrimSuffix(location, ".ww")
|
|
|
|
tmpl, err := template.New(path.Base(location)).Funcs(template.FuncMap{
|
|
"Include": templateFileInclude,
|
|
"IncludeFrom": templateContainerFileInclude,
|
|
}).ParseGlob(path.Join(OverlayDir, destFile+".ww*"))
|
|
if err != nil {
|
|
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
|
return nil
|
|
}
|
|
|
|
w, err := os.OpenFile(path.Join(tmpDir, destFile), os.O_RDWR|os.O_CREATE, info.Mode())
|
|
if err != nil {
|
|
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
|
return err
|
|
}
|
|
defer w.Close()
|
|
|
|
err = tmpl.Execute(w, t)
|
|
if err != nil {
|
|
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
|
return nil
|
|
}
|
|
|
|
} else if b, _ := regexp.MatchString(`\.ww[a-zA-Z0-9\-\._]*$`, location); b == true {
|
|
wwlog.Printf(wwlog.DEBUG, "Ignoring WW template file: %s\n", location)
|
|
} else {
|
|
wwlog.Printf(wwlog.DEBUG, "Found file: %s\n", location)
|
|
|
|
err := util.CopyFile(path.Join(OverlayDir, location), path.Join(tmpDir, location))
|
|
if err != nil {
|
|
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
|
return err
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
wwlog.Printf(wwlog.VERBOSE, "Finished generating overlay directory for: %s\n", n.Id.Get())
|
|
|
|
cmd := fmt.Sprintf("cd \"%s\"; find . | cpio --quiet -o -H newc -F \"%s\"", tmpDir, OverlayFile)
|
|
wwlog.Printf(wwlog.DEBUG, "RUNNING: %s\n", cmd)
|
|
err = exec.Command("/bin/sh", "-c", cmd).Run()
|
|
if err != nil {
|
|
wwlog.Printf(wwlog.ERROR, "Could not generate runtime image overlay: %s\n", err)
|
|
continue
|
|
}
|
|
wwlog.Printf(wwlog.INFO, "%-35s: Done\n", n.Id.Get())
|
|
|
|
wwlog.Printf(wwlog.DEBUG, "Removing temporary directory: %s\n", tmpDir)
|
|
os.RemoveAll(tmpDir)
|
|
|
|
}
|
|
|
|
return nil
|
|
}
|