This is a work in progress, some of which will be reverted like overlay handling.
This commit is contained in:
@@ -1,15 +1,36 @@
|
||||
profiles:
|
||||
default:
|
||||
vnfs: docker://warewulf/centos-8
|
||||
kernel version: 3.10.0-1127.el7.x86_64
|
||||
kernel args: crashkernel=no quiet
|
||||
runtime overlay files:
|
||||
- path: /etc/passwd
|
||||
source: /path/to/source/etc/ssh/sshd.conf-node2
|
||||
mode: 0644
|
||||
- path: /etc/
|
||||
mode: 0755
|
||||
directory: true
|
||||
- path: /etc/sshd.conf
|
||||
source: /path/to/source/etc/ssh/sshd.conf-node2
|
||||
mode: 0644
|
||||
- path: /etc/link
|
||||
source: /path/to/source/
|
||||
mode: 0644
|
||||
link: true
|
||||
test:
|
||||
runtime overlay files:
|
||||
- path: /this/is/a/test/file
|
||||
source: /path/to/source/etc/ssh/sshd.conf-node2
|
||||
mode: 0644
|
||||
|
||||
nodegroups:
|
||||
default:
|
||||
comment: This is the default group
|
||||
vnfs: docker://warewulf/centos-8
|
||||
runtime overlay: default
|
||||
domain suffix: default
|
||||
kernel version: ""
|
||||
kernel args: crashkernel=no quiet
|
||||
nodes:
|
||||
n0000:
|
||||
hostname: n0000
|
||||
kernel args: crashkernel=no
|
||||
profiles: [default, test]
|
||||
netdevs:
|
||||
eth0:
|
||||
hwaddr: 00:0c:29:23:8b:48
|
||||
@@ -25,6 +46,7 @@ nodegroups:
|
||||
n0001:
|
||||
hostname: n0001
|
||||
ipmi ipaddr: x.x.x.x
|
||||
kernel version: BOOO
|
||||
netdevs:
|
||||
eth0:
|
||||
hwaddr: aa:bb:cc:dd:ee:b0
|
||||
|
||||
13
internal/app/sandbox/main.go
Normal file
13
internal/app/sandbox/main.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||
"github.com/hpcng/warewulf/internal/pkg/overlay"
|
||||
)
|
||||
|
||||
func main() {
|
||||
nodeDB, _ := node.New()
|
||||
nodes, _ := nodeDB.FindAllNodes()
|
||||
// wwlog.SetLevel(wwlog.DEBUG)
|
||||
overlay.OverlayBuild(nodes, "runtime")
|
||||
}
|
||||
@@ -49,10 +49,10 @@ func IpxeSend(w http.ResponseWriter, req *http.Request) {
|
||||
if node.HostName.Defined() == true {
|
||||
conf := config.New()
|
||||
|
||||
log.Printf("IPXE: %15s: %s\n", node.Fqdn, req.URL.Path)
|
||||
log.Printf("IPXE: %15s: %s\n", node.Fqdn.String(), req.URL.Path)
|
||||
|
||||
// TODO: Fix template path to use config package
|
||||
ipxeTemplate := fmt.Sprintf("/etc/warewulf/ipxe/%s.ipxe", node.Ipxe)
|
||||
ipxeTemplate := fmt.Sprintf("/etc/warewulf/ipxe/%s.ipxe", node.Ipxe.String())
|
||||
|
||||
tmpl, err := template.ParseFiles(ipxeTemplate)
|
||||
if err != nil {
|
||||
@@ -76,7 +76,7 @@ func IpxeSend(w http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("SEND: %15s: %s\n", node.Fqdn, ipxeTemplate)
|
||||
log.Printf("SEND: %15s: %s\n", node.Fqdn.String(), ipxeTemplate)
|
||||
|
||||
} else {
|
||||
log.Printf("ERROR: iPXE request from unknown Node (hwaddr=%s)\n", url[2])
|
||||
|
||||
@@ -23,12 +23,12 @@ func KernelSend(w http.ResponseWriter, req *http.Request) {
|
||||
if err != nil {
|
||||
log.Printf("ERROR: %s\n", err)
|
||||
} else {
|
||||
log.Printf("SEND: %15s: %s\n", node.Fqdn, fileName)
|
||||
log.Printf("SEND: %15s: %s\n", node.Fqdn.String(), fileName)
|
||||
}
|
||||
|
||||
} else {
|
||||
w.WriteHeader(503)
|
||||
log.Printf("ERROR: No 'kernel version' set for node %s\n", node.Fqdn)
|
||||
log.Printf("ERROR: No 'kernel version' set for node %s\n", node.Fqdn.String())
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
@@ -15,6 +15,7 @@ func KmodsSend(w http.ResponseWriter, req *http.Request) {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
if node.KernelVersion.Defined() == true {
|
||||
fileName := config.KmodsImage(node.KernelVersion.String())
|
||||
|
||||
@@ -22,12 +23,12 @@ func KmodsSend(w http.ResponseWriter, req *http.Request) {
|
||||
if err != nil {
|
||||
log.Printf("ERROR: %s\n", err)
|
||||
} else {
|
||||
log.Printf("SEND: %15s: %s\n", node.Fqdn, fileName)
|
||||
log.Printf("SEND: %15s: %s\n", node.Fqdn.String(), fileName)
|
||||
}
|
||||
|
||||
} else {
|
||||
w.WriteHeader(503)
|
||||
log.Printf("ERROR: No 'kernel version' set for node %s\n", node.Fqdn)
|
||||
log.Printf("ERROR: No 'kernel version' set for node %s\n", node.Fqdn.String())
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
@@ -52,7 +52,7 @@ func RuntimeOverlaySend(w http.ResponseWriter, req *http.Request) {
|
||||
w.WriteHeader(404)
|
||||
return
|
||||
} else {
|
||||
log.Printf("REQ: %15s: %s\n", node.Fqdn, req.URL.Path)
|
||||
log.Printf("REQ: %15s: %s\n", node.Fqdn.String(), req.URL.Path)
|
||||
}
|
||||
|
||||
if node.RuntimeOverlay.Defined() == true {
|
||||
@@ -62,11 +62,11 @@ func RuntimeOverlaySend(w http.ResponseWriter, req *http.Request) {
|
||||
if err != nil {
|
||||
log.Printf("ERROR: %s\n", err)
|
||||
} else {
|
||||
log.Printf("SEND: %15s: %s\n", node.Fqdn, fileName)
|
||||
log.Printf("SEND: %15s: %s\n", node.Fqdn.String(), fileName)
|
||||
}
|
||||
} else {
|
||||
w.WriteHeader(503)
|
||||
log.Printf("ERROR: No 'runtime system-overlay' set for node %s\n", node.Fqdn)
|
||||
log.Printf("ERROR: No 'runtime system-overlay' set for node %s\n", node.Fqdn.String())
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
@@ -23,11 +23,11 @@ func SystemOverlaySend(w http.ResponseWriter, req *http.Request) {
|
||||
if err != nil {
|
||||
log.Printf("ERROR: %s\n", err)
|
||||
} else {
|
||||
log.Printf("SEND: %15s: %s\n", node.Fqdn, fileName)
|
||||
log.Printf("SEND: %15s: %s\n", node.Fqdn.String(), fileName)
|
||||
}
|
||||
} else {
|
||||
w.WriteHeader(503)
|
||||
log.Printf("ERROR: No 'system system-overlay' set for node %s\n", node.Fqdn)
|
||||
log.Printf("ERROR: No 'system system-overlay' set for node %s\n", node.Fqdn.String())
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
@@ -31,7 +31,7 @@ func getSanity(req *http.Request) (node.NodeInfo, error) {
|
||||
log.Printf("UNKNOWN: %15s: %s\n", hwaddr, req.URL.Path)
|
||||
return ret, errors.New("Unknown node HW address: " + hwaddr)
|
||||
} else {
|
||||
log.Printf("REQ: %15s: %s\n", ret.Fqdn, req.URL.Path)
|
||||
log.Printf("REQ: %15s: %s\n", ret.Fqdn.String(), req.URL.Path)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
package response
|
||||
|
||||
import (
|
||||
"github.com/hpcng/warewulf/internal/pkg/config"
|
||||
"github.com/hpcng/warewulf/internal/pkg/vnfs"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func VnfsSend(w http.ResponseWriter, req *http.Request) {
|
||||
config := config.New()
|
||||
// config := config.New()
|
||||
|
||||
node, err := getSanity(req)
|
||||
if err != nil {
|
||||
@@ -18,17 +17,23 @@ func VnfsSend(w http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
|
||||
if node.Vnfs.Defined() == true {
|
||||
v := vnfs.New(node.Vnfs.String())
|
||||
|
||||
err := sendFile(w, config.VnfsImage(v.NameClean()), node.Fqdn.String())
|
||||
v, err := vnfs.Load(node.Vnfs.String())
|
||||
if err != nil {
|
||||
log.Printf("ERROR: %s\n", err)
|
||||
w.WriteHeader(503)
|
||||
log.Printf("ERROR: Could not load VNFS: %s\n", node.Fqdn.String())
|
||||
return
|
||||
}
|
||||
|
||||
err = sendFile(w, v.Image, node.Fqdn.String())
|
||||
if err != nil {
|
||||
log.Printf("ERROR1: %s\n", err)
|
||||
} else {
|
||||
log.Printf("SEND: %15s: %s\n", node.Fqdn, config.VnfsImage(v.NameClean()))
|
||||
log.Printf("SEND: %15s: %s\n", node.Fqdn.String(), v.Image)
|
||||
}
|
||||
} else {
|
||||
w.WriteHeader(503)
|
||||
log.Printf("ERROR: No VNFS set for node %s\n", node.Fqdn)
|
||||
log.Printf("ERROR: No VNFS set for node %s\n", node.Fqdn.String())
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
@@ -2,11 +2,52 @@ package list
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/hpcng/warewulf/internal/pkg/config"
|
||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
"github.com/spf13/cobra"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
fmt.Printf("This command is coming soon...\n")
|
||||
config := config.New()
|
||||
nconfig, _ := node.New()
|
||||
nodes, _ := nconfig.FindAllNodes()
|
||||
nodemap := make(map[string]int)
|
||||
|
||||
for _, n := range nodes {
|
||||
nodemap[n.KernelVersion.String()] ++
|
||||
}
|
||||
|
||||
images, _ := ioutil.ReadDir(config.KernelParentDir())
|
||||
|
||||
fmt.Printf("%-38s %-16s %-16s %s\n", "KERNEL VERSION", "KERNEL SIZE(k)", "KMODS SIZE(k)", "NODES")
|
||||
fmt.Println(strings.Repeat("=", 80))
|
||||
|
||||
for _, file := range images {
|
||||
if util.IsDir(path.Join(config.KernelParentDir(), file.Name())) {
|
||||
var kernel_size int64
|
||||
var kmods_size int64
|
||||
if util.IsFile( config.KernelImage(file.Name())) {
|
||||
s, _ := os.Stat(config.KernelImage(file.Name()))
|
||||
kernel_size = s.Size() / 1024
|
||||
}
|
||||
if util.IsFile( config.KmodsImage(file.Name())) {
|
||||
s, _ := os.Stat(config.KmodsImage(file.Name()))
|
||||
kmods_size = s.Size() / 1024
|
||||
}
|
||||
|
||||
if nodemap[file.Name()] > 0 {
|
||||
fmt.Printf("%-38s %-16d %-16d %d\n", file.Name(), kernel_size, kmods_size, nodemap[file.Name()])
|
||||
} else {
|
||||
fmt.Printf("%-38s %-16d %-16d %d\n", file.Name(), kernel_size, kmods_size, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -67,11 +67,11 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
} else if ShowLong == true {
|
||||
fmt.Printf("%-22s %-12s %-26s %-30s %-12s\n", "NODE NAME", "GROUP NAME", "KERNEL VERSION", "VNFS IMAGE", "R-OVERLAY")
|
||||
fmt.Println(strings.Repeat("=", 100))
|
||||
fmt.Printf("%-22s %-12s %-26s %-35s %s\n", "NODE NAME", "GROUP NAME", "KERNEL VERSION", "VNFS IMAGE", "OVERLAYS (S/R)")
|
||||
fmt.Println(strings.Repeat("=", 120))
|
||||
|
||||
for _, node := range nodes {
|
||||
fmt.Printf("%-22s %-12s %-26s %-30s %-12s\n", node.Fqdn.String(), node.GroupName.Fprint(), node.KernelVersion.Fprint(), node.Vnfs.Fprint(), node.RuntimeOverlay.Fprint())
|
||||
fmt.Printf("%-22s %-12s %-26s %-35s %s\n", node.Fqdn.String(), node.GroupName.Fprint(), node.KernelVersion.Fprint(), node.Vnfs.Fprint(), node.SystemOverlay.Fprint() +"/"+ node.RuntimeOverlay.Fprint())
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
@@ -45,7 +45,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
wwlog.Printf(wwlog.INFO, "Updating System Overlays...\n")
|
||||
err := overlay.SystemBuild(updateNodes, true)
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.WARN, "Some system overlays failed to be generated\n")
|
||||
wwlog.Printf(wwlog.WARN, "Some system overlays failed to be generated: %s\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,25 +3,62 @@ package list
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/hpcng/warewulf/internal/pkg/config"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
"github.com/hpcng/warewulf/internal/pkg/vnfs"
|
||||
"github.com/spf13/cobra"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
config := config.New()
|
||||
nconfig, _ := node.New()
|
||||
nodes, _ := nconfig.FindAllNodes()
|
||||
nodemap := make(map[string]int)
|
||||
|
||||
files, err := ioutil.ReadDir(config.VnfsImageParentDir())
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
||||
os.Exit(1)
|
||||
for _, n := range nodes {
|
||||
nodemap[n.Vnfs.String()] ++
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
fmt.Println(f.Name())
|
||||
}
|
||||
images, _ := ioutil.ReadDir(config.VnfsImageParentDir())
|
||||
|
||||
fmt.Printf("VNFS LIST: work in progress: %s\n", config.VnfsImageParentDir())
|
||||
fmt.Printf("%-38s %-16s %s\n", "VNFS Name", "VNFS SIZE(k)", "NODES")
|
||||
fmt.Println(strings.Repeat("=", 80))
|
||||
|
||||
for _, file := range images {
|
||||
v, err := vnfs.Load(file.Name())
|
||||
if err == nil {
|
||||
var vnfs_size int64
|
||||
if util.IsFile( config.VnfsImage(file.Name())) {
|
||||
s, _ := os.Stat(config.VnfsImage(file.Name()))
|
||||
vnfs_size = s.Size() / 1024
|
||||
}
|
||||
|
||||
if nodemap[v.Source] > 0 {
|
||||
fmt.Printf("%-38s %-16d %d\n", v.Source, vnfs_size, nodemap[v.Source])
|
||||
} else {
|
||||
fmt.Printf("%-38s %-16d %d\n", v.Source, vnfs_size, 0)
|
||||
}
|
||||
|
||||
}
|
||||
continue
|
||||
|
||||
if util.IsDir(path.Join(config.VnfsImageParentDir(), file.Name())) {
|
||||
var vnfs_size int64
|
||||
if util.IsFile( config.VnfsImage(file.Name())) {
|
||||
s, _ := os.Stat(config.VnfsImage(file.Name()))
|
||||
vnfs_size = s.Size() / 1024
|
||||
}
|
||||
|
||||
if nodemap[file.Name()] > 0 {
|
||||
fmt.Printf("%-38s %-16d %d\n", file.Name(), vnfs_size, nodemap[file.Name()])
|
||||
} else {
|
||||
fmt.Printf("%-38s %-16d %d\n", file.Name(), vnfs_size, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -92,6 +92,10 @@ func (self *Config) VnfsChrootParentDir() string {
|
||||
return fmt.Sprintf("%s/chroot/", self.LocalStateDir)
|
||||
}
|
||||
|
||||
func (self *Config) KernelParentDir() string {
|
||||
return fmt.Sprintf("%s/provision/kernel/", self.LocalStateDir)
|
||||
}
|
||||
|
||||
func (self *Config) SystemOverlaySource(overlayName string) string {
|
||||
if overlayName == "" {
|
||||
wwlog.Printf(wwlog.ERROR, "System overlay name is not defined\n")
|
||||
@@ -132,7 +136,7 @@ func (self *Config) KernelImage(kernelVersion string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s/provision/kernel/vmlinuz-%s", self.LocalStateDir, kernelVersion)
|
||||
return path.Join(self.KernelParentDir(), kernelVersion, "vmlinuz")
|
||||
}
|
||||
|
||||
func (self *Config) KmodsImage(kernelVersion string) string {
|
||||
@@ -146,7 +150,7 @@ func (self *Config) KmodsImage(kernelVersion string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s/provision/kernel/kmods-%s.img", self.LocalStateDir, kernelVersion)
|
||||
return path.Join(self.KernelParentDir(), kernelVersion, "kmods.img")
|
||||
}
|
||||
|
||||
func (self *Config) SystemOverlayImage(nodeName string) string {
|
||||
@@ -177,32 +181,34 @@ func (self *Config) RuntimeOverlayImage(nodeName string) string {
|
||||
return fmt.Sprintf("%s/provision/overlays/runtime/%s.img", self.LocalStateDir, nodeName)
|
||||
}
|
||||
|
||||
func (self *Config) VnfsImageDir(uri string) string {
|
||||
if uri == "" {
|
||||
wwlog.Printf(wwlog.ERROR, "VNFS URI is not defined\n")
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *Config) VnfsImage(vnfsNameClean string) string {
|
||||
if vnfsNameClean == "" {
|
||||
if util.TaintCheck(uri, "^[a-zA-Z0-9-._:]+$") == false {
|
||||
wwlog.Printf(wwlog.ERROR, "VNFS name contains illegal characters: %s\n", uri)
|
||||
return ""
|
||||
}
|
||||
|
||||
return path.Join(self.VnfsImageParentDir(), uri)
|
||||
}
|
||||
|
||||
func (self *Config) VnfsImage(uri string) string {
|
||||
return path.Join(self.VnfsImageDir(uri), "image")
|
||||
}
|
||||
|
||||
func (self *Config) VnfsChroot(uri string) string {
|
||||
if uri == "" {
|
||||
wwlog.Printf(wwlog.ERROR, "VNFS name is not defined\n")
|
||||
return ""
|
||||
}
|
||||
|
||||
if util.TaintCheck(vnfsNameClean, "^[a-zA-Z0-9-._:]+$") == false {
|
||||
wwlog.Printf(wwlog.ERROR, "Runtime overlay name contains illegal characters: %s\n", vnfsNameClean)
|
||||
if util.TaintCheck(uri, "^[a-zA-Z0-9-._:]+$") == false {
|
||||
wwlog.Printf(wwlog.ERROR, "VNFS name contains illegal characters: %s\n", uri)
|
||||
return ""
|
||||
}
|
||||
|
||||
return path.Join(self.VnfsImageParentDir(), vnfsNameClean)
|
||||
return path.Join(self.VnfsChrootParentDir(), uri)
|
||||
}
|
||||
|
||||
func (self *Config) VnfsChroot(vnfsNameClean string) string {
|
||||
if vnfsNameClean == "" {
|
||||
wwlog.Printf(wwlog.ERROR, "VNFS name is not defined\n")
|
||||
return ""
|
||||
}
|
||||
|
||||
if util.TaintCheck(vnfsNameClean, "^[a-zA-Z0-9-._:]+$") == false {
|
||||
wwlog.Printf(wwlog.ERROR, "Runtime overlay name contains illegal characters: %s\n", vnfsNameClean)
|
||||
return ""
|
||||
}
|
||||
|
||||
return path.Join(self.VnfsChrootParentDir(), vnfsNameClean)
|
||||
}
|
||||
|
||||
|
||||
@@ -98,32 +98,11 @@ func (self *nodeYaml) SetGroupVal(groupID string, entry string, value string) er
|
||||
wwlog.Printf(wwlog.VERBOSE, "Setting group %s to: %s = '%s'\n", groupID, entry, value )
|
||||
|
||||
switch strings.ToUpper(entry) {
|
||||
case "VNFS":
|
||||
util.ValidateOrDie("VNFS", entry, "^[a-zA-Z0-9-._]*$")
|
||||
self.NodeGroups[groupID].Vnfs = value
|
||||
case "KERNEL":
|
||||
util.ValidateOrDie("Kernel Version", entry, "^[a-zA-Z0-9-._]*$")
|
||||
self.NodeGroups[groupID].KernelVersion = value
|
||||
case "DOMAINSUFFIX":
|
||||
util.ValidateOrDie("Domain", entry, "^[a-zA-Z0-9-._]*$")
|
||||
self.NodeGroups[groupID].DomainSuffix = value
|
||||
case "IPXE":
|
||||
util.ValidateOrDie("iPXE Template", entry, "^[a-zA-Z0-9-._]*$")
|
||||
self.NodeGroups[groupID].Ipxe = value
|
||||
case "SYSTEMOVERLAY":
|
||||
util.ValidateOrDie("System Overlay", entry, "^[a-zA-Z0-9-._]*$")
|
||||
self.NodeGroups[groupID].SystemOverlay = value
|
||||
case "RUNTIMEOVERLAY":
|
||||
util.ValidateOrDie("Runtime Overlay", entry, "^[a-zA-Z0-9-._]*$")
|
||||
self.NodeGroups[groupID].RuntimeOverlay = value
|
||||
case "IPMIUSERNAME":
|
||||
util.ValidateOrDie("IPMI Username", entry, "^[a-zA-Z0-9-._]*$")
|
||||
self.NodeGroups[groupID].IpmiUserName = value
|
||||
case "IPMIPASSWORD":
|
||||
util.ValidateOrDie("IPMI Password", entry, "^[a-zA-Z0-9-._]*$")
|
||||
self.NodeGroups[groupID].IpmiPassword = value
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
return errors.New("Group does not exist: " +groupID)
|
||||
}
|
||||
@@ -152,12 +131,6 @@ func (self *nodeYaml) SetNodeVal(groupID string, nodeID string, entry string, va
|
||||
case "IPXE":
|
||||
util.ValidateOrDie("iPXE Template", entry, "^[a-zA-Z0-9-._]*$")
|
||||
self.NodeGroups[groupID].Nodes[nodeID].Ipxe = value
|
||||
case "SYSTEMOVERLAY":
|
||||
util.ValidateOrDie("System Overlay", entry, "^[a-zA-Z0-9-._]*$")
|
||||
self.NodeGroups[groupID].Nodes[nodeID].SystemOverlay = value
|
||||
case "RUNTIMEOVERLAY":
|
||||
util.ValidateOrDie("Runtime Overlay", entry, "^[a-zA-Z0-9-._]*$")
|
||||
self.NodeGroups[groupID].Nodes[nodeID].RuntimeOverlay = value
|
||||
case "HOSTNAME":
|
||||
util.ValidateOrDie("Hostname", entry, "^[a-zA-Z0-9-._]*$")
|
||||
self.NodeGroups[groupID].Nodes[nodeID].Hostname = value
|
||||
@@ -192,7 +165,7 @@ func (self *nodeYaml) SetNodeNet(groupID string, nodeID string, netDev string, e
|
||||
if _, ok := self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev]; ok {
|
||||
wwlog.Printf(wwlog.VERBOSE, "Editing existing node NetDev entry for node: %s/%s\n", groupID, nodeID)
|
||||
} else {
|
||||
var nd netDevs
|
||||
var nd NetDevs
|
||||
self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev] = &nd
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -2,8 +2,9 @@ package node
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/hpcng/warewulf/internal/pkg/config"
|
||||
"github.com/hpcng/warewulf/internal/pkg/errors"
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
"github.com/hpcng/warewulf/internal/pkg/vnfs"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
"gopkg.in/yaml.v2"
|
||||
"io/ioutil"
|
||||
@@ -11,7 +12,6 @@ import (
|
||||
)
|
||||
|
||||
const ConfigFile = "/etc/warewulf/nodes.conf"
|
||||
const LocalStateDir = "/var/warewulf"
|
||||
|
||||
func init() {
|
||||
//TODO: Check to make sure nodes.conf is found
|
||||
@@ -19,45 +19,65 @@ func init() {
|
||||
}
|
||||
|
||||
type nodeYaml struct {
|
||||
NodeGroups map[string]*nodeGroup //`yaml:"nodegroups"`
|
||||
Profiles map[string]*profileConfig
|
||||
NodeGroups map[string]*nodeGroup
|
||||
Hwaddrs map[string]NodeInfo
|
||||
}
|
||||
|
||||
type profileConfig struct {
|
||||
Vnfs string `yaml:"vnfs"`
|
||||
Ipxe string `yaml:"ipxe template,omitempty"`
|
||||
KernelVersion string `yaml:"kernel version"`
|
||||
KernelArgs string `yaml:"kernel args"`
|
||||
IpmiUserName string `yaml:"ipmi username,omitempty"`
|
||||
IpmiPassword string `yaml:"ipmi password,omitempty"`
|
||||
DomainSuffix string `yaml:"domain suffix,omitempty"`
|
||||
RuntimeOverlay []OverlayEntry `yaml:"runtime overlay files,omitempty"`
|
||||
SystemOverlay []OverlayEntry `yaml:"system overlay files,omitempty"`
|
||||
}
|
||||
|
||||
type OverlayEntry struct {
|
||||
Path string `yaml:"path,omitempty"`
|
||||
File bool `yaml:"file,omitempty"`
|
||||
Dir bool `yaml:"dir,omitempty"`
|
||||
Link bool `yaml:"link,omitempty"`
|
||||
Template bool `yaml:"template,omitempty"`
|
||||
Mode int32 `yaml:"mode,omitempty"`
|
||||
Owner string `yaml:"owner,omitempty"`
|
||||
Group string `yaml:"group,omitempty"`
|
||||
Source string `yaml:"source,omitempty"`
|
||||
Sources []string `yaml:"sources,omitempty"`
|
||||
}
|
||||
|
||||
type nodeGroup struct {
|
||||
Comment string
|
||||
Vnfs string `yaml:"vnfs"`
|
||||
Ipxe string `yaml:"ipxe template,omitempty"`
|
||||
SystemOverlay string `yaml:"system overlay,omitempty""`
|
||||
RuntimeOverlay string `yaml:"runtime overlay""`
|
||||
DomainSuffix string `yaml:"domain suffix"`
|
||||
KernelVersion string `yaml:"kernel version"`
|
||||
KernelArgs string `yaml:"kernel args"`
|
||||
IpmiUserName string `yaml:"ipmi username,omitempty"`
|
||||
IpmiPassword string `yaml:"ipmi password,omitempty"`
|
||||
Nodes map[string]*nodeEntry
|
||||
Comment string
|
||||
DomainSuffix string `yaml:"domain suffix"`
|
||||
Profiles []string `yaml:"profiles"`
|
||||
Nodes map[string]*nodeEntry
|
||||
}
|
||||
|
||||
type nodeEntry struct {
|
||||
Hostname string `yaml:"hostname,omitempty"`
|
||||
Vnfs string `yaml:"vnfs,omitempty"`
|
||||
Ipxe string `yaml:"ipxe template,omitempty"`
|
||||
SystemOverlay string `yaml:"system overlay,omitempty"`
|
||||
RuntimeOverlay string `yaml:"runtime overlay,omitempty"`
|
||||
DomainSuffix string `yaml:"domain suffix,omitempty"`
|
||||
KernelVersion string `yaml:"kernel version,omitempty"`
|
||||
KernelArgs string `yaml:"kernel args,omitempty"`
|
||||
IpmiIpaddr string `yaml:"ipmi ipaddr,omitempty"`
|
||||
IpmiUserName string `yaml:"ipmi username,omitempty"`
|
||||
IpmiPassword string `yaml:"ipmi password,omitempty"`
|
||||
NetDevs map[string]*netDevs
|
||||
Hostname string `yaml:"hostname,omitempty"`
|
||||
Vnfs string `yaml:"vnfs"`
|
||||
Ipxe string `yaml:"ipxe template,omitempty"`
|
||||
KernelVersion string `yaml:"kernel version"`
|
||||
KernelArgs string `yaml:"kernel args"`
|
||||
IpmiUserName string `yaml:"ipmi username,omitempty"`
|
||||
IpmiPassword string `yaml:"ipmi password,omitempty"`
|
||||
DomainSuffix string `yaml:"domain suffix,omitempty"`
|
||||
IpmiIpaddr string `yaml:"ipmi ipaddr,omitempty"`
|
||||
Profiles []string `yaml:"profiles"`
|
||||
RuntimeOverlay []OverlayEntry `yaml:"system overlay files,omitempty"`
|
||||
SystemOverlay []OverlayEntry `yaml:"runtime overlay files,omitempty"`
|
||||
NetDevs map[string]*NetDevs
|
||||
}
|
||||
|
||||
type netDevs struct {
|
||||
Type string `yaml:"type,omitempty"`
|
||||
Hwaddr string
|
||||
Ipaddr string
|
||||
Netmask string
|
||||
Gateway string `yaml:"gateway,omitempty"`
|
||||
type NetDevs struct {
|
||||
Type string `yaml:"type,omitempty"`
|
||||
Hwaddr string
|
||||
Ipaddr string
|
||||
Netmask string
|
||||
Gateway string `yaml:"gateway,omitempty"`
|
||||
}
|
||||
|
||||
type EntryInfo struct {
|
||||
@@ -67,39 +87,43 @@ type EntryInfo struct {
|
||||
}
|
||||
|
||||
type NodeInfo struct {
|
||||
Id EntryInfo
|
||||
Gid EntryInfo
|
||||
Uid EntryInfo
|
||||
GroupName EntryInfo
|
||||
HostName EntryInfo
|
||||
DomainName EntryInfo
|
||||
Fqdn EntryInfo
|
||||
Vnfs EntryInfo
|
||||
Ipxe EntryInfo
|
||||
SystemOverlay EntryInfo
|
||||
RuntimeOverlay EntryInfo
|
||||
KernelVersion EntryInfo
|
||||
KernelArgs EntryInfo
|
||||
IpmiIpaddr EntryInfo
|
||||
IpmiUserName EntryInfo
|
||||
IpmiPassword EntryInfo
|
||||
NetDevs map[string]*netDevs
|
||||
Id string
|
||||
Gid string
|
||||
Uid string
|
||||
GroupName string
|
||||
HostName string
|
||||
DomainName string
|
||||
Fqdn string
|
||||
Vnfs string
|
||||
VnfsRoot string
|
||||
Ipxe string
|
||||
KernelVersion string
|
||||
KernelArgs string
|
||||
IpmiIpaddr string
|
||||
IpmiUserName string
|
||||
IpmiPassword string
|
||||
Profiles []string
|
||||
RuntimeOverlay []OverlayEntry
|
||||
SystemOverlay []OverlayEntry
|
||||
NetDevs map[string]*NetDevs
|
||||
}
|
||||
|
||||
type GroupInfo struct {
|
||||
Id EntryInfo
|
||||
GroupName EntryInfo
|
||||
DomainName EntryInfo
|
||||
Vnfs EntryInfo
|
||||
Ipxe EntryInfo
|
||||
SystemOverlay EntryInfo
|
||||
RuntimeOverlay EntryInfo
|
||||
KernelVersion EntryInfo
|
||||
KernelArgs EntryInfo
|
||||
IpmiUserName EntryInfo
|
||||
IpmiPassword EntryInfo
|
||||
Id string
|
||||
GroupName string
|
||||
DomainName string
|
||||
Vnfs string
|
||||
Ipxe string
|
||||
SystemOverlay string
|
||||
RuntimeOverlay string
|
||||
KernelVersion string
|
||||
KernelArgs string
|
||||
IpmiUserName string
|
||||
IpmiPassword string
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (i *EntryInfo) Default (value string) {
|
||||
if value == "" {
|
||||
return
|
||||
@@ -174,17 +198,9 @@ func (self *nodeYaml) FindAllGroups() ([]GroupInfo, error) {
|
||||
for groupname, group := range self.NodeGroups {
|
||||
var g GroupInfo
|
||||
|
||||
g.Id.Set(groupname)
|
||||
g.GroupName.Set(groupname)
|
||||
g.RuntimeOverlay.Set(group.RuntimeOverlay)
|
||||
g.SystemOverlay.Set(group.SystemOverlay)
|
||||
g.Ipxe.Set(group.Ipxe)
|
||||
g.KernelVersion.Set(group.KernelVersion)
|
||||
g.KernelArgs.Set(group.KernelArgs)
|
||||
g.Vnfs.Set(group.Vnfs)
|
||||
g.IpmiUserName.Set(group.IpmiUserName)
|
||||
g.IpmiPassword.Set(group.IpmiPassword)
|
||||
g.DomainName.Set(group.DomainSuffix)
|
||||
g.Id = groupname
|
||||
g.GroupName = groupname
|
||||
g.DomainName = group.DomainSuffix
|
||||
|
||||
// TODO: Validate or die on all inputs
|
||||
|
||||
@@ -201,55 +217,93 @@ func (self *nodeYaml) FindAllNodes() ([]NodeInfo, error) {
|
||||
for nodename, node := range group.Nodes {
|
||||
var n NodeInfo
|
||||
|
||||
n.Id.Set(nodename)
|
||||
n.Gid.Set(groupname)
|
||||
n.GroupName.Set(groupname)
|
||||
n.HostName.Set(node.Hostname)
|
||||
n.IpmiIpaddr.Set(node.IpmiIpaddr)
|
||||
n.Id = nodename
|
||||
n.Gid = groupname
|
||||
n.GroupName = groupname
|
||||
n.HostName = node.Hostname
|
||||
n.Profiles = node.Profiles
|
||||
n.IpmiIpaddr = node.IpmiIpaddr
|
||||
|
||||
n.Vnfs.Set(group.Vnfs)
|
||||
n.SystemOverlay.Set(group.SystemOverlay)
|
||||
n.RuntimeOverlay.Set(group.RuntimeOverlay)
|
||||
n.KernelVersion.Set(group.KernelVersion)
|
||||
n.KernelArgs.Set(group.KernelArgs)
|
||||
n.DomainName.Set(group.DomainSuffix)
|
||||
n.Ipxe.Set(group.Ipxe)
|
||||
n.IpmiUserName.Set(group.IpmiUserName)
|
||||
n.IpmiPassword.Set(group.IpmiPassword)
|
||||
if len(n.Profiles) == 0 {
|
||||
n.Profiles = append(n.Profiles, "default")
|
||||
}
|
||||
|
||||
n.Vnfs.Override(node.Vnfs)
|
||||
n.SystemOverlay.Override(node.SystemOverlay)
|
||||
n.RuntimeOverlay.Override(node.RuntimeOverlay)
|
||||
n.KernelVersion.Override(node.KernelVersion)
|
||||
n.KernelArgs.Override(node.KernelArgs)
|
||||
n.DomainName.Override(node.DomainSuffix)
|
||||
n.Ipxe.Override(node.Ipxe)
|
||||
n.IpmiUserName.Override(node.IpmiUserName)
|
||||
n.IpmiPassword.Override(node.IpmiPassword)
|
||||
|
||||
n.RuntimeOverlay.Default("default")
|
||||
n.SystemOverlay.Default("default")
|
||||
n.Ipxe.Default("default")
|
||||
|
||||
if n.DomainName.Defined() == true {
|
||||
if group.DomainSuffix != "" {
|
||||
n.Fqdn.Set(node.Hostname + "." + group.DomainSuffix)
|
||||
} else if node.DomainSuffix != "" {
|
||||
n.Fqdn.Set(node.Hostname + "." + node.DomainSuffix)
|
||||
for _, p := range n.Profiles {
|
||||
if _, ok := self.Profiles[p]; ok {
|
||||
} else {
|
||||
n.Fqdn.Set(node.Hostname)
|
||||
continue
|
||||
}
|
||||
if self.Profiles[p].Vnfs != "" {
|
||||
n.Vnfs = self.Profiles[p].Vnfs
|
||||
}
|
||||
if self.Profiles[p].KernelVersion != "" {
|
||||
n.KernelVersion = self.Profiles[p].KernelVersion
|
||||
}
|
||||
if self.Profiles[p].KernelArgs != "" {
|
||||
n.KernelArgs = self.Profiles[p].KernelArgs
|
||||
}
|
||||
if self.Profiles[p].Ipxe != "" {
|
||||
n.Ipxe = self.Profiles[p].Ipxe
|
||||
}
|
||||
if self.Profiles[p].IpmiUserName != "" {
|
||||
n.IpmiUserName = self.Profiles[p].IpmiUserName
|
||||
}
|
||||
if self.Profiles[p].IpmiPassword != "" {
|
||||
n.IpmiPassword = self.Profiles[p].IpmiPassword
|
||||
}
|
||||
if self.Profiles[p].DomainSuffix != "" {
|
||||
n.DomainName = self.Profiles[p].DomainSuffix
|
||||
}
|
||||
|
||||
for _, ro := range self.Profiles[p].RuntimeOverlay {
|
||||
n.RuntimeOverlay = append(n.RuntimeOverlay, ro)
|
||||
}
|
||||
for _, so := range self.Profiles[p].SystemOverlay {
|
||||
n.SystemOverlay = append(n.SystemOverlay, so)
|
||||
}
|
||||
}
|
||||
|
||||
n.NetDevs = node.NetDevs
|
||||
if node.DomainSuffix != "" {
|
||||
n.DomainName = node.DomainSuffix
|
||||
} else if group.DomainSuffix != "" {
|
||||
n.DomainName = group.DomainSuffix
|
||||
}
|
||||
if node.Vnfs != "" {
|
||||
n.Vnfs = node.Vnfs
|
||||
}
|
||||
if node.KernelVersion != "" {
|
||||
n.KernelVersion = node.KernelVersion
|
||||
}
|
||||
if node.KernelArgs != "" {
|
||||
n.KernelArgs = node.KernelArgs
|
||||
}
|
||||
if node.Ipxe != "" {
|
||||
n.Ipxe = node.Ipxe
|
||||
}
|
||||
if node.IpmiUserName != "" {
|
||||
n.IpmiUserName = node.IpmiUserName
|
||||
}
|
||||
if node.IpmiPassword != "" {
|
||||
n.IpmiPassword = node.IpmiPassword
|
||||
}
|
||||
|
||||
util.ValidateOrDie(n.Fqdn.String() +":group name", n.GroupName.String(), "^[a-zA-Z0-9-._]*$")
|
||||
util.ValidateOrDie(n.Fqdn.String() +":vnfs", n.Vnfs.String(), "^[a-zA-Z0-9-._:/]*$")
|
||||
util.ValidateOrDie(n.Fqdn.String() +":system overlay", n.SystemOverlay.String(), "^[a-zA-Z0-9-._]*$")
|
||||
util.ValidateOrDie(n.Fqdn.String() +":runtime overlay", n.RuntimeOverlay.String(), "^[a-zA-Z0-9-._]*$")
|
||||
util.ValidateOrDie(n.Fqdn.String() +":domain suffix", n.DomainName.String(), "^[a-zA-Z0-9-._]*$")
|
||||
util.ValidateOrDie(n.Fqdn.String() +":hostname", n.HostName.String(), "^[a-zA-Z0-9-_]*$")
|
||||
util.ValidateOrDie(n.Fqdn.String() +":kernel version", n.KernelVersion.String(), "^[a-zA-Z0-9-._]*$")
|
||||
if n.Ipxe == "" {
|
||||
n.Ipxe = "default"
|
||||
}
|
||||
if n.KernelArgs == "" {
|
||||
n.KernelArgs = "crashkernel=no quiet"
|
||||
}
|
||||
|
||||
config := config.New()
|
||||
n.VnfsRoot = config.VnfsChroot(vnfs.CleanName(n.Vnfs))
|
||||
|
||||
if n.DomainName != "" {
|
||||
n.Fqdn = node.Hostname + "." + n.DomainName
|
||||
} else {
|
||||
n.Fqdn = node.Hostname
|
||||
}
|
||||
|
||||
n.NetDevs = node.NetDevs
|
||||
|
||||
ret = append(ret, n)
|
||||
}
|
||||
@@ -296,7 +350,7 @@ func (nodes *nodeYaml) SearchByName(search string) ([]NodeInfo, error) {
|
||||
n, _ := nodes.FindAllNodes()
|
||||
|
||||
for _, node := range n {
|
||||
b, _ := regexp.MatchString(search, node.Fqdn.String())
|
||||
b, _ := regexp.MatchString(search, node.Fqdn)
|
||||
if b == true {
|
||||
ret = append(ret, node)
|
||||
}
|
||||
@@ -312,7 +366,7 @@ func (nodes *nodeYaml) SearchByNameList(searchList []string) ([]NodeInfo, error)
|
||||
|
||||
for _, search := range searchList {
|
||||
for _, node := range n {
|
||||
b, _ := regexp.MatchString(search, node.Fqdn.String())
|
||||
b, _ := regexp.MatchString(search, node.Fqdn)
|
||||
if b == true {
|
||||
ret = append(ret, node)
|
||||
}
|
||||
@@ -320,4 +374,4 @@ func (nodes *nodeYaml) SearchByNameList(searchList []string) ([]NodeInfo, error)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
}
|
||||
43
internal/pkg/overlay/funcmap.go
Normal file
43
internal/pkg/overlay/funcmap.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package overlay
|
||||
|
||||
import (
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
"github.com/hpcng/warewulf/internal/pkg/vnfs"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func templateFileInclude(path string) string {
|
||||
wwlog.Printf(wwlog.DEBUG, "Including file into template: %s\n", path)
|
||||
content, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.WARN, "Could not include file into template: %s\n", err)
|
||||
}
|
||||
return strings.TrimSuffix(string(content), "\n")
|
||||
}
|
||||
|
||||
func templateVnfsFileInclude(vnfsname string, filepath string) string {
|
||||
wwlog.Printf(wwlog.DEBUG, "Including VNFS file into template: %s: %s\n", vnfsname, filepath)
|
||||
|
||||
v, err := vnfs.Load(vnfsname)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
vnfsDir := v.Chroot
|
||||
|
||||
if util.IsDir(vnfsDir) == false {
|
||||
wwlog.Printf(wwlog.WARN, "Template requesting file from non-imported VNFS: %s (%s)\n", vnfsname, filepath)
|
||||
return ""
|
||||
}
|
||||
wwlog.Printf(wwlog.DEBUG, "IncludeVnfs file from: %s/%s\n", vnfsDir, filepath)
|
||||
|
||||
content, err := ioutil.ReadFile(path.Join(vnfsDir, filepath))
|
||||
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "Template include: %s\n", err)
|
||||
}
|
||||
return strings.TrimSuffix(string(content), "\n")
|
||||
}
|
||||
@@ -1,41 +1,214 @@
|
||||
package overlay
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/hpcng/warewulf/internal/pkg/config"
|
||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
"github.com/hpcng/warewulf/internal/pkg/vnfs"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
func templateFileInclude(path string) string {
|
||||
wwlog.Printf(wwlog.DEBUG, "Including file into template: %s\n", path)
|
||||
content, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.WARN, "Could not include file into template: %s\n", err)
|
||||
}
|
||||
return strings.TrimSuffix(string(content), "\n")
|
||||
}
|
||||
|
||||
func templateVnfsFileInclude(vnfsname string, filepath string) string {
|
||||
wwlog.Printf(wwlog.DEBUG, "Including VNFS file into template: %s: %s\n", vnfsname, filepath)
|
||||
func OverlayBuild(nodeList []node.NodeInfo, overlayType string) error {
|
||||
config := config.New()
|
||||
v := vnfs.New(vnfsname)
|
||||
|
||||
vnfsdir := config.VnfsChroot(v.NameClean())
|
||||
for _, n := range nodeList {
|
||||
wwlog.Printf(wwlog.DEBUG, "Processing overlay for node: %s\n", n.Fqdn)
|
||||
|
||||
if util.IsDir(config.VnfsImage(vnfs.CleanName(n.Vnfs))) == false {
|
||||
wwlog.Printf(wwlog.WARN, "'%s', VNFS not built: %s\n", n.Fqdn, n.Vnfs)
|
||||
// continue
|
||||
}
|
||||
|
||||
var files []node.OverlayEntry
|
||||
|
||||
tmpDir, err := ioutil.TempDir(os.TempDir(), ".wwctl-runtime-overlay-")
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if overlayType == "system" {
|
||||
wwlog.Printf(wwlog.VERBOSE, "Generating system overlay for node: %s\n", n.Fqdn)
|
||||
files = n.SystemOverlay
|
||||
} else if overlayType == "runtime" {
|
||||
wwlog.Printf(wwlog.VERBOSE, "Generating runtime overlay for node: %s\n", n.Fqdn)
|
||||
files = n.RuntimeOverlay
|
||||
} else {
|
||||
wwlog.Printf(wwlog.ERROR, "overlayType requested is not supported: %s\n", overlayType)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
fullPath := path.Join(tmpDir, file.Path)
|
||||
|
||||
mode := file.Mode
|
||||
if mode == 0 {
|
||||
mode = 0755
|
||||
}
|
||||
|
||||
if file.Dir == true {
|
||||
wwlog.Printf(wwlog.DEBUG, "Creating overlay directory: %s\n", file.Path)
|
||||
err := os.MkdirAll(fullPath, os.FileMode(mode))
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "Could not create parent directory in overlay: %s\n", file.Path)
|
||||
continue
|
||||
}
|
||||
} else if file.File == true {
|
||||
wwlog.Printf(wwlog.DEBUG, "Creating overlay file: %s\n", file.Path)
|
||||
|
||||
err := os.MkdirAll(path.Dir(fullPath), 0755)
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "Could not create parent directory for overlay file: %s\n", file.Dir)
|
||||
continue
|
||||
}
|
||||
|
||||
write, err := os.OpenFile(path.Join(tmpDir, file.Path), os.O_RDWR|os.O_CREATE, os.FileMode(mode))
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if file.Source != "" {
|
||||
tmpl, _ := template.New("string").Parse(file.Source)
|
||||
var tpl bytes.Buffer
|
||||
_ = tmpl.Execute(&tpl, n)
|
||||
string := tpl.String()
|
||||
|
||||
source, err := os.Open(string)
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
||||
source.Close()
|
||||
continue
|
||||
}
|
||||
_, err = io.Copy(write, source)
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
||||
source.Close()
|
||||
continue
|
||||
}
|
||||
source.Close()
|
||||
}
|
||||
|
||||
for _, s := range file.Sources {
|
||||
tmpl, _ := template.New("string").Parse(s)
|
||||
var tpl bytes.Buffer
|
||||
_ = tmpl.Execute(&tpl, n)
|
||||
string := tpl.String()
|
||||
|
||||
source, err := os.Open(string)
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.WARN, "%s\n", err)
|
||||
source.Close()
|
||||
continue
|
||||
}
|
||||
_, err = io.Copy(write, source)
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.WARN, "%s\n", err)
|
||||
source.Close()
|
||||
continue
|
||||
}
|
||||
source.Close()
|
||||
}
|
||||
|
||||
write.Close()
|
||||
} else if file.Link == true {
|
||||
wwlog.Printf(wwlog.DEBUG, "Creating overlay link: %s\n", file.Path)
|
||||
|
||||
if file.Source != "" {
|
||||
err := os.MkdirAll(path.Dir(fullPath), 0755)
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "Could not create parent directory for overlay file: %s\n", file.Path)
|
||||
continue
|
||||
}
|
||||
err = os.Symlink(file.Source, fullPath)
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.WARN, "Could not create overlay symlink: %s\n", err)
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
wwlog.Printf(wwlog.WARN, "Could not create link, no source defined: %s\n", file.Path)
|
||||
continue
|
||||
}
|
||||
} else if file.Template == true {
|
||||
wwlog.Printf(wwlog.DEBUG, "Creating overlay file from template: %s\n", file.Path)
|
||||
|
||||
err := os.MkdirAll(path.Dir(fullPath), 0755)
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "Could not create parent directory for overlay file: %s\n", file.Path)
|
||||
continue
|
||||
}
|
||||
|
||||
if file.Source != "" {
|
||||
tmpl, err := template.New(path.Base(file.Source)).Funcs(template.FuncMap{
|
||||
"Include": templateFileInclude,
|
||||
"IncludeFromVnfs": templateVnfsFileInclude,
|
||||
}).ParseFiles(file.Source)
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
w, err := os.OpenFile(fullPath, os.O_RDWR|os.O_CREATE, os.FileMode(mode))
|
||||
if err != nil {
|
||||
w.Close()
|
||||
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
err = tmpl.Execute(w, n)
|
||||
if err != nil {
|
||||
w.Close()
|
||||
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
||||
continue
|
||||
}
|
||||
w.Close()
|
||||
}
|
||||
|
||||
} else {
|
||||
wwlog.Printf(wwlog.ERROR, "Overlay file type error: %s\n", file.Path)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var overlayFile string
|
||||
if overlayType == "system" {
|
||||
overlayFile = config.SystemOverlayImage(n.Fqdn)
|
||||
} else if overlayType == "runtime" {
|
||||
overlayFile = config.RuntimeOverlayImage(n.Fqdn)
|
||||
}
|
||||
|
||||
err = os.MkdirAll(path.Dir(overlayFile), 0755)
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "Could not create parent directory for overlay file: %s\n", overlayFile)
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
wwlog.Printf(wwlog.VERBOSE, "Finished generating overlay directory for: %s\n", n.Fqdn)
|
||||
|
||||
os.Chmod(tmpDir, 0755)
|
||||
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)
|
||||
os.RemoveAll(tmpDir)
|
||||
continue
|
||||
}
|
||||
wwlog.Printf(wwlog.INFO, "%-35s: Done\n", n.Fqdn)
|
||||
|
||||
wwlog.Printf(wwlog.DEBUG, "Removing temporary directory: %s\n", tmpDir)
|
||||
os.RemoveAll(tmpDir)
|
||||
|
||||
if util.IsDir(vnfsdir) == false {
|
||||
wwlog.Printf(wwlog.WARN, "Template requesting file from non-imported VNFS: %s (%s)\n", vnfsname, filepath)
|
||||
return ""
|
||||
}
|
||||
wwlog.Printf(wwlog.DEBUG, "IncludeVnfs file from: %s/%s\n", vnfsdir, filepath)
|
||||
|
||||
content, err := ioutil.ReadFile(path.Join(vnfsdir, filepath))
|
||||
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "Template include: %s\n", err)
|
||||
}
|
||||
return strings.TrimSuffix(string(content), "\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,181 +0,0 @@
|
||||
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/vnfs"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
func FindAllRuntimeOverlays() ([]string, error) {
|
||||
config := config.New()
|
||||
var ret []string
|
||||
|
||||
wwlog.Printf(wwlog.DEBUG, "Looking for runtime overlays...")
|
||||
files, err := ioutil.ReadDir(config.RuntimeOverlayDir())
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
wwlog.Printf(wwlog.DEBUG, "Evaluating runtime overlay: %s\n", file.Name())
|
||||
if file.IsDir() == true {
|
||||
ret = append(ret, file.Name())
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
|
||||
func RuntimeOverlayInit(name string) error {
|
||||
config := config.New()
|
||||
|
||||
path := config.RuntimeOverlaySource(name)
|
||||
|
||||
if util.IsDir(path) == true {
|
||||
return errors.New("Runtime overlay already exists: "+name)
|
||||
}
|
||||
|
||||
err := os.MkdirAll(path, 0755)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
func RuntimeBuild(nodeList []node.NodeInfo, force bool) error {
|
||||
config := config.New()
|
||||
|
||||
wwlog.SetIndent(4)
|
||||
|
||||
for _, node := range nodeList {
|
||||
if node.RuntimeOverlay.String() != "" {
|
||||
OverlayDir := config.RuntimeOverlaySource(node.RuntimeOverlay.String())
|
||||
OverlayFile := config.RuntimeOverlayImage(node.Fqdn.String())
|
||||
vnfs := vnfs.New(node.Vnfs.String())
|
||||
|
||||
vnfsDir := config.VnfsChroot(vnfs.NameClean())
|
||||
|
||||
wwlog.Printf(wwlog.VERBOSE, "Building Runtime Overlay for: %s\n", node.Fqdn)
|
||||
|
||||
tmpDir, err := ioutil.TempDir(os.TempDir(), ".wwctl-runtime-overlay-")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if util.IsDir(OverlayDir) == false {
|
||||
wwlog.Printf(wwlog.WARN, "%-35s: Skipped (runtime overlay template not found)\n", node.Fqdn)
|
||||
continue
|
||||
}
|
||||
|
||||
if util.IsDir(vnfsDir) == false {
|
||||
wwlog.Printf(wwlog.WARN, "%-35s: Skipped (VNFS not imported)\n", node.Fqdn)
|
||||
continue
|
||||
}
|
||||
|
||||
err = os.MkdirAll(path.Dir(OverlayFile), 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if force == false {
|
||||
wwlog.Printf(wwlog.DEBUG, "Checking if overlay is required\n")
|
||||
}
|
||||
if util.PathIsNewer(OverlayDir, OverlayFile) {
|
||||
if force == false {
|
||||
wwlog.Printf(wwlog.INFO, "%-35s: Skipping, overlay is current\n", node.Fqdn)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
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, "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, "IncludeFromVnfs": templateVnfsFileInclude}).ParseGlob(path.Join(OverlayDir, destFile + ".ww*"))
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
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, node)
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
} 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", node.Fqdn)
|
||||
|
||||
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", node.Fqdn)
|
||||
|
||||
wwlog.Printf(wwlog.DEBUG, "Removing temporary directory: %s\n", tmpDir)
|
||||
os.RemoveAll(tmpDir)
|
||||
}
|
||||
}
|
||||
|
||||
wwlog.SetIndent(0)
|
||||
return nil
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
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/vnfs"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
func FindAllSystemOverlays() ([]string, error) {
|
||||
config := config.New()
|
||||
var ret []string
|
||||
|
||||
wwlog.Printf(wwlog.DEBUG, "Looking for system overlays...")
|
||||
files, err := ioutil.ReadDir(config.SystemOverlayDir())
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
wwlog.Printf(wwlog.DEBUG, "Evaluating system overlay: %s\n", file.Name())
|
||||
if file.IsDir() == true {
|
||||
ret = append(ret, file.Name())
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
|
||||
func SystemOverlayInit(name string) error {
|
||||
config := config.New()
|
||||
|
||||
path := config.SystemOverlaySource(name)
|
||||
|
||||
if util.IsDir(path) == true {
|
||||
return errors.New("Runtime overlay already exists: "+name)
|
||||
}
|
||||
|
||||
err := os.MkdirAll(path, 0755)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
func SystemBuild(nodeList []node.NodeInfo, force bool) error {
|
||||
config := config.New()
|
||||
|
||||
wwlog.SetIndent(4)
|
||||
|
||||
for _, node := range nodeList {
|
||||
if node.SystemOverlay.String() != "" {
|
||||
OverlayDir := config.SystemOverlaySource(node.SystemOverlay.String())
|
||||
OverlayFile := config.SystemOverlayImage(node.Fqdn.String())
|
||||
vnfs := vnfs.New(node.Vnfs.String())
|
||||
|
||||
vnfsDir := config.VnfsChroot(vnfs.NameClean())
|
||||
|
||||
wwlog.Printf(wwlog.VERBOSE, "Building System Overlay for: %s\n", node.Fqdn)
|
||||
|
||||
tmpDir, err := ioutil.TempDir(os.TempDir(), ".wwctl-system-overlay-")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if util.IsDir(OverlayDir) == false {
|
||||
wwlog.Printf(wwlog.WARN, "%-35s: Skipped (system overlay template not found)\n", node.Fqdn)
|
||||
continue
|
||||
}
|
||||
|
||||
if util.IsDir(vnfsDir) == false {
|
||||
wwlog.Printf(wwlog.WARN, "%-35s: Skipped (VNFS not imported)\n", node.Fqdn)
|
||||
continue
|
||||
}
|
||||
|
||||
err = os.MkdirAll(path.Dir(OverlayFile), 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if force == false {
|
||||
wwlog.Printf(wwlog.DEBUG, "Checking if overlay is required\n")
|
||||
}
|
||||
if util.PathIsNewer(OverlayDir, OverlayFile) {
|
||||
if force == false {
|
||||
wwlog.Printf(wwlog.INFO, "%-35s: Skipping, overlay is current\n", node.Fqdn)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
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, "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, "IncludeFromVnfs": templateVnfsFileInclude}).ParseGlob(path.Join(OverlayDir, destFile + ".ww*"))
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
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, node)
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
} 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", node.Fqdn)
|
||||
|
||||
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 system image overlay: %s\n", err)
|
||||
continue
|
||||
}
|
||||
wwlog.Printf(wwlog.INFO, "%-35s: Done\n", node.Fqdn)
|
||||
|
||||
wwlog.Printf(wwlog.DEBUG, "Removing temporary directory: %s\n", tmpDir)
|
||||
os.RemoveAll(tmpDir)
|
||||
}
|
||||
}
|
||||
|
||||
wwlog.SetIndent(0)
|
||||
return nil
|
||||
}
|
||||
@@ -37,6 +37,8 @@ func DirModTime(path string) (time.Time, error) {
|
||||
}
|
||||
|
||||
func PathIsNewer(source string, compare string) bool {
|
||||
wwlog.Printf(wwlog.DEBUG, "Comparing times on paths: '%s' - '%s'\n", source, compare)
|
||||
|
||||
time1, err := DirModTime(source)
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.DEBUG, "%s\n", err)
|
||||
|
||||
@@ -2,63 +2,61 @@ package vnfs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/hpcng/warewulf/internal/pkg/config"
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
func BuildContainerdir(v VnfsObject, buildForce bool) {
|
||||
config := config.New()
|
||||
func BuildContainerdir(vnfs VnfsObject, buildForce bool) {
|
||||
|
||||
if _, err := os.Stat(v.Source()); err != nil {
|
||||
wwlog.Printf(wwlog.INFO, "%-35s: Skipping (bad path)\n", v.Name())
|
||||
if _, err := os.Stat(vnfs.Source); err != nil {
|
||||
wwlog.Printf(wwlog.INFO, "%-35s: Skipping (bad path)\n", vnfs.Source)
|
||||
return
|
||||
}
|
||||
|
||||
wwlog.Printf(wwlog.DEBUG, "Checking if there have been any updates to the VNFS directory\n")
|
||||
if util.PathIsNewer(v.Source(), config.VnfsImage(v.NameClean())) {
|
||||
if util.PathIsNewer(vnfs.Source, vnfs.Image) {
|
||||
if buildForce == false {
|
||||
wwlog.Printf(wwlog.INFO, "%-35s: Skipping, VNFS is current\n", v.Name())
|
||||
wwlog.Printf(wwlog.INFO, "%-35s: Skipping, VNFS is current\n", vnfs.Name)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
wwlog.Printf(wwlog.DEBUG, "Making the directory: %s\n", path.Dir(config.VnfsImage(v.NameClean())))
|
||||
err := os.MkdirAll(path.Dir(config.VnfsImage(v.NameClean())), 0755)
|
||||
wwlog.Printf(wwlog.DEBUG, "Making parent directory for: %s\n", vnfs.Image)
|
||||
err := os.MkdirAll(path.Dir(vnfs.Image), 0755)
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
wwlog.Printf(wwlog.DEBUG, "Making the directory: %s\n", path.Dir(config.VnfsChroot(v.NameClean())))
|
||||
err = os.MkdirAll(path.Dir(config.VnfsChroot(v.NameClean())), 0755)
|
||||
wwlog.Printf(wwlog.DEBUG, "Making parent directory for: %s\n", vnfs.Chroot)
|
||||
err = os.MkdirAll(path.Dir(vnfs.Chroot), 0755)
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
wwlog.Printf(wwlog.DEBUG, "Building VNFS image: '%s' -> '%s'\n", v.Source(), config.VnfsImage(v.NameClean()))
|
||||
err = buildVnfs(v.Source(), config.VnfsImage(v.NameClean()))
|
||||
wwlog.Printf(wwlog.DEBUG, "Building VNFS image: '%s' -> '%s'\n", vnfs.Source, vnfs.Image)
|
||||
err = buildVnfs(vnfs.Source, vnfs.Image)
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Setup links from OCI rootfs to chroot path
|
||||
_ = os.Remove(config.VnfsChroot(v.NameClean()) + "-link")
|
||||
err = os.Symlink(v.Source(), config.VnfsChroot(v.NameClean())+"-link")
|
||||
_ = os.Remove(vnfs.Chroot + "-link")
|
||||
err = os.Symlink(vnfs.Source, vnfs.Chroot+"-link")
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "Could not create symlink for Chroot: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = os.Rename(config.VnfsChroot(v.NameClean())+"-link", config.VnfsChroot(v.NameClean()))
|
||||
err = os.Rename(vnfs.Chroot + "-link", vnfs.Chroot)
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "Could not rename link: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
wwlog.Printf(wwlog.INFO, "%-35s: Done\n", v.Name())
|
||||
wwlog.Printf(wwlog.INFO, "%-35s: Done\n", vnfs.Name)
|
||||
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
)
|
||||
|
||||
|
||||
func BuildDocker(v VnfsObject, buildForce bool) {
|
||||
wwlog.Printf(wwlog.VERBOSE, "Building OCI Container: %s\n", v.Source())
|
||||
func BuildDocker(vnfs VnfsObject, buildForce bool) {
|
||||
wwlog.Printf(wwlog.VERBOSE, "Building OCI Container: %s\n", vnfs.Source)
|
||||
config := config.New()
|
||||
|
||||
OciCacheDir := config.LocalStateDir + "/oci"
|
||||
@@ -25,7 +25,7 @@ func BuildDocker(v VnfsObject, buildForce bool) {
|
||||
}
|
||||
|
||||
wwlog.Printf(wwlog.VERBOSE, "Downloading OCI container layers\n")
|
||||
sourcePath, err := c.Pull(context.Background(), v.Source(), nil)
|
||||
sourcePath, err := c.Pull(context.Background(), vnfs.Source, nil)
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err)
|
||||
os.Exit(1)
|
||||
@@ -33,10 +33,10 @@ func BuildDocker(v VnfsObject, buildForce bool) {
|
||||
|
||||
hashDestination := VnfsHashDir + path.Base(sourcePath)
|
||||
|
||||
name, err := os.Readlink(config.VnfsImage(v.NameClean()))
|
||||
name, err := os.Readlink(vnfs.Image)
|
||||
if err == nil {
|
||||
if name == hashDestination && buildForce == false {
|
||||
wwlog.Printf(wwlog.INFO, "%-35s: Skipping, VNFS is current\n", v.Name())
|
||||
wwlog.Printf(wwlog.INFO, "%-35s: Skipping, VNFS is current\n", vnfs.Name)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -46,12 +46,16 @@ func BuildDocker(v VnfsObject, buildForce bool) {
|
||||
fmt.Printf("ERROR: %s\n", err)
|
||||
return
|
||||
}
|
||||
err = os.MkdirAll(path.Dir(config.VnfsImage(v.NameClean())), 0755)
|
||||
|
||||
wwlog.Printf(wwlog.DEBUG, "Making parent directory for: %s\n", vnfs.Image)
|
||||
err = os.MkdirAll(path.Dir(vnfs.Image), 0755)
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err)
|
||||
return
|
||||
}
|
||||
err = os.MkdirAll(path.Dir(config.VnfsChroot(v.NameClean())), 0755)
|
||||
|
||||
wwlog.Printf(wwlog.DEBUG, "Making parent directory for: %s\n", vnfs.Chroot)
|
||||
err = os.MkdirAll(path.Dir(vnfs.Chroot), 0755)
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err)
|
||||
return
|
||||
@@ -68,33 +72,33 @@ func BuildDocker(v VnfsObject, buildForce bool) {
|
||||
wwlog.Printf(wwlog.VERBOSE, "Finalizing Build\n")
|
||||
|
||||
// Setup links from OCI image to provision path
|
||||
_ = os.Remove(config.VnfsImage(v.NameClean()) + "-link")
|
||||
err = os.Symlink(hashDestination, config.VnfsImage(v.NameClean())+"-link")
|
||||
_ = os.Remove(vnfs.Image + "-link")
|
||||
err = os.Symlink(hashDestination, vnfs.Image + "-link")
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "Could not create symlink for Image: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = os.Rename(config.VnfsImage(v.NameClean())+"-link", config.VnfsImage(v.NameClean()))
|
||||
err = os.Rename(vnfs.Image + "-link", vnfs.Image)
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "Could not rename link: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Setup links from OCI rootfs to chroot path
|
||||
_ = os.Remove(config.VnfsChroot(v.NameClean()) + "-link")
|
||||
err = os.Symlink(sourcePath, config.VnfsChroot(v.NameClean())+"-link")
|
||||
_ = os.Remove(vnfs.Chroot + "-link")
|
||||
err = os.Symlink(sourcePath, vnfs.Chroot + "-link")
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "Could not create symlink for Chroot: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = os.Rename(config.VnfsChroot(v.NameClean())+"-link", config.VnfsChroot(v.NameClean()))
|
||||
err = os.Rename(vnfs.Chroot + "-link", vnfs.Chroot)
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "Could not rename link: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
||||
wwlog.Printf(wwlog.INFO, "%-35s: Done\n", v.Name())
|
||||
wwlog.Printf(wwlog.INFO, "%-35s: Done\n", vnfs.Source)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,70 +1,175 @@
|
||||
package vnfs
|
||||
|
||||
import (
|
||||
"github.com/hpcng/warewulf/internal/pkg/config"
|
||||
"github.com/hpcng/warewulf/internal/pkg/errors"
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
"gopkg.in/yaml.v2"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type VnfsObject struct {
|
||||
SourcePath string
|
||||
Name string
|
||||
Source string
|
||||
Chroot string
|
||||
Image string
|
||||
Config string
|
||||
}
|
||||
|
||||
func New(s string) VnfsObject {
|
||||
func Load (name string) (VnfsObject, error) {
|
||||
config := config.New()
|
||||
var ret VnfsObject
|
||||
pathFriendlyName := CleanName(name)
|
||||
|
||||
ret.SourcePath = s
|
||||
configFile := path.Join(config.VnfsImageDir(pathFriendlyName), "config.yaml")
|
||||
|
||||
return ret
|
||||
if util.IsFile(configFile) == false {
|
||||
return ret, errors.New("No Configuration for VNFS name: " + configFile)
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadFile(configFile)
|
||||
if err != nil {
|
||||
return ret, errors.New("Error reading VNFS configuration file: " + name)
|
||||
}
|
||||
|
||||
err = yaml.Unmarshal(data, &ret)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *VnfsObject) Name() string {
|
||||
if self.SourcePath == "" {
|
||||
return ""
|
||||
}
|
||||
func CleanName(source string) string {
|
||||
var tmp string
|
||||
|
||||
if strings.HasPrefix(self.SourcePath, "/") {
|
||||
return path.Base(self.SourcePath)
|
||||
}
|
||||
|
||||
return self.SourcePath
|
||||
}
|
||||
|
||||
func (self *VnfsObject) NameClean() string {
|
||||
if self.SourcePath == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
if strings.HasPrefix(self.SourcePath, "/") {
|
||||
return path.Base(self.SourcePath)
|
||||
}
|
||||
uri := strings.Split(self.SourcePath, "://")
|
||||
|
||||
return strings.ReplaceAll(uri[0]+":"+uri[1], "/", "_")
|
||||
}
|
||||
|
||||
func (self *VnfsObject) Source() string {
|
||||
if self.SourcePath == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
return self.SourcePath
|
||||
}
|
||||
|
||||
func Build(uri string, force bool) error {
|
||||
v := New(uri)
|
||||
|
||||
wwlog.Printf(wwlog.VERBOSE, "Building VNFS: %s\n", uri)
|
||||
if strings.HasPrefix(uri, "/") {
|
||||
if strings.HasSuffix(uri, "tar.gz") {
|
||||
//wwlog.Printf(wwlog.WARN, "Building VNFS from local tarball: %s\n", uri)
|
||||
wwlog.Printf(wwlog.WARN, "Building VNFS from local tarball is not supported yet: %s\n", uri)
|
||||
} else {
|
||||
BuildContainerdir(v, force)
|
||||
}
|
||||
if strings.HasPrefix(source, "/") == true {
|
||||
tmp = path.Base(source)
|
||||
} else {
|
||||
BuildDocker(v, force)
|
||||
tmp = source
|
||||
}
|
||||
|
||||
tmp = strings.ReplaceAll(tmp, "://", "-")
|
||||
tmp = strings.ReplaceAll(tmp, "/", ".")
|
||||
tmp = strings.ReplaceAll(tmp, ":", ".")
|
||||
|
||||
return tmp
|
||||
}
|
||||
|
||||
func New(source string) (VnfsObject, error) {
|
||||
var ret VnfsObject
|
||||
config := config.New()
|
||||
|
||||
pathFriendlyName := CleanName(source)
|
||||
|
||||
if strings.HasPrefix(source, "/") == true {
|
||||
ret.Source = source
|
||||
ret.Name = pathFriendlyName
|
||||
} else {
|
||||
tmp := strings.ReplaceAll(source, "://", "-")
|
||||
tmp = strings.ReplaceAll(tmp, "/", ".")
|
||||
tmp = strings.ReplaceAll(tmp, ":", ".")
|
||||
ret.Name = source
|
||||
ret.Source = source
|
||||
}
|
||||
|
||||
ret.Chroot = config.VnfsChroot(pathFriendlyName)
|
||||
ret.Image = config.VnfsImage(pathFriendlyName)
|
||||
ret.Config = path.Join(config.VnfsImageDir(pathFriendlyName), "config.yaml")
|
||||
|
||||
if util.IsFile(ret.Config) {
|
||||
return Load(source)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *VnfsObject) SaveConfig() error {
|
||||
|
||||
out, err := yaml.Marshal(self)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
file, err := os.OpenFile(self.Config, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
_, err = file.WriteString(string(out))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
func Build(name string, force bool) error {
|
||||
|
||||
vnfs, err := New(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
wwlog.Printf(wwlog.VERBOSE, "Building VNFS: %s\n", vnfs.Name)
|
||||
if strings.HasPrefix(vnfs.Source, "/") {
|
||||
if strings.HasSuffix(vnfs.Source, "tar.gz") {
|
||||
//wwlog.Printf(wwlog.WARN, "Building VNFS from local tarball: %s\n", uri)
|
||||
wwlog.Printf(wwlog.WARN, "Building VNFS from local tarball is not supported yet: %s\n", vnfs.Name)
|
||||
} else {
|
||||
BuildContainerdir(vnfs, force)
|
||||
}
|
||||
} else {
|
||||
BuildDocker(vnfs, force)
|
||||
}
|
||||
|
||||
err = vnfs.SaveConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
func (self *VnfsObject) Nameold() string {
|
||||
if self.Source == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
if strings.HasPrefix(self.Source, "/") {
|
||||
return path.Base(self.Source)
|
||||
}
|
||||
|
||||
return self.Source
|
||||
}
|
||||
|
||||
func NameClean1(SourcePath string) string {
|
||||
if SourcePath == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
if strings.HasPrefix(SourcePath, "/") {
|
||||
return path.Base(SourcePath)
|
||||
}
|
||||
uri := strings.Split(SourcePath, "://")
|
||||
|
||||
return strings.ReplaceAll(uri[0]+":"+uri[1], "/", "_")
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
DEVICE=eth0
|
||||
NAME=eth0
|
||||
IPADDR={{.NetDevs.eth0.Ipaddr}}
|
||||
NETMASK={{.NetDevs.eth0.Netmask}}
|
||||
GATEWAY={{.NetDevs.eth0.Gateway}}
|
||||
HWADDR={{.NetDevs.eth0.Hwaddr}}
|
||||
IPADDR={{.Netdev.eth0.Ipaddr}}
|
||||
NETMASK={{.Netdev.eth0.Netmask}}
|
||||
GATEWAY={{.Netdev.eth0.Gateway}}
|
||||
HWADDR={{.Netdev.eth0.Hwaddr}}
|
||||
BOOTPROTO=static
|
||||
ONBOOT=yes
|
||||
|
||||
Reference in New Issue
Block a user