From a4d2e3a0c836e350fa32c6aea4851b3cbcacea58 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Wed, 25 Nov 2020 23:58:38 -0800 Subject: [PATCH] This is a work in progress, some of which will be reverted like overlay handling. --- etc/nodes.conf | 32 +- internal/app/sandbox/main.go | 13 + internal/app/warewulfd/response/ipxe.go | 6 +- internal/app/warewulfd/response/kernel.go | 4 +- internal/app/warewulfd/response/kmods.go | 5 +- internal/app/warewulfd/response/runtime.go | 6 +- internal/app/warewulfd/response/system.go | 4 +- internal/app/warewulfd/response/util.go | 2 +- internal/app/warewulfd/response/vnfs.go | 19 +- internal/app/wwctl/kernel/list/main.go | 43 ++- internal/app/wwctl/node/list/main.go | 6 +- internal/app/wwctl/overlay/build/main.go | 2 +- internal/app/wwctl/vnfs/list/main.go | 55 +++- internal/pkg/config/config.go | 50 +-- internal/pkg/node/modify.go | 31 +- internal/pkg/node/node.go | 286 +++++++++++------- internal/pkg/overlay/funcmap.go | 43 +++ internal/pkg/overlay/overlay.go | 219 ++++++++++++-- internal/pkg/overlay/runtime.go | 181 ----------- internal/pkg/overlay/system.go | 181 ----------- internal/pkg/util/util.go | 2 + internal/pkg/vnfs/containerdir.go | 32 +- internal/pkg/vnfs/docker.go | 32 +- internal/pkg/vnfs/vnfs.go | 201 +++++++++--- .../sysconfig/network-scripts/ifcfg-eth0.ww | 8 +- 25 files changed, 789 insertions(+), 674 deletions(-) create mode 100644 internal/app/sandbox/main.go create mode 100644 internal/pkg/overlay/funcmap.go delete mode 100644 internal/pkg/overlay/runtime.go delete mode 100644 internal/pkg/overlay/system.go diff --git a/etc/nodes.conf b/etc/nodes.conf index b2aa0e9f..586c9ce5 100644 --- a/etc/nodes.conf +++ b/etc/nodes.conf @@ -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 diff --git a/internal/app/sandbox/main.go b/internal/app/sandbox/main.go new file mode 100644 index 00000000..5e2f00e1 --- /dev/null +++ b/internal/app/sandbox/main.go @@ -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") +} diff --git a/internal/app/warewulfd/response/ipxe.go b/internal/app/warewulfd/response/ipxe.go index a1e83c2d..9440b341 100644 --- a/internal/app/warewulfd/response/ipxe.go +++ b/internal/app/warewulfd/response/ipxe.go @@ -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]) diff --git a/internal/app/warewulfd/response/kernel.go b/internal/app/warewulfd/response/kernel.go index 17bd9f7c..8fca6a42 100644 --- a/internal/app/warewulfd/response/kernel.go +++ b/internal/app/warewulfd/response/kernel.go @@ -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 diff --git a/internal/app/warewulfd/response/kmods.go b/internal/app/warewulfd/response/kmods.go index ef0f9787..c5bfe00f 100644 --- a/internal/app/warewulfd/response/kmods.go +++ b/internal/app/warewulfd/response/kmods.go @@ -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 diff --git a/internal/app/warewulfd/response/runtime.go b/internal/app/warewulfd/response/runtime.go index 3e8bc77e..83b0a95d 100644 --- a/internal/app/warewulfd/response/runtime.go +++ b/internal/app/warewulfd/response/runtime.go @@ -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 diff --git a/internal/app/warewulfd/response/system.go b/internal/app/warewulfd/response/system.go index a6729db8..dfa1649b 100644 --- a/internal/app/warewulfd/response/system.go +++ b/internal/app/warewulfd/response/system.go @@ -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 diff --git a/internal/app/warewulfd/response/util.go b/internal/app/warewulfd/response/util.go index 4746af0f..e739f8e1 100644 --- a/internal/app/warewulfd/response/util.go +++ b/internal/app/warewulfd/response/util.go @@ -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 diff --git a/internal/app/warewulfd/response/vnfs.go b/internal/app/warewulfd/response/vnfs.go index 6986926f..2d5eb8ed 100644 --- a/internal/app/warewulfd/response/vnfs.go +++ b/internal/app/warewulfd/response/vnfs.go @@ -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 diff --git a/internal/app/wwctl/kernel/list/main.go b/internal/app/wwctl/kernel/list/main.go index 65384b2a..0e10f4e0 100644 --- a/internal/app/wwctl/kernel/list/main.go +++ b/internal/app/wwctl/kernel/list/main.go @@ -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 } \ No newline at end of file diff --git a/internal/app/wwctl/node/list/main.go b/internal/app/wwctl/node/list/main.go index 3f14b520..a2cfff35 100644 --- a/internal/app/wwctl/node/list/main.go +++ b/internal/app/wwctl/node/list/main.go @@ -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 { diff --git a/internal/app/wwctl/overlay/build/main.go b/internal/app/wwctl/overlay/build/main.go index b927576c..24ed4561 100644 --- a/internal/app/wwctl/overlay/build/main.go +++ b/internal/app/wwctl/overlay/build/main.go @@ -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) } } diff --git a/internal/app/wwctl/vnfs/list/main.go b/internal/app/wwctl/vnfs/list/main.go index 045fb2df..2fa015a5 100644 --- a/internal/app/wwctl/vnfs/list/main.go +++ b/internal/app/wwctl/vnfs/list/main.go @@ -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 } \ No newline at end of file diff --git a/internal/pkg/config/config.go b/internal/pkg/config/config.go index 5c95def5..6743347b 100644 --- a/internal/pkg/config/config.go +++ b/internal/pkg/config/config.go @@ -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) -} - diff --git a/internal/pkg/node/modify.go b/internal/pkg/node/modify.go index b3e01de3..e120f777 100644 --- a/internal/pkg/node/modify.go +++ b/internal/pkg/node/modify.go @@ -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 { diff --git a/internal/pkg/node/node.go b/internal/pkg/node/node.go index 79801880..139c435c 100644 --- a/internal/pkg/node/node.go +++ b/internal/pkg/node/node.go @@ -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 -} +} \ No newline at end of file diff --git a/internal/pkg/overlay/funcmap.go b/internal/pkg/overlay/funcmap.go new file mode 100644 index 00000000..0ed1c5cd --- /dev/null +++ b/internal/pkg/overlay/funcmap.go @@ -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") +} diff --git a/internal/pkg/overlay/overlay.go b/internal/pkg/overlay/overlay.go index 3e5a9721..e7dee1a7 100644 --- a/internal/pkg/overlay/overlay.go +++ b/internal/pkg/overlay/overlay.go @@ -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 } diff --git a/internal/pkg/overlay/runtime.go b/internal/pkg/overlay/runtime.go deleted file mode 100644 index d72e9e88..00000000 --- a/internal/pkg/overlay/runtime.go +++ /dev/null @@ -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 -} diff --git a/internal/pkg/overlay/system.go b/internal/pkg/overlay/system.go deleted file mode 100644 index 9b42dbcf..00000000 --- a/internal/pkg/overlay/system.go +++ /dev/null @@ -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 -} \ No newline at end of file diff --git a/internal/pkg/util/util.go b/internal/pkg/util/util.go index e7889073..34b272e6 100644 --- a/internal/pkg/util/util.go +++ b/internal/pkg/util/util.go @@ -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) diff --git a/internal/pkg/vnfs/containerdir.go b/internal/pkg/vnfs/containerdir.go index 50668bc9..6e2e7897 100644 --- a/internal/pkg/vnfs/containerdir.go +++ b/internal/pkg/vnfs/containerdir.go @@ -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) } diff --git a/internal/pkg/vnfs/docker.go b/internal/pkg/vnfs/docker.go index 4965eb2a..e46abf81 100644 --- a/internal/pkg/vnfs/docker.go +++ b/internal/pkg/vnfs/docker.go @@ -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 } diff --git a/internal/pkg/vnfs/vnfs.go b/internal/pkg/vnfs/vnfs.go index 146a2f0e..4c428a4f 100644 --- a/internal/pkg/vnfs/vnfs.go +++ b/internal/pkg/vnfs/vnfs.go @@ -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], "/", "_") +} \ No newline at end of file diff --git a/overlays/system/default/etc/sysconfig/network-scripts/ifcfg-eth0.ww b/overlays/system/default/etc/sysconfig/network-scripts/ifcfg-eth0.ww index 9b27c5af..99ec46a8 100644 --- a/overlays/system/default/etc/sysconfig/network-scripts/ifcfg-eth0.ww +++ b/overlays/system/default/etc/sysconfig/network-scripts/ifcfg-eth0.ww @@ -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