This commit adds the ability to configure the default IPMI port for a profile or per node. If the port is not set, we default to 623. Updated some areas to default to 'lan' for IPMI interface if it has not been set.
301 lines
8.7 KiB
Go
301 lines
8.7 KiB
Go
package overlay
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net"
|
|
"os"
|
|
"os/exec"
|
|
"path"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"text/template"
|
|
|
|
"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"
|
|
)
|
|
|
|
type TemplateStruct struct {
|
|
Id string
|
|
Hostname string
|
|
ClusterName string
|
|
Container string
|
|
Init string
|
|
Root string
|
|
IpmiIpaddr string
|
|
IpmiNetmask string
|
|
IpmiPort string
|
|
IpmiGateway string
|
|
IpmiUserName string
|
|
IpmiPassword string
|
|
IpmiInterface string
|
|
NetDevs map[string]*node.NetDevs
|
|
Keys map[string]string
|
|
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("runtime")
|
|
}
|
|
|
|
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" {
|
|
wwlog.Printf(wwlog.VERBOSE, "Building runtime overlay for: %s\n", n.Id.Get())
|
|
|
|
OverlayDir = config.RuntimeOverlaySource(n.RuntimeOverlay.Get())
|
|
OverlayFile = config.RuntimeOverlayImage(n.Id.Get())
|
|
} else if overlayType == "system" {
|
|
wwlog.Printf(wwlog.VERBOSE, "Building system overlay for: %s\n", n.Id.Get())
|
|
|
|
OverlayDir = config.SystemOverlaySource(n.SystemOverlay.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.ClusterName = n.ClusterName.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.IpmiPort = n.IpmiPort.Get()
|
|
t.IpmiGateway = n.IpmiGateway.Get()
|
|
t.IpmiUserName = n.IpmiUserName.Get()
|
|
t.IpmiPassword = n.IpmiPassword.Get()
|
|
t.IpmiInterface = n.IpmiInterface.Get()
|
|
t.NetDevs = make(map[string]*node.NetDevs)
|
|
t.Keys = make(map[string]string)
|
|
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.NetDevs[devname].Default = netdev.Default.GetB()
|
|
mask := net.IPMask(net.ParseIP(netdev.Netmask.Get()).To4())
|
|
ipaddr := net.ParseIP(netdev.Ipaddr.Get()).To4()
|
|
netaddr := net.IPNet{IP: ipaddr, Mask: mask}
|
|
netPrefix, _ := net.IPMask(net.ParseIP(netdev.Netmask.Get()).To4()).Size()
|
|
t.NetDevs[devname].Prefix = strconv.Itoa(netPrefix)
|
|
t.NetDevs[devname].IpCIDR = netaddr.String()
|
|
|
|
}
|
|
for keyname, key := range n.Keys {
|
|
t.Keys[keyname] = key.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,
|
|
"inc": func(i int) int { return i + 1 },
|
|
"dec": func(i int) int { return i - 1 },
|
|
}).ParseGlob(path.Join(OverlayDir, destFile+".ww*"))
|
|
if err != nil {
|
|
wwlog.Printf(wwlog.ERROR, "template.New %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, "path.Join %s\n", err)
|
|
return err
|
|
}
|
|
defer w.Close()
|
|
|
|
err = tmpl.Execute(w, t)
|
|
if err != nil {
|
|
wwlog.Printf(wwlog.ERROR, "tmpl.Execute %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())
|
|
|
|
compressor, err := exec.LookPath("pigz")
|
|
if err != nil {
|
|
wwlog.Printf(wwlog.VERBOSE, "Could not locate PIGZ, using GZIP\n")
|
|
compressor = "gzip"
|
|
} else {
|
|
wwlog.Printf(wwlog.VERBOSE, "Using PIGZ to compress the container: %s\n", compressor)
|
|
}
|
|
|
|
cmd := fmt.Sprintf("cd \"%s\"; find . | cpio --quiet -o -H newc | %s -c > \"%s\"", tmpDir, compressor, 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
|
|
}
|