From e5e23b5868bde4b22a170f2400781300dadd5eed Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Mon, 23 Nov 2020 23:11:20 -0800 Subject: [PATCH 01/32] Changed backend node API to account for default and overrides for UI --- etc/nodes.conf | 1 - internal/app/warewulfd/response/ipxe.go | 10 +- internal/app/warewulfd/response/kernel.go | 6 +- internal/app/warewulfd/response/kmods.go | 6 +- internal/app/warewulfd/response/runtime.go | 8 +- internal/app/warewulfd/response/system.go | 6 +- internal/app/warewulfd/response/util.go | 2 +- internal/app/warewulfd/response/vnfs.go | 6 +- internal/app/wwctl/build/main.go | 4 +- internal/app/wwctl/group/delete/main.go | 2 +- internal/app/wwctl/group/list/main.go | 2 +- internal/app/wwctl/group/set/main.go | 52 +- internal/app/wwctl/group/set/root.go | 4 +- internal/app/wwctl/kernel/build/main.go | 4 +- internal/app/wwctl/node/add/main.go | 2 + internal/app/wwctl/node/delete/main.go | 4 +- internal/app/wwctl/node/list/main.go | 32 +- internal/app/wwctl/node/list/root.go | 2 + internal/app/wwctl/node/poweroff/power.go | 4 +- internal/app/wwctl/node/poweron/power.go | 4 +- internal/app/wwctl/node/powerstatus/power.go | 4 +- internal/app/wwctl/node/set/main.go | 70 +-- internal/app/wwctl/node/set/root.go | 6 +- internal/app/wwctl/overlay/build/main.go | 4 +- internal/app/wwctl/overlay/chmod/main.go | 4 +- internal/app/wwctl/overlay/create/main.go | 4 +- internal/app/wwctl/overlay/delete/main.go | 4 +- internal/app/wwctl/overlay/edit/main.go | 4 +- internal/app/wwctl/overlay/imprt/main.go | 4 +- internal/app/wwctl/overlay/list/main.go | 8 +- internal/app/wwctl/overlay/mkdir/main.go | 4 +- internal/app/wwctl/vnfs/build/main.go | 4 +- internal/pkg/node/modify.go | 249 +++++++++ internal/pkg/node/node.go | 501 ++++++------------- internal/pkg/overlay/runtime.go | 8 +- internal/pkg/overlay/system.go | 8 +- 36 files changed, 569 insertions(+), 478 deletions(-) create mode 100644 internal/pkg/node/modify.go diff --git a/etc/nodes.conf b/etc/nodes.conf index 40cf1e3c..b2aa0e9f 100644 --- a/etc/nodes.conf +++ b/etc/nodes.conf @@ -43,7 +43,6 @@ nodegroups: nodes: n0000: hostname: localtest - kernel version: 3.10.0-1127.el7.x86_64 system overlay: test netdevs: eth0: diff --git a/internal/app/warewulfd/response/ipxe.go b/internal/app/warewulfd/response/ipxe.go index 6a9e2d3b..a1e83c2d 100644 --- a/internal/app/warewulfd/response/ipxe.go +++ b/internal/app/warewulfd/response/ipxe.go @@ -46,7 +46,7 @@ func IpxeSend(w http.ResponseWriter, req *http.Request) { return } - if node.HostName != "" { + if node.HostName.Defined() == true { conf := config.New() log.Printf("IPXE: %15s: %s\n", node.Fqdn, req.URL.Path) @@ -62,13 +62,13 @@ func IpxeSend(w http.ResponseWriter, req *http.Request) { var replace iPxeTemplate - replace.Fqdn = node.Fqdn + replace.Fqdn = node.Fqdn.String() replace.Ipaddr = conf.Ipaddr replace.Port = strconv.Itoa(conf.Port) - replace.Hostname = node.HostName + replace.Hostname = node.HostName.String() replace.Hwaddr = url[2] - replace.Vnfs = node.Vnfs - replace.Kernelargs = node.KernelArgs + replace.Vnfs = node.Vnfs.String() + replace.Kernelargs = node.KernelArgs.String() err = tmpl.Execute(w, replace) if err != nil { diff --git a/internal/app/warewulfd/response/kernel.go b/internal/app/warewulfd/response/kernel.go index 8613e9b1..17bd9f7c 100644 --- a/internal/app/warewulfd/response/kernel.go +++ b/internal/app/warewulfd/response/kernel.go @@ -16,10 +16,10 @@ func KernelSend(w http.ResponseWriter, req *http.Request) { return } - if node.KernelVersion != "" { - fileName := config.KernelImage(node.KernelVersion) + if node.KernelVersion.Defined() == true { + fileName := config.KernelImage(node.KernelVersion.String()) - err := sendFile(w, fileName, node.Fqdn) + err := sendFile(w, fileName, node.Fqdn.String()) if err != nil { log.Printf("ERROR: %s\n", err) } else { diff --git a/internal/app/warewulfd/response/kmods.go b/internal/app/warewulfd/response/kmods.go index 90043190..ef0f9787 100644 --- a/internal/app/warewulfd/response/kmods.go +++ b/internal/app/warewulfd/response/kmods.go @@ -15,10 +15,10 @@ func KmodsSend(w http.ResponseWriter, req *http.Request) { log.Println(err) return } - if node.KernelVersion != "" { - fileName := config.KmodsImage(node.KernelVersion) + if node.KernelVersion.Defined() == true { + fileName := config.KmodsImage(node.KernelVersion.String()) - err := sendFile(w, fileName, node.Fqdn) + err := sendFile(w, fileName, node.Fqdn.String()) if err != nil { log.Printf("ERROR: %s\n", err) } else { diff --git a/internal/app/warewulfd/response/runtime.go b/internal/app/warewulfd/response/runtime.go index 06b30309..3e8bc77e 100644 --- a/internal/app/warewulfd/response/runtime.go +++ b/internal/app/warewulfd/response/runtime.go @@ -47,7 +47,7 @@ func RuntimeOverlaySend(w http.ResponseWriter, req *http.Request) { return } - if node.Fqdn == "" { + if node.Fqdn.Defined() == false { log.Printf("UNKNOWN: %15s: %s\n", remote[0], req.URL.Path) w.WriteHeader(404) return @@ -55,10 +55,10 @@ func RuntimeOverlaySend(w http.ResponseWriter, req *http.Request) { log.Printf("REQ: %15s: %s\n", node.Fqdn, req.URL.Path) } - if node.RuntimeOverlay != "" { - fileName := config.RuntimeOverlayImage(node.Fqdn) + if node.RuntimeOverlay.Defined() == true { + fileName := config.RuntimeOverlayImage(node.Fqdn.String()) - err := sendFile(w, fileName, node.Fqdn) + err := sendFile(w, fileName, node.Fqdn.String()) if err != nil { log.Printf("ERROR: %s\n", err) } else { diff --git a/internal/app/warewulfd/response/system.go b/internal/app/warewulfd/response/system.go index ae87fc25..a6729db8 100644 --- a/internal/app/warewulfd/response/system.go +++ b/internal/app/warewulfd/response/system.go @@ -16,10 +16,10 @@ func SystemOverlaySend(w http.ResponseWriter, req *http.Request) { return } - if node.SystemOverlay != "" { - fileName := config.SystemOverlayImage(node.Fqdn) + if node.SystemOverlay.Defined() == true { + fileName := config.SystemOverlayImage(node.Fqdn.String()) - err := sendFile(w, fileName, node.Fqdn) + err := sendFile(w, fileName, node.Fqdn.String()) if err != nil { log.Printf("ERROR: %s\n", err) } else { diff --git a/internal/app/warewulfd/response/util.go b/internal/app/warewulfd/response/util.go index 793ef1fb..4746af0f 100644 --- a/internal/app/warewulfd/response/util.go +++ b/internal/app/warewulfd/response/util.go @@ -27,7 +27,7 @@ func getSanity(req *http.Request) (node.NodeInfo, error) { return ret, errors.New("Could not find node by HW address") } - if ret.Fqdn == "" { + if ret.Fqdn.Defined() == false { log.Printf("UNKNOWN: %15s: %s\n", hwaddr, req.URL.Path) return ret, errors.New("Unknown node HW address: " + hwaddr) } else { diff --git a/internal/app/warewulfd/response/vnfs.go b/internal/app/warewulfd/response/vnfs.go index c6e03fdf..6986926f 100644 --- a/internal/app/warewulfd/response/vnfs.go +++ b/internal/app/warewulfd/response/vnfs.go @@ -17,10 +17,10 @@ func VnfsSend(w http.ResponseWriter, req *http.Request) { return } - if node.Vnfs != "" { - v := vnfs.New(node.Vnfs) + if node.Vnfs.Defined() == true { + v := vnfs.New(node.Vnfs.String()) - err := sendFile(w, config.VnfsImage(v.NameClean()), node.Fqdn) + err := sendFile(w, config.VnfsImage(v.NameClean()), node.Fqdn.String()) if err != nil { log.Printf("ERROR: %s\n", err) } else { diff --git a/internal/app/wwctl/build/main.go b/internal/app/wwctl/build/main.go index 0a2f5edc..353cd5a4 100644 --- a/internal/app/wwctl/build/main.go +++ b/internal/app/wwctl/build/main.go @@ -46,7 +46,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { wwlog.Printf(wwlog.INFO, "Building VNFS images...\n") for _, node := range nodes { - set[node.Vnfs] ++ + set[node.Vnfs.String()] ++ } for e := range set { vnfs.Build(e, buildForce) @@ -60,7 +60,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { wwlog.Printf(wwlog.INFO, "Building Kernel images...\n") for _, node := range nodes { - set[node.KernelVersion] ++ + set[node.KernelVersion.String()] ++ } for e := range set { kernel.Build(e) diff --git a/internal/app/wwctl/group/delete/main.go b/internal/app/wwctl/group/delete/main.go index 97348514..71ee3fd4 100644 --- a/internal/app/wwctl/group/delete/main.go +++ b/internal/app/wwctl/group/delete/main.go @@ -31,7 +31,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { wwlog.Printf(wwlog.ERROR, "%s\n", err) } else { for _, n := range nodes { - if n.GroupName == g { + if n.GroupName.String() == g { numNodes ++ } } diff --git a/internal/app/wwctl/group/list/main.go b/internal/app/wwctl/group/list/main.go index 177ff841..9abbc31e 100644 --- a/internal/app/wwctl/group/list/main.go +++ b/internal/app/wwctl/group/list/main.go @@ -35,7 +35,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } else { fmt.Printf("%-22s %-16s %-30s %-30s %-16s\n", "GROUP NAME", "DOMAINNAME", "KERNEL VERSION", "VNFS IMAGE", "RUNTIME OVERLAY") for _, g := range groups { - fmt.Printf("%-22s %-16s %-30s %-30s %-16s\n", g.GroupName, g.DomainName, g.KernelVersion, g.Vnfs, g.RuntimeOverlay) + fmt.Printf("%-22s %-16s %-30s %-30s %-16s\n", g.GroupName.String(), g.DomainName.String(), g.KernelVersion.String(), g.Vnfs.String(), g.RuntimeOverlay.String()) } } diff --git a/internal/app/wwctl/group/set/main.go b/internal/app/wwctl/group/set/main.go index 4ed4e3e7..e572e600 100644 --- a/internal/app/wwctl/group/set/main.go +++ b/internal/app/wwctl/group/set/main.go @@ -24,7 +24,19 @@ func CobraRunE(cmd *cobra.Command, args []string) error { os.Exit(1) } - if len(args) > 0 { + if SetGroupAll == true { + var tmp []node.GroupInfo + tmp, err = nodeDB.FindAllGroups() + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + + for _, g := range tmp { + groups = append(groups, g) + } + + } else if len(args) > 0 { var tmp []node.GroupInfo tmp, err = nodeDB.FindAllGroups() if err != nil { @@ -34,7 +46,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { for _, a := range args { for _, g := range tmp { - if g.Id == a { + if g.Id.String() == a { groups = append(groups, g) } } @@ -48,7 +60,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { for _, g := range groups { if SetVnfs != "" { wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting vnfs to: %s\n", g.Id, SetVnfs) - err := nodeDB.SetGroupVal(g.Id, "vnfs", SetVnfs) + err := nodeDB.SetGroupVal(g.Id.String(), "vnfs", SetVnfs) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -61,14 +73,14 @@ func CobraRunE(cmd *cobra.Command, args []string) error { os.Exit(1) } for _, n := range nodes { - _ = nodeDB.SetNodeVal(g.Id, n.Id, "vnfs", "") + _ = nodeDB.SetNodeVal(g.Id.String(), n.Id.String(), "vnfs", "") } } } if SetKernel != "" { wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting kernel to: %s\n", g.Id, SetVnfs) - err := nodeDB.SetGroupVal(g.Id, "kernel", SetKernel) + err := nodeDB.SetGroupVal(g.Id.String(), "kernel", SetKernel) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -81,14 +93,14 @@ func CobraRunE(cmd *cobra.Command, args []string) error { os.Exit(1) } for _, n := range nodes { - _ = nodeDB.SetNodeVal(g.Id, n.Id, "kernel", "") + _ = nodeDB.SetNodeVal(g.Id.String(), n.Id.String(), "kernel", "") } } } if SetDomainName != "" { wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting domain name to: %s\n", g.Id, SetDomainName) - err := nodeDB.SetGroupVal(g.Id, "domain", SetDomainName) + err := nodeDB.SetGroupVal(g.Id.String(), "domain", SetDomainName) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -101,14 +113,14 @@ func CobraRunE(cmd *cobra.Command, args []string) error { os.Exit(1) } for _, n := range nodes { - _ = nodeDB.SetNodeVal(g.Id, n.Id, "domain", "") + _ = nodeDB.SetNodeVal(g.Id.String(), n.Id.String(), "domain", "") } } } if SetIpxe != "" { wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting iPXE template to: %s\n", g.Id, SetIpxe) - err := nodeDB.SetGroupVal(g.Id, "ipxe", SetIpxe) + err := nodeDB.SetGroupVal(g.Id.String(), "ipxe", SetIpxe) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -121,14 +133,14 @@ func CobraRunE(cmd *cobra.Command, args []string) error { os.Exit(1) } for _, n := range nodes { - _ = nodeDB.SetNodeVal(g.Id, n.Id, "ipxe", "") + _ = nodeDB.SetNodeVal(g.Id.String(), n.Id.String(), "ipxe", "") } } } if SetRuntimeOverlay != "" { wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting runtime overlay to: %s\n", g.Id, SetRuntimeOverlay) - err := nodeDB.SetGroupVal(g.Id, "runtimeoverlay", SetRuntimeOverlay) + err := nodeDB.SetGroupVal(g.Id.String(), "runtimeoverlay", SetRuntimeOverlay) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -140,14 +152,14 @@ func CobraRunE(cmd *cobra.Command, args []string) error { os.Exit(1) } for _, n := range nodes { - _ = nodeDB.SetNodeVal(g.Id, n.Id, "runtimeoverlay", "") + _ = nodeDB.SetNodeVal(g.Id.String(), n.Id.String(), "runtimeoverlay", "") } } } if SetSystemOverlay != "" { wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting system overlay to: %s\n", g.Id, SetSystemOverlay) - err := nodeDB.SetGroupVal(g.Id, "systemoverlay", SetSystemOverlay) + err := nodeDB.SetGroupVal(g.Id.String(), "systemoverlay", SetSystemOverlay) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -159,13 +171,13 @@ func CobraRunE(cmd *cobra.Command, args []string) error { os.Exit(1) } for _, n := range nodes { - _ = nodeDB.SetNodeVal(g.Id, n.Id, "systemoverlay", "") + _ = nodeDB.SetNodeVal(g.Id.String(), n.Id.String(), "systemoverlay", "") } } } if SetIpmiIpaddr != "" { wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting IPMI IP address to: %s\n", g.Id, SetIpmiIpaddr) - err := nodeDB.SetGroupVal(g.Id, "ipmiipaddr", SetIpmiIpaddr) + err := nodeDB.SetGroupVal(g.Id.String(), "ipmiipaddr", SetIpmiIpaddr) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -177,13 +189,13 @@ func CobraRunE(cmd *cobra.Command, args []string) error { os.Exit(1) } for _, n := range nodes { - _ = nodeDB.SetNodeVal(g.Id, n.Id, "ipmiipaddr", "") + _ = nodeDB.SetNodeVal(g.Id.String(), n.Id.String(), "ipmiipaddr", "") } } } if SetIpmiUsername != "" { wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting IPMI IP username to: %s\n", g.Id, SetIpmiUsername) - err := nodeDB.SetGroupVal(g.Id, "ipmiusername", SetIpmiUsername) + err := nodeDB.SetGroupVal(g.Id.String(), "ipmiusername", SetIpmiUsername) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -195,13 +207,13 @@ func CobraRunE(cmd *cobra.Command, args []string) error { os.Exit(1) } for _, n := range nodes { - _ = nodeDB.SetNodeVal(g.Id, n.Id, "ipmiusername", "") + _ = nodeDB.SetNodeVal(g.Id.String(), n.Id.String(), "ipmiusername", "") } } } if SetIpmiPassword != "" { wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting IPMI IP password to: %s\n", g.Id, SetIpmiPassword) - err := nodeDB.SetGroupVal(g.Id, "ipmipassword", SetIpmiPassword) + err := nodeDB.SetGroupVal(g.Id.String(), "ipmipassword", SetIpmiPassword) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -213,7 +225,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { os.Exit(1) } for _, n := range nodes { - _ = nodeDB.SetNodeVal(g.Id, n.Id, "ipmipassword", "") + _ = nodeDB.SetNodeVal(g.Id.String(), n.Id.String(), "ipmipassword", "") } } } diff --git a/internal/app/wwctl/group/set/root.go b/internal/app/wwctl/group/set/root.go index 8338958b..d4378b52 100644 --- a/internal/app/wwctl/group/set/root.go +++ b/internal/app/wwctl/group/set/root.go @@ -20,7 +20,7 @@ var ( SetIpmiIpaddr string SetIpmiUsername string SetIpmiPassword string - + SetGroupAll bool ) func init() { @@ -35,6 +35,8 @@ func init() { baseCmd.PersistentFlags().StringVar(&SetIpmiPassword, "ipmipass", "", "Set the node's IPMI password") baseCmd.PersistentFlags().BoolVarP(&SetClearNodes, "clear", "c", false, "Clear node configurations when setting parent group") + baseCmd.PersistentFlags().BoolVarP(&SetGroupAll, "all", "a", false, "Set all nodes") + } // GetRootCommand returns the root cobra.Command for the application. diff --git a/internal/app/wwctl/kernel/build/main.go b/internal/app/wwctl/kernel/build/main.go index 89f01653..ae9e7844 100644 --- a/internal/app/wwctl/kernel/build/main.go +++ b/internal/app/wwctl/kernel/build/main.go @@ -27,7 +27,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } for _, node := range nodes { - set[node.KernelVersion] ++ + set[node.KernelVersion.String()] ++ } } else if BuildAll == true { @@ -39,7 +39,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } for _, node := range nodes { - set[node.KernelVersion] ++ + set[node.KernelVersion.String()] ++ } } else if len(args) == 1 { diff --git a/internal/app/wwctl/node/add/main.go b/internal/app/wwctl/node/add/main.go index e52bf95b..ad4d3a49 100644 --- a/internal/app/wwctl/node/add/main.go +++ b/internal/app/wwctl/node/add/main.go @@ -1,6 +1,7 @@ package add import ( + "fmt" "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" @@ -20,6 +21,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) } + fmt.Printf("Added node: %s\n", a) } nodeDB.Persist() diff --git a/internal/app/wwctl/node/delete/main.go b/internal/app/wwctl/node/delete/main.go index 23b566f4..f036e7c4 100644 --- a/internal/app/wwctl/node/delete/main.go +++ b/internal/app/wwctl/node/delete/main.go @@ -21,11 +21,11 @@ func CobraRunE(cmd *cobra.Command, args []string) error { nodeList, err := nodeDB.SearchByNameList(args) for _, n := range nodeList { - if SetGroup != "" && SetGroup != n.GroupName { + if SetGroup != "" && SetGroup != n.GroupName.String() { wwlog.Printf(wwlog.DEBUG, "skipping node of different group: %s/%s\n", n.GroupName, n.Id) continue } - err := nodeDB.DelNode(n.GroupName, n.Id) + err := nodeDB.DelNode(n.GroupName.String(), n.Id.String()) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) } else { diff --git a/internal/app/wwctl/node/list/main.go b/internal/app/wwctl/node/list/main.go index 95ebec14..3f14b520 100644 --- a/internal/app/wwctl/node/list/main.go +++ b/internal/app/wwctl/node/list/main.go @@ -7,6 +7,7 @@ import ( "github.com/spf13/cobra" "os" "reflect" + "strings" ) @@ -38,32 +39,49 @@ func CobraRunE(cmd *cobra.Command, args []string) error { typeOfS := v.Type() fmt.Printf("################################################################################\n") for i := 0; i< v.NumField(); i++ { - fmt.Printf("%-25s %s = %v\n", node.Fqdn, typeOfS.Field(i).Name, v.Field(i).Interface()) + //TODO: Fix for NetDevs and Interface should print Fprint() method + fmt.Printf("%-25s %s = %v\n", node.Fqdn.String(), typeOfS.Field(i).Name, v.Field(i).Interface()) } } } else if ShowNet == true { - fmt.Printf("%-22s %-10s %-20s %-16s %-16s %-16s %s\n", "NODE NAME", "DEVICE", "HWADDR", "IPADDR", "NETMASK", "GATEWAY", "TYPE") + fmt.Printf("%-22s %-6s %-18s %-15s %-15s\n", "NODE NAME", "DEVICE", "HWADDR", "IPADDR", "GATEWAY") + fmt.Println(strings.Repeat("=", 80)) for _, node := range nodes { - for name, dev := range node.NetDevs { - fmt.Printf("%-22s %-10s %-20s %-16s %-16s %-16s %s\n", node.Fqdn, name, dev.Hwaddr, dev.Ipaddr, dev.Netmask, dev.Gateway, dev.Type) + if len(node.NetDevs) > 0 { + for name, dev := range node.NetDevs { + fmt.Printf("%-22s %-6s %-18s %-15s %-15s\n", node.Fqdn.String(), name, dev.Hwaddr, dev.Ipaddr, dev.Gateway) + } + } else { + fmt.Printf("%-22s %-6s %-18s %-15s %-15s\n", node.Fqdn.String(), "--", "--", "--", "--") } } } else if ShowIpmi == true { fmt.Printf("%-22s %-16s %-20s %-20s\n", "NODE NAME", "IPMI IPADDR", "IPMI USERNAME", "IPMI PASSWORD") + fmt.Println(strings.Repeat("=", 80)) for _, node := range nodes { - fmt.Printf("%-22s %-16s %-20s %-20s\n", node.Fqdn, node.IpmiIpaddr, node.IpmiUserName, node.IpmiPassword) + fmt.Printf("%-22s %-16s %-20s %-20s\n", node.Fqdn.String(), node.IpmiIpaddr.Fprint(), node.IpmiUserName.Fprint(), node.IpmiPassword.Fprint()) + } + + } 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)) + + 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()) } } else { - fmt.Printf("%-22s %-16s %-30s %-30s %-16s\n", "NODE NAME", "GROUP NAME", "KERNEL VERSION", "VNFS IMAGE", "RUNTIME OVERLAY") + fmt.Printf("%-22s %-26s %-30s\n", "NODE NAME", "KERNEL VERSION", "VNFS IMAGE") + fmt.Println(strings.Repeat("=", 80)) for _, node := range nodes { - fmt.Printf("%-22s %-16s %-30s %-30s %-16s\n", node.Fqdn, node.GroupName, node.KernelVersion, node.Vnfs, node.RuntimeOverlay) + fmt.Printf("%-22s %-26s %-30s\n", node.Fqdn.String(), node.KernelVersion.Fprint(), node.Vnfs.Fprint()) } + } diff --git a/internal/app/wwctl/node/list/root.go b/internal/app/wwctl/node/list/root.go index 59c1c9cc..9bc4fe3c 100644 --- a/internal/app/wwctl/node/list/root.go +++ b/internal/app/wwctl/node/list/root.go @@ -12,12 +12,14 @@ var ( ShowNet bool ShowIpmi bool ShowAll bool + ShowLong bool ) func init() { baseCmd.PersistentFlags().BoolVarP(&ShowNet, "net", "n", false, "Show node network configurations") baseCmd.PersistentFlags().BoolVarP(&ShowIpmi, "ipmi", "i", false, "Show node IPMI configurations") baseCmd.PersistentFlags().BoolVarP(&ShowAll, "all", "a", false, "Show all node configurations") + baseCmd.PersistentFlags().BoolVarP(&ShowLong, "long", "l", false, "Show long or wide format") } // GetRootCommand returns the root cobra.Command for the application. diff --git a/internal/app/wwctl/node/poweroff/power.go b/internal/app/wwctl/node/poweroff/power.go index 3364fd88..9b17a2e6 100644 --- a/internal/app/wwctl/node/poweroff/power.go +++ b/internal/app/wwctl/node/poweroff/power.go @@ -34,13 +34,13 @@ func CobraRunE(cmd *cobra.Command, args []string) error { for _, node := range nodeList { - if node.IpmiIpaddr == "" { + if node.IpmiIpaddr.String() == "" { wwlog.Printf(wwlog.ERROR, "%s: No IPMI IP address\n", node.HostName) continue } ipmiCmd := power.IPMI{ - HostName: node.IpmiIpaddr, + HostName: node.IpmiIpaddr.String(), User: "ADMIN", Password: "ADMIN", AuthType: "MD5", diff --git a/internal/app/wwctl/node/poweron/power.go b/internal/app/wwctl/node/poweron/power.go index 900177c2..95703f3d 100644 --- a/internal/app/wwctl/node/poweron/power.go +++ b/internal/app/wwctl/node/poweron/power.go @@ -34,13 +34,13 @@ func CobraRunE(cmd *cobra.Command, args []string) error { for _, node := range nodeList { - if node.IpmiIpaddr == "" { + if node.IpmiIpaddr.String() == "" { wwlog.Printf(wwlog.ERROR, "%s: No IPMI IP address\n", node.HostName) continue } ipmiCmd := power.IPMI{ - HostName: node.IpmiIpaddr, + HostName: node.IpmiIpaddr.String(), User: "ADMIN", Password: "ADMIN", AuthType: "MD5", diff --git a/internal/app/wwctl/node/powerstatus/power.go b/internal/app/wwctl/node/powerstatus/power.go index 1f02fb57..960550f4 100644 --- a/internal/app/wwctl/node/powerstatus/power.go +++ b/internal/app/wwctl/node/powerstatus/power.go @@ -34,13 +34,13 @@ func CobraRunE(cmd *cobra.Command, args []string) error { for _, node := range nodeList { - if node.IpmiIpaddr == "" { + if node.IpmiIpaddr.String() == "" { wwlog.Printf(wwlog.ERROR, "%s: No IPMI IP address\n", node.HostName) continue } ipmiCmd := power.IPMI{ - HostName: node.IpmiIpaddr, + HostName: node.IpmiIpaddr.String(), User: "ADMIN", Password: "ADMIN", AuthType: "MD5", diff --git a/internal/app/wwctl/node/set/main.go b/internal/app/wwctl/node/set/main.go index e7d2db05..8c76889f 100644 --- a/internal/app/wwctl/node/set/main.go +++ b/internal/app/wwctl/node/set/main.go @@ -24,31 +24,37 @@ func CobraRunE(cmd *cobra.Command, args []string) error { os.Exit(1) } - if len(args) > 0 { - nodes, err = nodeDB.SearchByNameList(args) + if SetNodeAll == true { + nodes, err = nodeDB.FindAllNodes() if err != nil { wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) os.Exit(1) } + } else if len(args) > 0 { + nodes, err = nodeDB.SearchByNameList(args) + if err != nil { + wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + os.Exit(1) + } } else { cmd.Usage() os.Exit(1) } for _, n := range nodes { - wwlog.Printf(wwlog.VERBOSE, "Evaluating node: %s\n", n.Fqdn) + wwlog.Printf(wwlog.VERBOSE, "Evaluating node: %s\n", n.Fqdn.String()) if SetVnfs != "" { - wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting vnfs to: %s\n", n.Fqdn, SetVnfs) - err := nodeDB.SetNodeVal(n.Gid, n.Id, "vnfs", SetVnfs) + wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting vnfs to: %s\n", n.Fqdn.String(), SetVnfs) + err := nodeDB.SetNodeVal(n.Gid.String(), n.Id.String(), "vnfs", SetVnfs) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) } } if SetKernel != "" { - wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting kernel to: %s\n", n.Fqdn, SetVnfs) - err := nodeDB.SetNodeVal(n.Gid, n.Id, "kernel", SetKernel) + wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting kernel to: %s\n", n.Fqdn.String(), SetKernel) + err := nodeDB.SetNodeVal(n.Gid.String(), n.Id.String(), "kernel", SetKernel) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -56,7 +62,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } if SetDomainName != "" { wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting domain name to: %s\n", n.Fqdn, SetDomainName) - err := nodeDB.SetNodeVal(n.Gid, n.Id, "domain", SetDomainName) + err := nodeDB.SetNodeVal(n.Gid.String(), n.Id.String(), "domain", SetDomainName) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -64,7 +70,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } if SetIpxe != "" { wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting iPXE template to: %s\n", n.Fqdn, SetIpxe) - err := nodeDB.SetNodeVal(n.Gid, n.Id, "ipxe", SetIpxe) + err := nodeDB.SetNodeVal(n.Gid.String(), n.Id.String(), "ipxe", SetIpxe) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -72,7 +78,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } if SetRuntimeOverlay != "" { wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting runtime overlay to: %s\n", n.Fqdn, SetRuntimeOverlay) - err := nodeDB.SetNodeVal(n.Gid, n.Id, "runtimeoverlay", SetRuntimeOverlay) + err := nodeDB.SetNodeVal(n.Gid.String(), n.Id.String(), "runtimeoverlay", SetRuntimeOverlay) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -80,7 +86,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } if SetSystemOverlay != "" { wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting system overlay to: %s\n", n.Fqdn, SetSystemOverlay) - err := nodeDB.SetNodeVal(n.Gid, n.Id, "systemoverlay", SetSystemOverlay) + err := nodeDB.SetNodeVal(n.Gid.String(), n.Id.String(), "systemoverlay", SetSystemOverlay) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -88,7 +94,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } if SetHostname != "" { wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting hostname to: %s\n", n.Fqdn, SetHostname) - err := nodeDB.SetNodeVal(n.Gid, n.Id, "hostname", SetHostname) + err := nodeDB.SetNodeVal(n.Gid.String(), n.Id.String(), "hostname", SetHostname) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -96,7 +102,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } if SetIpmiIpaddr != "" { wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting IPMI IP address to: %s\n", n.Fqdn, SetIpmiIpaddr) - err := nodeDB.SetNodeVal(n.Gid, n.Id, "ipmiipaddr", SetIpmiIpaddr) + err := nodeDB.SetNodeVal(n.Gid.String(), n.Id.String(), "ipmiipaddr", SetIpmiIpaddr) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -104,7 +110,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } if SetIpmiUsername != "" { wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting IPMI IP username to: %s\n", n.Fqdn, SetIpmiUsername) - err := nodeDB.SetNodeVal(n.Gid, n.Id, "ipmiusername", SetIpmiUsername) + err := nodeDB.SetNodeVal(n.Gid.String(), n.Id.String(), "ipmiusername", SetIpmiUsername) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -112,7 +118,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } if SetIpmiPassword != "" { wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting IPMI IP password to: %s\n", n.Fqdn, SetIpmiPassword) - err := nodeDB.SetNodeVal(n.Gid, n.Id, "ipmipassword", SetIpmiPassword) + err := nodeDB.SetNodeVal(n.Gid.String(), n.Id.String(), "ipmipassword", SetIpmiPassword) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -127,7 +133,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { os.Exit(1) } wwlog.Printf(wwlog.VERBOSE, "Node: %s, Deleting network device: %s\n", n.Fqdn, SetNetDev) - err := nodeDB.DelNodeNet(n.Gid, n.Id, SetNetDev) + err := nodeDB.DelNodeNet(n.Gid.String(), n.Id.String(), SetNetDev) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -140,7 +146,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { os.Exit(1) } wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting Ipaddr to: %s\n", n.Fqdn, SetNetDev, SetIpaddr) - err := nodeDB.SetNodeNet(n.Gid, n.Id, SetNetDev, "ipaddr", SetIpaddr) + err := nodeDB.SetNodeNet(n.Gid.String(), n.Id.String(), SetNetDev, "ipaddr", SetIpaddr) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -152,7 +158,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { os.Exit(1) } wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting netmask to: %s\n", n.Fqdn, SetNetDev, SetNetmask) - err := nodeDB.SetNodeNet(n.Gid, n.Id, SetNetDev, "netmask", SetNetmask) + err := nodeDB.SetNodeNet(n.Gid.String(), n.Id.String(), SetNetDev, "netmask", SetNetmask) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -164,7 +170,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { os.Exit(1) } wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting gateway to: %s\n", n.Fqdn, SetNetDev, SetGateway) - err := nodeDB.SetNodeNet(n.Gid, n.Id, SetNetDev, "gateway", SetGateway) + err := nodeDB.SetNodeNet(n.Gid.String(), n.Id.String(), SetNetDev, "gateway", SetGateway) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -176,7 +182,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { os.Exit(1) } wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting HW address to: %s\n", n.Fqdn, SetNetDev, SetHwaddr) - err := nodeDB.SetNodeNet(n.Gid, n.Id, SetNetDev, "hwaddr", SetHwaddr) + err := nodeDB.SetNodeNet(n.Gid.String(), n.Id.String(), SetNetDev, "hwaddr", SetHwaddr) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -185,17 +191,21 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } if len(nodes) > 0 { - q := fmt.Sprintf("Are you sure you want to modify %d nodes(s)", len(nodes)) - - prompt := promptui.Prompt{ - Label: q, - IsConfirm: true, - } - - result, _ := prompt.Run() - - if result == "y" || result == "yes" { + if SetYes == true { nodeDB.Persist() + } else { + q := fmt.Sprintf("Are you sure you want to modify %d nodes(s)", len(nodes)) + + prompt := promptui.Prompt{ + Label: q, + IsConfirm: true, + } + + result, _ := prompt.Run() + + if result == "y" || result == "yes" { + nodeDB.Persist() + } } } else { diff --git a/internal/app/wwctl/node/set/root.go b/internal/app/wwctl/node/set/root.go index 211be16e..f65ec18d 100644 --- a/internal/app/wwctl/node/set/root.go +++ b/internal/app/wwctl/node/set/root.go @@ -25,7 +25,8 @@ var ( SetIpmiIpaddr string SetIpmiUsername string SetIpmiPassword string - + SetNodeAll bool + SetYes bool ) func init() { @@ -46,6 +47,9 @@ func init() { baseCmd.PersistentFlags().StringVarP(&SetGateway, "gateway", "G", "", "Set the node's network device gateway") baseCmd.PersistentFlags().StringVarP(&SetHwaddr, "hwaddr", "N", "", "Set the node's network device HW address") baseCmd.PersistentFlags().BoolVar(&SetNetDevDel, "delete", false, "Delete the node's network device") + baseCmd.PersistentFlags().BoolVarP(&SetNodeAll, "all", "a", false, "Set all nodes") + + baseCmd.PersistentFlags().BoolVarP(&SetYes, "yes", "y", false, "Set 'yes' to all questions asked") } diff --git a/internal/app/wwctl/overlay/build/main.go b/internal/app/wwctl/overlay/build/main.go index 3dbb0eda..b927576c 100644 --- a/internal/app/wwctl/overlay/build/main.go +++ b/internal/app/wwctl/overlay/build/main.go @@ -25,9 +25,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } for _, node := range nodes { - if SystemOverlay == true && node.SystemOverlay == args[0] { + if SystemOverlay == true && node.SystemOverlay.String() == args[0] { updateNodes = append(updateNodes, node) - } else if node.RuntimeOverlay == args[0] { + } else if node.RuntimeOverlay.String() == args[0] { updateNodes = append(updateNodes, node) } } diff --git a/internal/app/wwctl/overlay/chmod/main.go b/internal/app/wwctl/overlay/chmod/main.go index 4ce3c364..bd8352ba 100644 --- a/internal/app/wwctl/overlay/chmod/main.go +++ b/internal/app/wwctl/overlay/chmod/main.go @@ -64,9 +64,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error { var updateNodes []node.NodeInfo for _, node := range nodes { - if SystemOverlay == true && node.SystemOverlay == overlayName { + if SystemOverlay == true && node.SystemOverlay.String() == overlayName { updateNodes = append(updateNodes, node) - } else if node.RuntimeOverlay == overlayName { + } else if node.RuntimeOverlay.String() == overlayName { updateNodes = append(updateNodes, node) } } diff --git a/internal/app/wwctl/overlay/create/main.go b/internal/app/wwctl/overlay/create/main.go index 95d31c90..237341cb 100644 --- a/internal/app/wwctl/overlay/create/main.go +++ b/internal/app/wwctl/overlay/create/main.go @@ -48,9 +48,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error { var updateNodes []node.NodeInfo for _, node := range nodes { - if SystemOverlay == true && node.SystemOverlay == args[0] { + if SystemOverlay == true && node.SystemOverlay.String() == args[0] { updateNodes = append(updateNodes, node) - } else if node.RuntimeOverlay == args[0] { + } else if node.RuntimeOverlay.String() == args[0] { updateNodes = append(updateNodes, node) } } diff --git a/internal/app/wwctl/overlay/delete/main.go b/internal/app/wwctl/overlay/delete/main.go index 05fbbc25..a59e8c61 100644 --- a/internal/app/wwctl/overlay/delete/main.go +++ b/internal/app/wwctl/overlay/delete/main.go @@ -110,9 +110,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error { var updateNodes []node.NodeInfo for _, node := range nodes { - if SystemOverlay == true && node.SystemOverlay == args[0] { + if SystemOverlay == true && node.SystemOverlay.String() == args[0] { updateNodes = append(updateNodes, node) - } else if node.RuntimeOverlay == args[0] { + } else if node.RuntimeOverlay.String() == args[0] { updateNodes = append(updateNodes, node) } } diff --git a/internal/app/wwctl/overlay/edit/main.go b/internal/app/wwctl/overlay/edit/main.go index 1b68e538..cebe1021 100644 --- a/internal/app/wwctl/overlay/edit/main.go +++ b/internal/app/wwctl/overlay/edit/main.go @@ -108,9 +108,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error { var updateNodes []node.NodeInfo for _, node := range nodes { - if SystemOverlay == true && node.SystemOverlay == args[0] { + if SystemOverlay == true && node.SystemOverlay.String() == args[0] { updateNodes = append(updateNodes, node) - } else if node.RuntimeOverlay == args[0] { + } else if node.RuntimeOverlay.String() == args[0] { updateNodes = append(updateNodes, node) } } diff --git a/internal/app/wwctl/overlay/imprt/main.go b/internal/app/wwctl/overlay/imprt/main.go index 0ce1c3b1..8374736f 100644 --- a/internal/app/wwctl/overlay/imprt/main.go +++ b/internal/app/wwctl/overlay/imprt/main.go @@ -60,9 +60,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error { var updateNodes []node.NodeInfo for _, node := range nodes { - if SystemOverlay == true && node.SystemOverlay == overlayName { + if SystemOverlay == true && node.SystemOverlay.String() == overlayName { updateNodes = append(updateNodes, node) - } else if node.RuntimeOverlay == overlayName { + } else if node.RuntimeOverlay.String() == overlayName { updateNodes = append(updateNodes, node) } } diff --git a/internal/app/wwctl/overlay/list/main.go b/internal/app/wwctl/overlay/list/main.go index 1b51fff9..0266ac14 100644 --- a/internal/app/wwctl/overlay/list/main.go +++ b/internal/app/wwctl/overlay/list/main.go @@ -53,12 +53,12 @@ func CobraRunE(cmd *cobra.Command, args []string) error { for _, node := range nodeList { if SystemOverlay == true { - if node.SystemOverlay != "" { - set[node.SystemOverlay] ++ + if node.SystemOverlay.String() != "" { + set[node.SystemOverlay.String()] ++ } } else { - if node.RuntimeOverlay != "" { - set[node.RuntimeOverlay] ++ + if node.RuntimeOverlay.String() != "" { + set[node.RuntimeOverlay.String()] ++ } } } diff --git a/internal/app/wwctl/overlay/mkdir/main.go b/internal/app/wwctl/overlay/mkdir/main.go index 62dfe7c8..ef38ae0f 100644 --- a/internal/app/wwctl/overlay/mkdir/main.go +++ b/internal/app/wwctl/overlay/mkdir/main.go @@ -57,9 +57,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error { var updateNodes []node.NodeInfo for _, node := range nodes { - if SystemOverlay == true && node.SystemOverlay == args[0] { + if SystemOverlay == true && node.SystemOverlay.String() == args[0] { updateNodes = append(updateNodes, node) - } else if node.RuntimeOverlay == args[0] { + } else if node.RuntimeOverlay.String() == args[0] { updateNodes = append(updateNodes, node) } } diff --git a/internal/app/wwctl/vnfs/build/main.go b/internal/app/wwctl/vnfs/build/main.go index 92590ae8..8fbd1539 100644 --- a/internal/app/wwctl/vnfs/build/main.go +++ b/internal/app/wwctl/vnfs/build/main.go @@ -28,7 +28,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } for _, node := range nodes { - set[node.Vnfs] ++ + set[node.Vnfs.String()] ++ } } else if BuildAll == true { @@ -40,7 +40,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } for _, node := range nodes { - set[node.Vnfs] ++ + set[node.Vnfs.String()] ++ } } else if len(args) == 1 { diff --git a/internal/pkg/node/modify.go b/internal/pkg/node/modify.go new file mode 100644 index 00000000..b3e01de3 --- /dev/null +++ b/internal/pkg/node/modify.go @@ -0,0 +1,249 @@ +package node + +import ( + "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" + "os" + "strings" +) + +func (self *nodeYaml) AddGroup(groupID string) error { + var group nodeGroup + + if _, ok := self.NodeGroups[groupID]; ok { + return errors.New("Group name already exists: " + groupID) + } + + self.NodeGroups[groupID] = &group + self.NodeGroups[groupID].DomainSuffix = groupID + + return nil +} + +func (self *nodeYaml) AddNode(groupID string, nodeID string) error { + var node nodeEntry + + wwlog.Printf(wwlog.VERBOSE, "Adding new node: %s/%s\n", groupID, nodeID) + + if _, ok := self.NodeGroups[groupID]; ok { + if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { + return errors.New("Nodename already exists in group: " + nodeID) + } + } else { + return errors.New("Group does not exist: "+groupID) + } + + self.NodeGroups[groupID].Nodes[nodeID] = &node + self.NodeGroups[groupID].Nodes[nodeID].Hostname = nodeID + + return nil +} + +func (self *nodeYaml) DelNode(groupID string, nodeID string) error { + + if _, ok := self.NodeGroups[groupID]; ok { + if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { + delete(self.NodeGroups[groupID].Nodes, nodeID) + wwlog.Printf(wwlog.VERBOSE, "Deleting node: %s/%s\n", groupID, nodeID) + } else { + return errors.New("Node '"+nodeID+"' was not found in group '"+groupID+"'") + } + } else { + return errors.New("Group '"+groupID+"' was not found") + } + + return nil +} + +func (self *nodeYaml) DelNodeNet(groupID string, nodeID string, netDev string) error { + + if _, ok := self.NodeGroups[groupID]; ok { + if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { + if _, ok := self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev]; ok { + wwlog.Printf(wwlog.VERBOSE, "Deleting node network device: %s/%s:%s\n", groupID, nodeID, netDev) + delete(self.NodeGroups[groupID].Nodes[nodeID].NetDevs, netDev) + } else { + return errors.New("Network device '"+netDev+"' was not found in node '"+groupID+"/"+nodeID+"'") + } + } else { + return errors.New("Node '"+nodeID+"' was not found in group '"+groupID+"'") + } + } else { + return errors.New("Group '"+groupID+"' was not found") + } + + return nil +} + + +func (self *nodeYaml) DelGroup(groupname string) error { + if _, ok := self.NodeGroups[groupname]; ok { + delete(self.NodeGroups, groupname) + } else { + return errors.New("Node group undefined: " + groupname) + } + + return nil +} + +func (self *nodeYaml) SetGroupVal(groupID string, entry string, value string) error { + if strings.ToUpper(value) == "UNDEF" || strings.ToUpper(value) == "NIL" || strings.ToUpper(value) == "DEL" { + value = "" + } + + if _, ok := self.NodeGroups[groupID]; ok { + 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) + } + + return nil +} + +func (self *nodeYaml) SetNodeVal(groupID string, nodeID string, entry string, value string) error { + if strings.ToUpper(value) == "UNDEF" || strings.ToUpper(value) == "NIL" || strings.ToUpper(value) == "DEL" { + value = "" + } + if _, ok := self.NodeGroups[groupID]; ok { + if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { + wwlog.Printf(wwlog.VERBOSE, "Setting node %s/%s to: %s = '%s'\n", groupID, nodeID, entry, value ) + + switch strings.ToUpper(entry) { + case "VNFS": + util.ValidateOrDie("VNFS", entry, "^[a-zA-Z0-9-._]*$") + self.NodeGroups[groupID].Nodes[nodeID].Vnfs = value + case "KERNEL": + util.ValidateOrDie("Kernel Version", entry, "^[a-zA-Z0-9-._]*$") + self.NodeGroups[groupID].Nodes[nodeID].KernelVersion = value + case "DOMAINSUFFIX": + util.ValidateOrDie("Domain", entry, "^[a-zA-Z0-9-._]*$") + self.NodeGroups[groupID].Nodes[nodeID].DomainSuffix = value + 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 + case "IPMIIPADDR": + util.ValidateOrDie("IPMI IP Address", entry, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") + self.NodeGroups[groupID].Nodes[nodeID].IpmiIpaddr = value + case "IPMIUSERNAME": + util.ValidateOrDie("IPMI Username", entry, "^[a-zA-Z0-9-._]*$") + self.NodeGroups[groupID].Nodes[nodeID].IpmiUserName = value + case "IPMIPASSWORD": + util.ValidateOrDie("IPMI Password", entry, "^[a-zA-Z0-9-._]*$") + self.NodeGroups[groupID].Nodes[nodeID].IpmiPassword = value + + } + } else { + return errors.New("Node does not exist: " +groupID+ "/" +nodeID) + } + } else { + return errors.New("Group does not exist: " +groupID) + } + + return nil +} + +func (self *nodeYaml) SetNodeNet(groupID string, nodeID string, netDev string, entry string, value string) error { + if strings.ToUpper(value) == "UNDEF" || strings.ToUpper(value) == "NIL" || strings.ToUpper(value) == "DEL" { + value = "" + } + + if _, ok := self.NodeGroups[groupID]; ok { + if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { + 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 + self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev] = &nd + } + } else { + return errors.New("Node does not exist: "+groupID+"/"+nodeID) + } + } else { + return errors.New("Group does not exist: "+groupID) + } + + switch strings.ToUpper(entry) { + case "IPADDR": + util.ValidateOrDie("IP address", value, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") + self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Ipaddr = value + case "NETMASK": + util.ValidateOrDie("Netmask", value, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") + self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Netmask = value + case "GATEWAY": + util.ValidateOrDie("Gateway", value, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") + self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Gateway = value + case "TYPE": + util.ValidateOrDie("Network device type", value, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") + self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Type = value + case "HWADDR": + util.ValidateOrDie("HW address", value, "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$") + self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Hwaddr = value + + } + + return nil +} + +func (self *nodeYaml) Persist() error { + + out, err := yaml.Marshal(self) + if err != nil { + return err + } + + file, err := os.OpenFile(ConfigFile, 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 +} + diff --git a/internal/pkg/node/node.go b/internal/pkg/node/node.go index 4f559210..79801880 100644 --- a/internal/pkg/node/node.go +++ b/internal/pkg/node/node.go @@ -7,9 +7,7 @@ import ( "github.com/hpcng/warewulf/internal/pkg/wwlog" "gopkg.in/yaml.v2" "io/ioutil" - "os" "regexp" - "strings" ) const ConfigFile = "/etc/warewulf/nodes.conf" @@ -21,7 +19,8 @@ func init() { } type nodeYaml struct { - NodeGroups map[string]*nodeGroup //`yaml:"nodegroups"` + NodeGroups map[string]*nodeGroup //`yaml:"nodegroups"` + Hwaddrs map[string]NodeInfo } type nodeGroup struct { @@ -58,41 +57,96 @@ type netDevs struct { Hwaddr string Ipaddr string Netmask string - Gateway string`yaml:"gateway,omitempty"` + Gateway string `yaml:"gateway,omitempty"` +} + +type EntryInfo struct { + Value string + override string + def string } type NodeInfo struct { - Id string - Gid string - Uid string - GroupName string - HostName string - DomainName string - Fqdn string - Vnfs string - Ipxe string - SystemOverlay string - RuntimeOverlay string - KernelVersion string - KernelArgs string - IpmiIpaddr string - IpmiUserName string - IpmiPassword string + 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 } type GroupInfo struct { - Id string - GroupName string - DomainName string - Vnfs string - Ipxe string - SystemOverlay string - RuntimeOverlay string - KernelVersion string - KernelArgs string - IpmiUserName string - IpmiPassword string + Id EntryInfo + GroupName EntryInfo + DomainName EntryInfo + Vnfs EntryInfo + Ipxe EntryInfo + SystemOverlay EntryInfo + RuntimeOverlay EntryInfo + KernelVersion EntryInfo + KernelArgs EntryInfo + IpmiUserName EntryInfo + IpmiPassword EntryInfo +} + +func (i *EntryInfo) Default (value string) { + if value == "" { + return + } + i.def = value +} + +func (i *EntryInfo) Set (value string) { + if value == "" { + return + } + i.Value = value + i.override = "" +} + +func (i *EntryInfo) Override (value string) { + if value == "" { + return + } + i.override = value +} + +func (i *EntryInfo) String () string { + if i.override != "" { + return i.override + } else if i.Value != "" { + return i.Value + } + return i.def +} + +func (i *EntryInfo) Defined () bool { + if i.String() == "" { + return false + } + return true +} + +func (i *EntryInfo) Fprint () string { + if i.override != "" { + return "["+ i.override +"]" + } else if i.Value != "" { + return i.Value + } else if i.def != "" { + return "("+ i.def +")" + } + return "--" } func New() (nodeYaml, error) { @@ -113,243 +167,6 @@ func New() (nodeYaml, error) { return ret, nil } -func (self *nodeYaml) AddGroup(groupID string) error { - var group nodeGroup - - if _, ok := self.NodeGroups[groupID]; ok { - return errors.New("Group name already exists: " + groupID) - } - - self.NodeGroups[groupID] = &group - self.NodeGroups[groupID].DomainSuffix = groupID - - return nil -} - -func (self *nodeYaml) AddNode(groupID string, nodeID string) error { - var node nodeEntry - - wwlog.Printf(wwlog.VERBOSE, "Adding new node: %s/%s\n", groupID, nodeID) - - if _, ok := self.NodeGroups[groupID]; ok { - if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { - return errors.New("Nodename already exists in group: " + nodeID) - } - } else { - return errors.New("Group does not exist: "+groupID) - } - - self.NodeGroups[groupID].Nodes[nodeID] = &node - self.NodeGroups[groupID].Nodes[nodeID].Hostname = nodeID - - return nil -} - -func (self *nodeYaml) DelNode(groupID string, nodeID string) error { - - if _, ok := self.NodeGroups[groupID]; ok { - if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { - delete(self.NodeGroups[groupID].Nodes, nodeID) - wwlog.Printf(wwlog.VERBOSE, "Deleting node: %s/%s\n", groupID, nodeID) - } else { - return errors.New("Node '"+nodeID+"' was not found in group '"+groupID+"'") - } - } else { - return errors.New("Group '"+groupID+"' was not found") - } - - return nil -} - -func (self *nodeYaml) DelNodeNet(groupID string, nodeID string, netDev string) error { - - if _, ok := self.NodeGroups[groupID]; ok { - if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { - if _, ok := self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev]; ok { - wwlog.Printf(wwlog.VERBOSE, "Deleting node network device: %s/%s:%s\n", groupID, nodeID, netDev) - delete(self.NodeGroups[groupID].Nodes[nodeID].NetDevs, netDev) - } else { - return errors.New("Network device '"+netDev+"' was not found in node '"+groupID+"/"+nodeID+"'") - } - } else { - return errors.New("Node '"+nodeID+"' was not found in group '"+groupID+"'") - } - } else { - return errors.New("Group '"+groupID+"' was not found") - } - - return nil -} - - -func (self *nodeYaml) DelGroup(groupname string) error { - if _, ok := self.NodeGroups[groupname]; ok { - delete(self.NodeGroups, groupname) - } else { - return errors.New("Node group undefined: " + groupname) - } - - return nil -} - -func (self *nodeYaml) SetGroupVal(groupID string, entry string, value string) error { - if strings.ToUpper(value) == "UNDEF" || strings.ToUpper(value) == "NIL" || strings.ToUpper(value) == "DEL" { - value = "" - } - - if _, ok := self.NodeGroups[groupID]; ok { - 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) - } - - return nil -} - -func (self *nodeYaml) SetNodeVal(groupID string, nodeID string, entry string, value string) error { - if strings.ToUpper(value) == "UNDEF" || strings.ToUpper(value) == "NIL" || strings.ToUpper(value) == "DEL" { - value = "" - } - if _, ok := self.NodeGroups[groupID]; ok { - if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { - wwlog.Printf(wwlog.VERBOSE, "Setting node %s/%s to: %s = '%s'\n", groupID, nodeID, entry, value ) - - switch strings.ToUpper(entry) { - case "VNFS": - util.ValidateOrDie("VNFS", entry, "^[a-zA-Z0-9-._]*$") - self.NodeGroups[groupID].Nodes[nodeID].Vnfs = value - case "KERNEL": - util.ValidateOrDie("Kernel Version", entry, "^[a-zA-Z0-9-._]*$") - self.NodeGroups[groupID].Nodes[nodeID].KernelVersion = value - case "DOMAINSUFFIX": - util.ValidateOrDie("Domain", entry, "^[a-zA-Z0-9-._]*$") - self.NodeGroups[groupID].Nodes[nodeID].DomainSuffix = value - 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 - case "IPMIIPADDR": - util.ValidateOrDie("IPMI IP Address", entry, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") - self.NodeGroups[groupID].Nodes[nodeID].IpmiIpaddr = value - case "IPMIUSERNAME": - util.ValidateOrDie("IPMI Username", entry, "^[a-zA-Z0-9-._]*$") - self.NodeGroups[groupID].Nodes[nodeID].IpmiUserName = value - case "IPMIPASSWORD": - util.ValidateOrDie("IPMI Password", entry, "^[a-zA-Z0-9-._]*$") - self.NodeGroups[groupID].Nodes[nodeID].IpmiPassword = value - - } - } else { - return errors.New("Node does not exist: " +groupID+ "/" +nodeID) - } - } else { - return errors.New("Group does not exist: " +groupID) - } - - return nil -} - -func (self *nodeYaml) SetNodeNet(groupID string, nodeID string, netDev string, entry string, value string) error { - if strings.ToUpper(value) == "UNDEF" || strings.ToUpper(value) == "NIL" || strings.ToUpper(value) == "DEL" { - value = "" - } - - if _, ok := self.NodeGroups[groupID]; ok { - if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { - 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 - self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev] = &nd - } - } else { - return errors.New("Node does not exist: "+groupID+"/"+nodeID) - } - } else { - return errors.New("Group does not exist: "+groupID) - } - - switch strings.ToUpper(entry) { - case "IPADDR": - util.ValidateOrDie("IP address", value, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") - self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Ipaddr = value - case "NETMASK": - util.ValidateOrDie("Netmask", value, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") - self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Netmask = value - case "GATEWAY": - util.ValidateOrDie("Gateway", value, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") - self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Gateway = value - case "TYPE": - util.ValidateOrDie("Network device type", value, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") - self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Type = value - case "HWADDR": - util.ValidateOrDie("HW address", value, "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$") - self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Hwaddr = value - - } - - return nil -} - -func (self *nodeYaml) Persist() error { - - out, err := yaml.Marshal(self) - if err != nil { - return err - } - - file, err := os.OpenFile(ConfigFile, 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 (self *nodeYaml) FindAllGroups() ([]GroupInfo, error) { var ret []GroupInfo @@ -357,17 +174,17 @@ func (self *nodeYaml) FindAllGroups() ([]GroupInfo, error) { for groupname, group := range self.NodeGroups { var g GroupInfo - g.Id = groupname - g.GroupName = groupname - g.RuntimeOverlay = group.RuntimeOverlay - g.SystemOverlay = group.SystemOverlay - g.Ipxe = group.Ipxe - g.KernelVersion = group.KernelVersion - g.KernelArgs = group.KernelArgs - g.Vnfs = group.Vnfs - g.IpmiUserName = group.IpmiUserName - g.IpmiPassword = group.IpmiPassword - g.DomainName = group.DomainSuffix + 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) // TODO: Validate or die on all inputs @@ -384,79 +201,55 @@ func (self *nodeYaml) FindAllNodes() ([]NodeInfo, error) { for nodename, node := range group.Nodes { var n NodeInfo - n.Id = nodename - n.Gid = groupname -// n.Uid = groupname + ":" + nodename - n.GroupName = groupname - n.HostName = node.Hostname - n.IpmiIpaddr = node.IpmiIpaddr + n.Id.Set(nodename) + n.Gid.Set(groupname) + n.GroupName.Set(groupname) + n.HostName.Set(node.Hostname) + n.IpmiIpaddr.Set(node.IpmiIpaddr) - n.Vnfs = group.Vnfs - n.SystemOverlay = group.SystemOverlay - n.RuntimeOverlay = group.RuntimeOverlay - n.KernelVersion = group.KernelVersion - n.KernelArgs = group.KernelArgs - n.DomainName = group.DomainSuffix - n.Ipxe = group.Ipxe - n.IpmiUserName = group.IpmiUserName - n.IpmiPassword = group.IpmiPassword + 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) + + 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) + } else { + n.Fqdn.Set(node.Hostname) + } + } n.NetDevs = node.NetDevs - if node.IpmiUserName != "" { - n.IpmiUserName = node.IpmiUserName - } - if node.IpmiPassword != "" { - n.IpmiPassword = node.IpmiPassword - } - if node.KernelVersion != "" { - n.KernelVersion = node.KernelVersion - } - if node.Vnfs != "" { - n.Vnfs = node.Vnfs - } - if node.SystemOverlay != "" { - n.SystemOverlay = node.SystemOverlay - } - if node.RuntimeOverlay != "" { - n.RuntimeOverlay = node.RuntimeOverlay - } - if node.DomainSuffix != "" { - n.DomainName = node.DomainSuffix - } - if node.Ipxe != "" { - n.Ipxe = node.Ipxe - } - if node.KernelArgs != "" { - n.KernelArgs = node.KernelArgs - } - - if n.RuntimeOverlay == "" { - n.RuntimeOverlay = "default" - } - if n.SystemOverlay == "" { - n.SystemOverlay = "default" - } - if n.Ipxe == "" { - n.Ipxe = "default" - } - if n.HostName == "" { - n.HostName = nodename - } - - if n.DomainName != "" { - n.Fqdn = node.Hostname + "." + n.DomainName - } else { - n.Fqdn = node.Hostname - } - - util.ValidateOrDie(n.Fqdn +":group name", n.GroupName, "^[a-zA-Z0-9-._]*$") - util.ValidateOrDie(n.Fqdn +":vnfs", n.Vnfs, "^[a-zA-Z0-9-._:/]*$") - util.ValidateOrDie(n.Fqdn +":system overlay", n.SystemOverlay, "^[a-zA-Z0-9-._]*$") - util.ValidateOrDie(n.Fqdn +":runtime overlay", n.RuntimeOverlay, "^[a-zA-Z0-9-._]*$") - util.ValidateOrDie(n.Fqdn +":domain suffix", n.DomainName, "^[a-zA-Z0-9-._]*$") - util.ValidateOrDie(n.Fqdn +":hostname", n.HostName, "^[a-zA-Z0-9-_]*$") - util.ValidateOrDie(n.Fqdn +":kernel version", n.KernelVersion, "^[a-zA-Z0-9-._]*$") + 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-._]*$") ret = append(ret, n) } @@ -465,10 +258,10 @@ func (self *nodeYaml) FindAllNodes() ([]NodeInfo, error) { return ret, nil } -func (nodes *nodeYaml) FindByHwaddr(hwa string) (NodeInfo, error) { +func (self *nodeYaml) FindByHwaddr(hwa string) (NodeInfo, error) { var ret NodeInfo - n, _ := nodes.FindAllNodes() + n, _ := self.FindAllNodes() for _, node := range n { for _, dev := range node.NetDevs { @@ -481,10 +274,10 @@ func (nodes *nodeYaml) FindByHwaddr(hwa string) (NodeInfo, error) { return ret, errors.New("No nodes found with HW Addr: " + hwa) } -func (nodes *nodeYaml) FindByIpaddr(ipaddr string) (NodeInfo, error) { +func (self *nodeYaml) FindByIpaddr(ipaddr string) (NodeInfo, error) { var ret NodeInfo - n, _ := nodes.FindAllNodes() + n, _ := self.FindAllNodes() for _, node := range n { for _, dev := range node.NetDevs { @@ -503,7 +296,7 @@ func (nodes *nodeYaml) SearchByName(search string) ([]NodeInfo, error) { n, _ := nodes.FindAllNodes() for _, node := range n { - b, _ := regexp.MatchString(search, node.Fqdn) + b, _ := regexp.MatchString(search, node.Fqdn.String()) if b == true { ret = append(ret, node) } @@ -519,7 +312,7 @@ func (nodes *nodeYaml) SearchByNameList(searchList []string) ([]NodeInfo, error) for _, search := range searchList { for _, node := range n { - b, _ := regexp.MatchString(search, node.Fqdn) + b, _ := regexp.MatchString(search, node.Fqdn.String()) if b == true { ret = append(ret, node) } diff --git a/internal/pkg/overlay/runtime.go b/internal/pkg/overlay/runtime.go index e95cdbdd..d72e9e88 100644 --- a/internal/pkg/overlay/runtime.go +++ b/internal/pkg/overlay/runtime.go @@ -60,10 +60,10 @@ func RuntimeBuild(nodeList []node.NodeInfo, force bool) error { wwlog.SetIndent(4) for _, node := range nodeList { - if node.RuntimeOverlay != "" { - OverlayDir := config.RuntimeOverlaySource(node.RuntimeOverlay) - OverlayFile := config.RuntimeOverlayImage(node.Fqdn) - vnfs := vnfs.New(node.Vnfs) + 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()) diff --git a/internal/pkg/overlay/system.go b/internal/pkg/overlay/system.go index 89453e62..9b42dbcf 100644 --- a/internal/pkg/overlay/system.go +++ b/internal/pkg/overlay/system.go @@ -60,10 +60,10 @@ func SystemBuild(nodeList []node.NodeInfo, force bool) error { wwlog.SetIndent(4) for _, node := range nodeList { - if node.SystemOverlay != "" { - OverlayDir := config.SystemOverlaySource(node.SystemOverlay) - OverlayFile := config.SystemOverlayImage(node.Fqdn) - vnfs := vnfs.New(node.Vnfs) + 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()) From a4d2e3a0c836e350fa32c6aea4851b3cbcacea58 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Wed, 25 Nov 2020 23:58:38 -0800 Subject: [PATCH 02/32] 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 From 6d3ec350b664f039ad287f7b24353e5ac811a52f Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Thu, 26 Nov 2020 16:38:34 -0800 Subject: [PATCH 03/32] Updates to nodeStore --- internal/pkg/node/constructors.go | 219 +++++++++++++++++ internal/pkg/node/datastructure.go | 123 ++++++++++ internal/pkg/node/methods.go | 55 +++++ internal/pkg/node/modifiers.go | 209 ++++++++++++++++ internal/pkg/node/modify.go | 222 ----------------- internal/pkg/node/node.go | 377 ----------------------------- 6 files changed, 606 insertions(+), 599 deletions(-) create mode 100644 internal/pkg/node/constructors.go create mode 100644 internal/pkg/node/datastructure.go create mode 100644 internal/pkg/node/methods.go create mode 100644 internal/pkg/node/modifiers.go delete mode 100644 internal/pkg/node/modify.go delete mode 100644 internal/pkg/node/node.go diff --git a/internal/pkg/node/constructors.go b/internal/pkg/node/constructors.go new file mode 100644 index 00000000..ad76b714 --- /dev/null +++ b/internal/pkg/node/constructors.go @@ -0,0 +1,219 @@ +package node + +import ( + "fmt" + "github.com/hpcng/warewulf/internal/pkg/errors" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "gopkg.in/yaml.v2" + "io/ioutil" + "regexp" +) + +func New() (nodeYaml, error) { + var ret nodeYaml + + wwlog.Printf(wwlog.DEBUG, "Opening node configuration file: %s\n", ConfigFile) + data, err := ioutil.ReadFile(ConfigFile) + if err != nil { + fmt.Printf("error reading node configuration file\n") + return ret, err + } + + err = yaml.Unmarshal(data, &ret) + if err != nil { + return ret, err + } + + return ret, nil +} + +func (self *nodeYaml) FindAllNodes() ([]NodeInfo, error) { + var ret []NodeInfo + + for groupname, group := range self.NodeGroups { + for nodename, node := range group.Nodes { + var n NodeInfo + var allProfiles []string + + if node.Disabled == true || group.Disabled == true { + wwlog.Printf(wwlog.VERBOSE, "Skipping disabled node: %s/%s\n", groupname, nodename) + continue + } + + n.Id = nodename + n.Gid = groupname + n.GroupName = groupname + n.HostName = node.Hostname + n.IpmiIpaddr.Set(node.IpmiIpaddr) + + n.Profiles = node.Profiles + + allProfiles = append(allProfiles, group.Profiles...) + allProfiles = append(allProfiles, node.Profiles...) + + for _, p := range allProfiles { + if _, ok := self.NodeProfiles[p]; !ok { + wwlog.Printf(wwlog.WARN, "Profile not found for node '%s': %s\n", nodename, p) + continue + } + + n.Vnfs.profile = self.NodeProfiles[p].Vnfs + n.KernelVersion.profile = self.NodeProfiles[p].KernelVersion + n.KernelArgs.profile = self.NodeProfiles[p].KernelArgs + n.Ipxe.profile = self.NodeProfiles[p].Ipxe + n.IpmiUserName.profile = self.NodeProfiles[p].IpmiUserName + n.IpmiPassword.profile = self.NodeProfiles[p].IpmiPassword + n.DomainName.profile = self.NodeProfiles[p].DomainName + n.SystemOverlay.profile = self.NodeProfiles[p].SystemOverlay + n.RuntimeOverlay.profile = self.NodeProfiles[p].RuntimeOverlay + } + + n.DomainName.value = node.DomainName + n.DomainName.group = group.DomainName + n.Vnfs.value = node.Vnfs + n.KernelVersion.value = node.KernelVersion + n.KernelArgs.value = node.KernelArgs + n.Ipxe.value = node.Ipxe + n.IpmiUserName.value = node.IpmiUserName + n.IpmiPassword.value = node.IpmiPassword + + n.RuntimeOverlay.def = "default" + n.SystemOverlay.def = "default" + n.Ipxe.def = "default" + n.KernelArgs.def = "crashkernel=no quiet" + + // config := config.New() + // n.VnfsRoot = config.VnfsChroot(vnfs.CleanName(n.Vnfs)) + + if n.DomainName.Defined() == true { + n.Fqdn = n.HostName + "." + n.DomainName.Get() + } else { + n.Fqdn = node.Hostname + } + + n.NetDevs = node.NetDevs + + ret = append(ret, n) + } + } + + return ret, nil +} + +func (self *nodeYaml) FindAllGroups() ([]GroupInfo, error) { + var ret []GroupInfo + + for groupname, group := range self.NodeGroups { + var g GroupInfo + + g.Id = groupname + g.DomainName = group.DomainName + g.Disabled = group.Disabled + g.Comment = group.Comment + + g.Profiles = group.Profiles + + // TODO: Validate or die on all inputs + + ret = append(ret, g) + } + return ret, nil +} + +func (self *nodeYaml) FindAllProfiles() ([]ProfileInfo, error) { + var ret []ProfileInfo + + for name, profile := range self.NodeProfiles { + var p ProfileInfo + + p.Id = name + p.Comment = profile.Comment + p.Vnfs = profile.Vnfs + p.Ipxe = profile.Ipxe + p.KernelVersion = profile.KernelVersion + p.KernelArgs = profile.KernelArgs + p.IpmiUserName = profile.IpmiUserName + p.IpmiPassword = profile.IpmiPassword + p.DomainName = profile.DomainName + p.RuntimeOverlay = profile.RuntimeOverlay + p.SystemOverlay = profile.SystemOverlay + + // TODO: Validate or die on all inputs + + ret = append(ret, p) + } + return ret, nil +} + + + +func (self *nodeYaml) FindByHwaddr(hwa string) (NodeInfo, error) { + var ret NodeInfo + + n, _ := self.FindAllNodes() + + for _, node := range n { + for _, dev := range node.NetDevs { + if dev.Hwaddr == hwa { + return node, nil + } + } + } + + return ret, errors.New("No nodes found with HW Addr: " + hwa) +} + +func (self *nodeYaml) FindByIpaddr(ipaddr string) (NodeInfo, error) { + var ret NodeInfo + + n, _ := self.FindAllNodes() + + for _, node := range n { + for _, dev := range node.NetDevs { + if dev.Ipaddr == ipaddr { + return node, nil + } + } + } + + return ret, errors.New("No nodes found with IP Addr: " + ipaddr) +} + + + + + + + + +func (nodes *nodeYaml) SearchByName(search string) ([]NodeInfo, error) { + var ret []NodeInfo + + n, _ := nodes.FindAllNodes() + + for _, node := range n { + b, _ := regexp.MatchString(search, node.Fqdn) + if b == true { + ret = append(ret, node) + } + } + + return ret, nil +} + +func (nodes *nodeYaml) SearchByNameList(searchList []string) ([]NodeInfo, error) { + var ret []NodeInfo + + n, _ := nodes.FindAllNodes() + + for _, search := range searchList { + for _, node := range n { + b, _ := regexp.MatchString(search, node.Fqdn) + if b == true { + ret = append(ret, node) + } + } + } + + return ret, nil +} diff --git a/internal/pkg/node/datastructure.go b/internal/pkg/node/datastructure.go new file mode 100644 index 00000000..831ce558 --- /dev/null +++ b/internal/pkg/node/datastructure.go @@ -0,0 +1,123 @@ +package node + +import ( + "github.com/hpcng/warewulf/internal/pkg/util" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "os" +) + +type nodeYaml struct { + NodeProfiles map[string]*ProfileConf + NodeGroups map[string]*GroupConf +} + +type ProfileConf struct { + Comment string `yaml:"comment"` + Vnfs string `yaml:"vnfs,omitempty"` + Ipxe string `yaml:"ipxe template,omitempty"` + KernelVersion string `yaml:"kernel version,omitempty"` + KernelArgs string `yaml:"kernel args,omitempty"` + IpmiUserName string `yaml:"ipmi username,omitempty"` + IpmiPassword string `yaml:"ipmi password,omitempty"` + DomainName string `yaml:"domain name,omitempty"` + RuntimeOverlay string `yaml:"runtime overlay files,omitempty"` + SystemOverlay string `yaml:"system overlay files,omitempty"` +} + +type GroupConf struct { + Comment string `yaml:"comment"` + Disabled bool `yaml:"disabled,omitempty"` + DomainName string `yaml:"domain name"` + Profiles []string `yaml:"profiles,omitempty"` + Nodes map[string]*NodeConf +} + +type NodeConf struct { + Comment string `yaml:"comment,omitempty"` + Disabled bool `yaml:"disabled,omitempty"` + Hostname string `yaml:"hostname,omitempty"` + Vnfs string `yaml:"vnfs,omitempty"` + Ipxe string `yaml:"ipxe template,omitempty"` + KernelVersion string `yaml:"kernel version,omitempty"` + KernelArgs string `yaml:"kernel args,omitempty"` + IpmiUserName string `yaml:"ipmi username,omitempty"` + IpmiPassword string `yaml:"ipmi password,omitempty"` + DomainName string `yaml:"domain name,omitempty"` + IpmiIpaddr string `yaml:"ipmi ipaddr,omitempty"` + RuntimeOverlay string `yaml:"runtime overlay files,omitempty"` + SystemOverlay string `yaml:"system overlay files,omitempty"` + Profiles []string `yaml:"profiles,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 NodeInfoEntry struct { + value string + profile string + group string + def string +} + +type NodeInfo struct { + Id string + Gid string + Uid string + Comment string + GroupName string + HostName string + Fqdn string + DomainName NodeInfoEntry + Vnfs NodeInfoEntry + VnfsRoot NodeInfoEntry + Ipxe NodeInfoEntry + KernelVersion NodeInfoEntry + KernelArgs NodeInfoEntry + IpmiIpaddr NodeInfoEntry + IpmiUserName NodeInfoEntry + IpmiPassword NodeInfoEntry + RuntimeOverlay NodeInfoEntry + SystemOverlay NodeInfoEntry + Profiles []string + NetDevs map[string]*NetDevs +} + +type GroupInfo struct { + Id string + Comment string + Disabled bool + DomainName string + Profiles []string +} + +type ProfileInfo struct { + Id string + Comment string + Vnfs string + Ipxe string + KernelVersion string + KernelArgs string + IpmiUserName string + IpmiPassword string + DomainName string + RuntimeOverlay string + SystemOverlay string +} + + + +const ConfigFile = "/etc/warewulf/nodes.conf" + +func init() { + //TODO: Check to make sure nodes.conf is found + if util.IsFile(ConfigFile) == false { + wwlog.Printf(wwlog.ERROR, "Configuration file not found: %s\n", ConfigFile) + os.Exit(1) + } +} diff --git a/internal/pkg/node/methods.go b/internal/pkg/node/methods.go new file mode 100644 index 00000000..93e12b54 --- /dev/null +++ b/internal/pkg/node/methods.go @@ -0,0 +1,55 @@ +package node + +func (self *NodeInfoEntry) String() string { + if self.value != "" { + return "node=" + self.value + } + if self.group != "" { + return "group=" + self.group + } + if self.profile != "" { + return "profile=" + self.profile + } + if self.def != "" { + return "default=" + self.def + } + return "--" +} + +func (self *NodeInfoEntry) Get() string { + if self.value != "" { + return self.value + } + if self.group != "" { + return self.group + } + if self.profile != "" { + return self.profile + } + if self.def != "" { + return self.def + } + return "" +} + +func (self *NodeInfoEntry) Defined() bool { + if self.Get() == "" { + return false + } + return true +} + +func (self *NodeInfoEntry) Set(value string) { + if value == "" { + return + } + self.value = value +} + +func (self *NodeInfoEntry) Unset() { + self.value = "" +} + +func (self *NodeInfoEntry) GetReal() string { + return self.value +} \ No newline at end of file diff --git a/internal/pkg/node/modifiers.go b/internal/pkg/node/modifiers.go new file mode 100644 index 00000000..014a9dca --- /dev/null +++ b/internal/pkg/node/modifiers.go @@ -0,0 +1,209 @@ +package node + +import ( + "github.com/hpcng/warewulf/internal/pkg/errors" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + + "gopkg.in/yaml.v2" + "os" +) + +/**** + * + * NODE MODIFIERS + * +****/ + +func (self *nodeYaml) AddNode(groupID string, nodeID string) error { + var node NodeConf + + wwlog.Printf(wwlog.VERBOSE, "Adding new node: %s/%s\n", groupID, nodeID) + + if _, ok := self.NodeGroups[groupID]; !ok { + return errors.New("Group does not exist: " + groupID) + } + + if _, ok := self.NodeGroups[groupID].Nodes[groupID]; ok { + return errors.New("Nodename already exists in group: " + nodeID) + } + + self.NodeGroups[groupID].Nodes[nodeID] = &node + self.NodeGroups[groupID].Nodes[nodeID].Hostname = nodeID + + return nil +} + +func (self *nodeYaml) DelNode(groupID string, nodeID string) error { + + if _, ok := self.NodeGroups[groupID]; !ok { + return errors.New("Group '" + groupID + "' was not found") + } + if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; !ok { + return errors.New("Node '" + nodeID + "' was not found in group '" + groupID + "'") + } + + wwlog.Printf(wwlog.VERBOSE, "Deleting node network device: %s/%s\n", groupID, nodeID) + delete(self.NodeGroups[groupID].Nodes, nodeID) + + return nil +} + +func(self *nodeYaml) NodeUpdate(node NodeInfo) error { + groupID := node.Gid + nodeID := node.Id + + if _, ok := self.NodeGroups[groupID]; !ok { + return errors.New("Group '" + groupID + "' was not found") + } + if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; !ok { + return errors.New("Node '" + nodeID + "' was not found in group '" + groupID + "'") + } + + self.NodeGroups[groupID].Nodes[nodeID].Hostname = node.HostName + self.NodeGroups[groupID].Nodes[nodeID].Vnfs = node.Vnfs.GetReal() + self.NodeGroups[groupID].Nodes[nodeID].DomainName = node.DomainName.GetReal() + self.NodeGroups[groupID].Nodes[nodeID].Ipxe = node.Ipxe.GetReal() + self.NodeGroups[groupID].Nodes[nodeID].KernelVersion = node.KernelVersion.GetReal() + self.NodeGroups[groupID].Nodes[nodeID].KernelArgs = node.KernelArgs.GetReal() + self.NodeGroups[groupID].Nodes[nodeID].IpmiIpaddr = node.IpmiIpaddr.GetReal() + self.NodeGroups[groupID].Nodes[nodeID].IpmiUserName = node.IpmiUserName.GetReal() + self.NodeGroups[groupID].Nodes[nodeID].IpmiPassword = node.IpmiPassword.GetReal() + self.NodeGroups[groupID].Nodes[nodeID].RuntimeOverlay = node.RuntimeOverlay.GetReal() + self.NodeGroups[groupID].Nodes[nodeID].SystemOverlay = node.SystemOverlay.GetReal() + self.NodeGroups[groupID].Nodes[nodeID].Profiles = node.Profiles + self.NodeGroups[groupID].Nodes[nodeID].NetDevs = node.NetDevs + + return nil +} + + + +/**** + * + * GROUP MODIFIERS + * +****/ + +func (self *nodeYaml) AddGroup(groupID string) error { + var group GroupConf + + wwlog.Printf(wwlog.VERBOSE, "Adding new group: %s/%s\n", groupID) + + if _, ok := self.NodeGroups[groupID]; ok { + return errors.New("Group name already exists: " + groupID) + } + + self.NodeGroups[groupID] = &group + self.NodeGroups[groupID].DomainName = groupID + + return nil +} + +func (self *nodeYaml) DelGroup(groupID string) error { + if _, ok := self.NodeGroups[groupID]; !ok { + + return errors.New("Group '" + groupID + "' was not found") + } + + wwlog.Printf(wwlog.VERBOSE, "Deleting group: %s\n", groupID) + delete(self.NodeGroups, groupID) + + return nil +} + +func(self *nodeYaml) GroupUpdate(group GroupInfo) error { + groupID := group.Id + + if _, ok := self.NodeGroups[groupID]; !ok { + return errors.New("Group '" + groupID + "' was not found") + } + + self.NodeGroups[groupID].DomainName = group.DomainName + + return nil +} + + + + +/**** + * + * PROFILE MODIFIERS + * +****/ + +func (self *nodeYaml) AddProfile(profileID string) error { + var profile ProfileConf + + wwlog.Printf(wwlog.VERBOSE, "Adding new profile: %s/%s\n", profileID) + + if _, ok := self.NodeProfiles[profileID]; ok { + return errors.New("Profile name already exists: " + profileID) + } + + self.NodeProfiles[profileID] = &profile + + return nil +} + +func (self *nodeYaml) DelProfile(profileID string) error { + if _, ok := self.NodeProfiles[profileID]; ! ok { + return errors.New("Group '" + profileID + "' was not found") + } + + wwlog.Printf(wwlog.VERBOSE, "Deleting profile: %s\n", profileID) + delete(self.NodeProfiles, profileID) + + return nil +} + +func(self *nodeYaml) ProfileUpdate(profile ProfileInfo) error { + profileID := profile.Id + + if _, ok := self.NodeProfiles[profileID]; ! ok { + return errors.New("Group '" + profileID + "' was not found") + } + + self.NodeProfiles[profileID].DomainName = profile.DomainName + self.NodeProfiles[profileID].Vnfs = profile.Vnfs + self.NodeProfiles[profileID].Ipxe = profile.Ipxe + self.NodeProfiles[profileID].KernelVersion = profile.KernelVersion + self.NodeProfiles[profileID].IpmiUserName = profile.IpmiUserName + self.NodeProfiles[profileID].IpmiPassword = profile.IpmiPassword + self.NodeProfiles[profileID].RuntimeOverlay = profile.RuntimeOverlay + self.NodeProfiles[profileID].SystemOverlay = profile.SystemOverlay + + return nil +} + + + + +/**** + * + * PERSISTENCE + * +****/ + +func (self *nodeYaml) Persist() error { + + out, err := yaml.Marshal(self) + if err != nil { + return err + } + + file, err := os.OpenFile(ConfigFile, 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 +} diff --git a/internal/pkg/node/modify.go b/internal/pkg/node/modify.go deleted file mode 100644 index e120f777..00000000 --- a/internal/pkg/node/modify.go +++ /dev/null @@ -1,222 +0,0 @@ -package node - -import ( - "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" - "os" - "strings" -) - -func (self *nodeYaml) AddGroup(groupID string) error { - var group nodeGroup - - if _, ok := self.NodeGroups[groupID]; ok { - return errors.New("Group name already exists: " + groupID) - } - - self.NodeGroups[groupID] = &group - self.NodeGroups[groupID].DomainSuffix = groupID - - return nil -} - -func (self *nodeYaml) AddNode(groupID string, nodeID string) error { - var node nodeEntry - - wwlog.Printf(wwlog.VERBOSE, "Adding new node: %s/%s\n", groupID, nodeID) - - if _, ok := self.NodeGroups[groupID]; ok { - if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { - return errors.New("Nodename already exists in group: " + nodeID) - } - } else { - return errors.New("Group does not exist: "+groupID) - } - - self.NodeGroups[groupID].Nodes[nodeID] = &node - self.NodeGroups[groupID].Nodes[nodeID].Hostname = nodeID - - return nil -} - -func (self *nodeYaml) DelNode(groupID string, nodeID string) error { - - if _, ok := self.NodeGroups[groupID]; ok { - if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { - delete(self.NodeGroups[groupID].Nodes, nodeID) - wwlog.Printf(wwlog.VERBOSE, "Deleting node: %s/%s\n", groupID, nodeID) - } else { - return errors.New("Node '"+nodeID+"' was not found in group '"+groupID+"'") - } - } else { - return errors.New("Group '"+groupID+"' was not found") - } - - return nil -} - -func (self *nodeYaml) DelNodeNet(groupID string, nodeID string, netDev string) error { - - if _, ok := self.NodeGroups[groupID]; ok { - if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { - if _, ok := self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev]; ok { - wwlog.Printf(wwlog.VERBOSE, "Deleting node network device: %s/%s:%s\n", groupID, nodeID, netDev) - delete(self.NodeGroups[groupID].Nodes[nodeID].NetDevs, netDev) - } else { - return errors.New("Network device '"+netDev+"' was not found in node '"+groupID+"/"+nodeID+"'") - } - } else { - return errors.New("Node '"+nodeID+"' was not found in group '"+groupID+"'") - } - } else { - return errors.New("Group '"+groupID+"' was not found") - } - - return nil -} - - -func (self *nodeYaml) DelGroup(groupname string) error { - if _, ok := self.NodeGroups[groupname]; ok { - delete(self.NodeGroups, groupname) - } else { - return errors.New("Node group undefined: " + groupname) - } - - return nil -} - -func (self *nodeYaml) SetGroupVal(groupID string, entry string, value string) error { - if strings.ToUpper(value) == "UNDEF" || strings.ToUpper(value) == "NIL" || strings.ToUpper(value) == "DEL" { - value = "" - } - - if _, ok := self.NodeGroups[groupID]; ok { - wwlog.Printf(wwlog.VERBOSE, "Setting group %s to: %s = '%s'\n", groupID, entry, value ) - - switch strings.ToUpper(entry) { - case "DOMAINSUFFIX": - util.ValidateOrDie("Domain", entry, "^[a-zA-Z0-9-._]*$") - self.NodeGroups[groupID].DomainSuffix = value - } - - } else { - return errors.New("Group does not exist: " +groupID) - } - - return nil -} - -func (self *nodeYaml) SetNodeVal(groupID string, nodeID string, entry string, value string) error { - if strings.ToUpper(value) == "UNDEF" || strings.ToUpper(value) == "NIL" || strings.ToUpper(value) == "DEL" { - value = "" - } - if _, ok := self.NodeGroups[groupID]; ok { - if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { - wwlog.Printf(wwlog.VERBOSE, "Setting node %s/%s to: %s = '%s'\n", groupID, nodeID, entry, value ) - - switch strings.ToUpper(entry) { - case "VNFS": - util.ValidateOrDie("VNFS", entry, "^[a-zA-Z0-9-._]*$") - self.NodeGroups[groupID].Nodes[nodeID].Vnfs = value - case "KERNEL": - util.ValidateOrDie("Kernel Version", entry, "^[a-zA-Z0-9-._]*$") - self.NodeGroups[groupID].Nodes[nodeID].KernelVersion = value - case "DOMAINSUFFIX": - util.ValidateOrDie("Domain", entry, "^[a-zA-Z0-9-._]*$") - self.NodeGroups[groupID].Nodes[nodeID].DomainSuffix = value - case "IPXE": - util.ValidateOrDie("iPXE Template", entry, "^[a-zA-Z0-9-._]*$") - self.NodeGroups[groupID].Nodes[nodeID].Ipxe = value - case "HOSTNAME": - util.ValidateOrDie("Hostname", entry, "^[a-zA-Z0-9-._]*$") - self.NodeGroups[groupID].Nodes[nodeID].Hostname = value - case "IPMIIPADDR": - util.ValidateOrDie("IPMI IP Address", entry, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") - self.NodeGroups[groupID].Nodes[nodeID].IpmiIpaddr = value - case "IPMIUSERNAME": - util.ValidateOrDie("IPMI Username", entry, "^[a-zA-Z0-9-._]*$") - self.NodeGroups[groupID].Nodes[nodeID].IpmiUserName = value - case "IPMIPASSWORD": - util.ValidateOrDie("IPMI Password", entry, "^[a-zA-Z0-9-._]*$") - self.NodeGroups[groupID].Nodes[nodeID].IpmiPassword = value - - } - } else { - return errors.New("Node does not exist: " +groupID+ "/" +nodeID) - } - } else { - return errors.New("Group does not exist: " +groupID) - } - - return nil -} - -func (self *nodeYaml) SetNodeNet(groupID string, nodeID string, netDev string, entry string, value string) error { - if strings.ToUpper(value) == "UNDEF" || strings.ToUpper(value) == "NIL" || strings.ToUpper(value) == "DEL" { - value = "" - } - - if _, ok := self.NodeGroups[groupID]; ok { - if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { - 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 - self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev] = &nd - } - } else { - return errors.New("Node does not exist: "+groupID+"/"+nodeID) - } - } else { - return errors.New("Group does not exist: "+groupID) - } - - switch strings.ToUpper(entry) { - case "IPADDR": - util.ValidateOrDie("IP address", value, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") - self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Ipaddr = value - case "NETMASK": - util.ValidateOrDie("Netmask", value, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") - self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Netmask = value - case "GATEWAY": - util.ValidateOrDie("Gateway", value, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") - self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Gateway = value - case "TYPE": - util.ValidateOrDie("Network device type", value, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") - self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Type = value - case "HWADDR": - util.ValidateOrDie("HW address", value, "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$") - self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Hwaddr = value - - } - - return nil -} - -func (self *nodeYaml) Persist() error { - - out, err := yaml.Marshal(self) - if err != nil { - return err - } - - file, err := os.OpenFile(ConfigFile, 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 -} - diff --git a/internal/pkg/node/node.go b/internal/pkg/node/node.go deleted file mode 100644 index 139c435c..00000000 --- a/internal/pkg/node/node.go +++ /dev/null @@ -1,377 +0,0 @@ -package node - -import ( - "fmt" - "github.com/hpcng/warewulf/internal/pkg/config" - "github.com/hpcng/warewulf/internal/pkg/errors" - "github.com/hpcng/warewulf/internal/pkg/vnfs" - "github.com/hpcng/warewulf/internal/pkg/wwlog" - "gopkg.in/yaml.v2" - "io/ioutil" - "regexp" -) - -const ConfigFile = "/etc/warewulf/nodes.conf" - -func init() { - //TODO: Check to make sure nodes.conf is found - -} - -type nodeYaml struct { - 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 - 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"` - 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 EntryInfo struct { - Value string - override string - def string -} - -type NodeInfo struct { - 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 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 - } - i.def = value -} - -func (i *EntryInfo) Set (value string) { - if value == "" { - return - } - i.Value = value - i.override = "" -} - -func (i *EntryInfo) Override (value string) { - if value == "" { - return - } - i.override = value -} - -func (i *EntryInfo) String () string { - if i.override != "" { - return i.override - } else if i.Value != "" { - return i.Value - } - return i.def -} - -func (i *EntryInfo) Defined () bool { - if i.String() == "" { - return false - } - return true -} - -func (i *EntryInfo) Fprint () string { - if i.override != "" { - return "["+ i.override +"]" - } else if i.Value != "" { - return i.Value - } else if i.def != "" { - return "("+ i.def +")" - } - return "--" -} - -func New() (nodeYaml, error) { - var ret nodeYaml - - wwlog.Printf(wwlog.DEBUG, "Opening node configuration file: %s\n", ConfigFile) - data, err := ioutil.ReadFile(ConfigFile) - if err != nil { - fmt.Printf("error reading node configuration file\n") - return ret, err - } - - err = yaml.Unmarshal(data, &ret) - if err != nil { - return ret, err - } - - return ret, nil -} - - -func (self *nodeYaml) FindAllGroups() ([]GroupInfo, error) { - var ret []GroupInfo - - for groupname, group := range self.NodeGroups { - var g GroupInfo - - g.Id = groupname - g.GroupName = groupname - g.DomainName = group.DomainSuffix - - // TODO: Validate or die on all inputs - - ret = append(ret, g) - } - return ret, nil -} - - -func (self *nodeYaml) FindAllNodes() ([]NodeInfo, error) { - var ret []NodeInfo - - for groupname, group := range self.NodeGroups { - for nodename, node := range group.Nodes { - var n NodeInfo - - n.Id = nodename - n.Gid = groupname - n.GroupName = groupname - n.HostName = node.Hostname - n.Profiles = node.Profiles - n.IpmiIpaddr = node.IpmiIpaddr - - if len(n.Profiles) == 0 { - n.Profiles = append(n.Profiles, "default") - } - - for _, p := range n.Profiles { - if _, ok := self.Profiles[p]; ok { - } else { - 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) - } - } - - 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 - } - - 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) - } - } - - return ret, nil -} - -func (self *nodeYaml) FindByHwaddr(hwa string) (NodeInfo, error) { - var ret NodeInfo - - n, _ := self.FindAllNodes() - - for _, node := range n { - for _, dev := range node.NetDevs { - if dev.Hwaddr == hwa { - return node, nil - } - } - } - - return ret, errors.New("No nodes found with HW Addr: " + hwa) -} - -func (self *nodeYaml) FindByIpaddr(ipaddr string) (NodeInfo, error) { - var ret NodeInfo - - n, _ := self.FindAllNodes() - - for _, node := range n { - for _, dev := range node.NetDevs { - if dev.Ipaddr == ipaddr { - return node, nil - } - } - } - - return ret, errors.New("No nodes found with IP Addr: " + ipaddr) -} - -func (nodes *nodeYaml) SearchByName(search string) ([]NodeInfo, error) { - var ret []NodeInfo - - n, _ := nodes.FindAllNodes() - - for _, node := range n { - b, _ := regexp.MatchString(search, node.Fqdn) - if b == true { - ret = append(ret, node) - } - } - - return ret, nil -} - -func (nodes *nodeYaml) SearchByNameList(searchList []string) ([]NodeInfo, error) { - var ret []NodeInfo - - n, _ := nodes.FindAllNodes() - - for _, search := range searchList { - for _, node := range n { - b, _ := regexp.MatchString(search, node.Fqdn) - if b == true { - ret = append(ret, node) - } - } - } - - return ret, nil -} \ No newline at end of file From e84b4e4d6abd2c20efec3d157b5a33c2deb75d08 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Thu, 26 Nov 2020 19:14:58 -0800 Subject: [PATCH 04/32] Fixes for the new nodeDB API --- internal/app/warewulfd/response/ipxe.go | 16 ++++++++-------- internal/app/warewulfd/response/kernel.go | 8 ++++---- internal/app/warewulfd/response/kmods.go | 8 ++++---- internal/app/warewulfd/response/runtime.go | 12 ++++++------ internal/app/warewulfd/response/system.go | 8 ++++---- internal/app/warewulfd/response/util.go | 4 ++-- internal/app/warewulfd/response/vnfs.go | 11 +++++------ 7 files changed, 33 insertions(+), 34 deletions(-) diff --git a/internal/app/warewulfd/response/ipxe.go b/internal/app/warewulfd/response/ipxe.go index 9440b341..11194c6e 100644 --- a/internal/app/warewulfd/response/ipxe.go +++ b/internal/app/warewulfd/response/ipxe.go @@ -46,13 +46,13 @@ func IpxeSend(w http.ResponseWriter, req *http.Request) { return } - if node.HostName.Defined() == true { + if node.Id.Defined() == true { conf := config.New() - log.Printf("IPXE: %15s: %s\n", node.Fqdn.String(), req.URL.Path) + log.Printf("IPXE: %15s: %s\n", node.Fqdn.Get(), req.URL.Path) // TODO: Fix template path to use config package - ipxeTemplate := fmt.Sprintf("/etc/warewulf/ipxe/%s.ipxe", node.Ipxe.String()) + ipxeTemplate := fmt.Sprintf("/etc/warewulf/ipxe/%s.ipxe", node.Ipxe.Get()) tmpl, err := template.ParseFiles(ipxeTemplate) if err != nil { @@ -62,13 +62,13 @@ func IpxeSend(w http.ResponseWriter, req *http.Request) { var replace iPxeTemplate - replace.Fqdn = node.Fqdn.String() + replace.Fqdn = node.Fqdn.Get() replace.Ipaddr = conf.Ipaddr replace.Port = strconv.Itoa(conf.Port) - replace.Hostname = node.HostName.String() + replace.Hostname = node.HostName.Get() replace.Hwaddr = url[2] - replace.Vnfs = node.Vnfs.String() - replace.Kernelargs = node.KernelArgs.String() + replace.Vnfs = node.Vnfs.Get() + replace.Kernelargs = node.KernelArgs.Get() err = tmpl.Execute(w, replace) if err != nil { @@ -76,7 +76,7 @@ func IpxeSend(w http.ResponseWriter, req *http.Request) { return } - log.Printf("SEND: %15s: %s\n", node.Fqdn.String(), ipxeTemplate) + log.Printf("SEND: %15s: %s\n", node.Fqdn.Get(), 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 8fca6a42..f9fac3b9 100644 --- a/internal/app/warewulfd/response/kernel.go +++ b/internal/app/warewulfd/response/kernel.go @@ -17,18 +17,18 @@ func KernelSend(w http.ResponseWriter, req *http.Request) { } if node.KernelVersion.Defined() == true { - fileName := config.KernelImage(node.KernelVersion.String()) + fileName := config.KernelImage(node.KernelVersion.Get()) - err := sendFile(w, fileName, node.Fqdn.String()) + err := sendFile(w, fileName, node.Fqdn.Get()) if err != nil { log.Printf("ERROR: %s\n", err) } else { - log.Printf("SEND: %15s: %s\n", node.Fqdn.String(), fileName) + log.Printf("SEND: %15s: %s\n", node.Fqdn.Get(), fileName) } } else { w.WriteHeader(503) - log.Printf("ERROR: No 'kernel version' set for node %s\n", node.Fqdn.String()) + log.Printf("ERROR: No 'kernel version' set for node %s\n", node.Fqdn.Get()) } return diff --git a/internal/app/warewulfd/response/kmods.go b/internal/app/warewulfd/response/kmods.go index c5bfe00f..00db3605 100644 --- a/internal/app/warewulfd/response/kmods.go +++ b/internal/app/warewulfd/response/kmods.go @@ -17,18 +17,18 @@ func KmodsSend(w http.ResponseWriter, req *http.Request) { } if node.KernelVersion.Defined() == true { - fileName := config.KmodsImage(node.KernelVersion.String()) + fileName := config.KmodsImage(node.KernelVersion.Get()) - err := sendFile(w, fileName, node.Fqdn.String()) + err := sendFile(w, fileName, node.Fqdn.Get()) if err != nil { log.Printf("ERROR: %s\n", err) } else { - log.Printf("SEND: %15s: %s\n", node.Fqdn.String(), fileName) + log.Printf("SEND: %15s: %s\n", node.Fqdn.Get(), fileName) } } else { w.WriteHeader(503) - log.Printf("ERROR: No 'kernel version' set for node %s\n", node.Fqdn.String()) + log.Printf("ERROR: No 'kernel version' set for node %s\n", node.Fqdn.Get()) } return diff --git a/internal/app/warewulfd/response/runtime.go b/internal/app/warewulfd/response/runtime.go index 83b0a95d..7c784a85 100644 --- a/internal/app/warewulfd/response/runtime.go +++ b/internal/app/warewulfd/response/runtime.go @@ -47,26 +47,26 @@ func RuntimeOverlaySend(w http.ResponseWriter, req *http.Request) { return } - if node.Fqdn.Defined() == false { + if node.Id.Defined() == false { log.Printf("UNKNOWN: %15s: %s\n", remote[0], req.URL.Path) w.WriteHeader(404) return } else { - log.Printf("REQ: %15s: %s\n", node.Fqdn.String(), req.URL.Path) + log.Printf("REQ: %15s: %s\n", node.Fqdn.Get(), req.URL.Path) } if node.RuntimeOverlay.Defined() == true { - fileName := config.RuntimeOverlayImage(node.Fqdn.String()) + fileName := config.RuntimeOverlayImage(node.Fqdn.Get()) - err := sendFile(w, fileName, node.Fqdn.String()) + err := sendFile(w, fileName, node.Fqdn.Get()) if err != nil { log.Printf("ERROR: %s\n", err) } else { - log.Printf("SEND: %15s: %s\n", node.Fqdn.String(), fileName) + log.Printf("SEND: %15s: %s\n", node.Fqdn.Get(), fileName) } } else { w.WriteHeader(503) - log.Printf("ERROR: No 'runtime system-overlay' set for node %s\n", node.Fqdn.String()) + log.Printf("ERROR: No 'runtime system-overlay' set for node %s\n", node.Fqdn.Get()) } return diff --git a/internal/app/warewulfd/response/system.go b/internal/app/warewulfd/response/system.go index dfa1649b..2a28cd56 100644 --- a/internal/app/warewulfd/response/system.go +++ b/internal/app/warewulfd/response/system.go @@ -17,17 +17,17 @@ func SystemOverlaySend(w http.ResponseWriter, req *http.Request) { } if node.SystemOverlay.Defined() == true { - fileName := config.SystemOverlayImage(node.Fqdn.String()) + fileName := config.SystemOverlayImage(node.Fqdn.Get()) - err := sendFile(w, fileName, node.Fqdn.String()) + err := sendFile(w, fileName, node.Fqdn.Get()) if err != nil { log.Printf("ERROR: %s\n", err) } else { - log.Printf("SEND: %15s: %s\n", node.Fqdn.String(), fileName) + log.Printf("SEND: %15s: %s\n", node.Fqdn.Get(), fileName) } } else { w.WriteHeader(503) - log.Printf("ERROR: No 'system system-overlay' set for node %s\n", node.Fqdn.String()) + log.Printf("ERROR: No 'system system-overlay' set for node %s\n", node.Fqdn.Get()) } return diff --git a/internal/app/warewulfd/response/util.go b/internal/app/warewulfd/response/util.go index e739f8e1..f4ccc79a 100644 --- a/internal/app/warewulfd/response/util.go +++ b/internal/app/warewulfd/response/util.go @@ -2,8 +2,8 @@ package response import ( "fmt" - "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/errors" + "github.com/hpcng/warewulf/internal/pkg/node" "io" "log" "net/http" @@ -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.String(), req.URL.Path) + log.Printf("REQ: %15s: %s\n", ret.Fqdn.Get(), req.URL.Path) } return ret, nil diff --git a/internal/app/warewulfd/response/vnfs.go b/internal/app/warewulfd/response/vnfs.go index 2d5eb8ed..e6e84a18 100644 --- a/internal/app/warewulfd/response/vnfs.go +++ b/internal/app/warewulfd/response/vnfs.go @@ -7,7 +7,6 @@ import ( ) func VnfsSend(w http.ResponseWriter, req *http.Request) { -// config := config.New() node, err := getSanity(req) if err != nil { @@ -18,22 +17,22 @@ func VnfsSend(w http.ResponseWriter, req *http.Request) { if node.Vnfs.Defined() == true { - v, err := vnfs.Load(node.Vnfs.String()) + v, err := vnfs.Load(node.Vnfs.Get()) if err != nil { w.WriteHeader(503) - log.Printf("ERROR: Could not load VNFS: %s\n", node.Fqdn.String()) + log.Printf("ERROR: Could not load VNFS: %s\n", node.Fqdn.Get()) return } - err = sendFile(w, v.Image, node.Fqdn.String()) + err = sendFile(w, v.Image, node.Fqdn.Get()) if err != nil { log.Printf("ERROR1: %s\n", err) } else { - log.Printf("SEND: %15s: %s\n", node.Fqdn.String(), v.Image) + log.Printf("SEND: %15s: %s\n", node.Fqdn.Get(), v.Image) } } else { w.WriteHeader(503) - log.Printf("ERROR: No VNFS set for node %s\n", node.Fqdn.String()) + log.Printf("ERROR: No VNFS set for node %s\n", node.Fqdn.Get()) } return From 421a03b75dd2479a164a392d0e2e86891f56444c Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Thu, 26 Nov 2020 19:15:30 -0800 Subject: [PATCH 05/32] Updates to nodeDB --- internal/pkg/node/constructors.go | 58 +++++++++++++++--------------- internal/pkg/node/datastructure.go | 14 ++++---- internal/pkg/node/methods.go | 22 ++++++++++++ internal/pkg/node/modifiers.go | 6 ++-- 4 files changed, 61 insertions(+), 39 deletions(-) diff --git a/internal/pkg/node/constructors.go b/internal/pkg/node/constructors.go index ad76b714..11018d65 100644 --- a/internal/pkg/node/constructors.go +++ b/internal/pkg/node/constructors.go @@ -40,10 +40,10 @@ func (self *nodeYaml) FindAllNodes() ([]NodeInfo, error) { continue } - n.Id = nodename - n.Gid = groupname - n.GroupName = groupname - n.HostName = node.Hostname + n.Id.Set(nodename) + n.Gid.Set(groupname) + n.GroupName.Set(groupname) + n.HostName.Set(node.Hostname) n.IpmiIpaddr.Set(node.IpmiIpaddr) n.Profiles = node.Profiles @@ -57,38 +57,38 @@ func (self *nodeYaml) FindAllNodes() ([]NodeInfo, error) { continue } - n.Vnfs.profile = self.NodeProfiles[p].Vnfs - n.KernelVersion.profile = self.NodeProfiles[p].KernelVersion - n.KernelArgs.profile = self.NodeProfiles[p].KernelArgs - n.Ipxe.profile = self.NodeProfiles[p].Ipxe - n.IpmiUserName.profile = self.NodeProfiles[p].IpmiUserName - n.IpmiPassword.profile = self.NodeProfiles[p].IpmiPassword - n.DomainName.profile = self.NodeProfiles[p].DomainName - n.SystemOverlay.profile = self.NodeProfiles[p].SystemOverlay - n.RuntimeOverlay.profile = self.NodeProfiles[p].RuntimeOverlay + n.Vnfs.SetProfile(self.NodeProfiles[p].Vnfs) + n.KernelVersion.SetProfile(self.NodeProfiles[p].KernelVersion) + n.KernelArgs.SetProfile(self.NodeProfiles[p].KernelArgs) + n.Ipxe.SetProfile(self.NodeProfiles[p].Ipxe) + n.IpmiUserName.SetProfile(self.NodeProfiles[p].IpmiUserName) + n.IpmiPassword.SetProfile(self.NodeProfiles[p].IpmiPassword) + n.DomainName.SetProfile(self.NodeProfiles[p].DomainName) + n.SystemOverlay.SetProfile(self.NodeProfiles[p].SystemOverlay) + n.RuntimeOverlay.SetProfile(self.NodeProfiles[p].RuntimeOverlay) } - n.DomainName.value = node.DomainName - n.DomainName.group = group.DomainName - n.Vnfs.value = node.Vnfs - n.KernelVersion.value = node.KernelVersion - n.KernelArgs.value = node.KernelArgs - n.Ipxe.value = node.Ipxe - n.IpmiUserName.value = node.IpmiUserName - n.IpmiPassword.value = node.IpmiPassword + n.DomainName.Set(node.DomainName) + n.DomainName.SetGroup(group.DomainName) + n.Vnfs.Set(node.Vnfs) + n.KernelVersion.Set(node.KernelVersion) + n.KernelArgs.Set(node.KernelArgs) + n.Ipxe.Set(node.Ipxe) + n.IpmiUserName.Set(node.IpmiUserName) + n.IpmiPassword.Set(node.IpmiPassword) - n.RuntimeOverlay.def = "default" - n.SystemOverlay.def = "default" - n.Ipxe.def = "default" - n.KernelArgs.def = "crashkernel=no quiet" + n.RuntimeOverlay.SetDefault("default") + n.SystemOverlay.SetDefault("default") + n.Ipxe.SetDefault("default") + n.KernelArgs.SetDefault("crashkernel=no quiet") // config := config.New() // n.VnfsRoot = config.VnfsChroot(vnfs.CleanName(n.Vnfs)) if n.DomainName.Defined() == true { - n.Fqdn = n.HostName + "." + n.DomainName.Get() + n.Fqdn.Set(node.Hostname +"."+ n.DomainName.Get()) } else { - n.Fqdn = node.Hostname + n.Fqdn.Set(node.Hostname) } n.NetDevs = node.NetDevs @@ -192,7 +192,7 @@ func (nodes *nodeYaml) SearchByName(search string) ([]NodeInfo, error) { n, _ := nodes.FindAllNodes() for _, node := range n { - b, _ := regexp.MatchString(search, node.Fqdn) + b, _ := regexp.MatchString(search, node.Fqdn.Get()) if b == true { ret = append(ret, node) } @@ -208,7 +208,7 @@ func (nodes *nodeYaml) SearchByNameList(searchList []string) ([]NodeInfo, error) for _, search := range searchList { for _, node := range n { - b, _ := regexp.MatchString(search, node.Fqdn) + b, _ := regexp.MatchString(search, node.Fqdn.Get()) if b == true { ret = append(ret, node) } diff --git a/internal/pkg/node/datastructure.go b/internal/pkg/node/datastructure.go index 831ce558..4ce7acca 100644 --- a/internal/pkg/node/datastructure.go +++ b/internal/pkg/node/datastructure.go @@ -66,13 +66,13 @@ type NodeInfoEntry struct { } type NodeInfo struct { - Id string - Gid string - Uid string - Comment string - GroupName string - HostName string - Fqdn string + Id NodeInfoEntry + Gid NodeInfoEntry + Uid NodeInfoEntry + Comment NodeInfoEntry + GroupName NodeInfoEntry + HostName NodeInfoEntry + Fqdn NodeInfoEntry DomainName NodeInfoEntry Vnfs NodeInfoEntry VnfsRoot NodeInfoEntry diff --git a/internal/pkg/node/methods.go b/internal/pkg/node/methods.go index 93e12b54..dfc25789 100644 --- a/internal/pkg/node/methods.go +++ b/internal/pkg/node/methods.go @@ -36,9 +36,31 @@ func (self *NodeInfoEntry) Defined() bool { if self.Get() == "" { return false } + return true } +func (self *NodeInfoEntry) SetDefault(value string) { + if value == "" { + return + } + self.def = value +} + +func (self *NodeInfoEntry) SetGroup(value string) { + if value == "" { + return + } + self.group = value +} + +func (self *NodeInfoEntry) SetProfile(value string) { + if value == "" { + return + } + self.profile = value +} + func (self *NodeInfoEntry) Set(value string) { if value == "" { return diff --git a/internal/pkg/node/modifiers.go b/internal/pkg/node/modifiers.go index 014a9dca..3a07df51 100644 --- a/internal/pkg/node/modifiers.go +++ b/internal/pkg/node/modifiers.go @@ -49,8 +49,8 @@ func (self *nodeYaml) DelNode(groupID string, nodeID string) error { } func(self *nodeYaml) NodeUpdate(node NodeInfo) error { - groupID := node.Gid - nodeID := node.Id + groupID := node.Gid.Get() + nodeID := node.Id.Get() if _, ok := self.NodeGroups[groupID]; !ok { return errors.New("Group '" + groupID + "' was not found") @@ -59,7 +59,7 @@ func(self *nodeYaml) NodeUpdate(node NodeInfo) error { return errors.New("Node '" + nodeID + "' was not found in group '" + groupID + "'") } - self.NodeGroups[groupID].Nodes[nodeID].Hostname = node.HostName + self.NodeGroups[groupID].Nodes[nodeID].Hostname = node.HostName.GetReal() self.NodeGroups[groupID].Nodes[nodeID].Vnfs = node.Vnfs.GetReal() self.NodeGroups[groupID].Nodes[nodeID].DomainName = node.DomainName.GetReal() self.NodeGroups[groupID].Nodes[nodeID].Ipxe = node.Ipxe.GetReal() From 942dd77323303475eac3e9af55e37c1545077eee Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Thu, 26 Nov 2020 19:16:13 -0800 Subject: [PATCH 06/32] Updates to kernel for new nodeDB updates --- internal/pkg/kernel/kernel.go | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/internal/pkg/kernel/kernel.go b/internal/pkg/kernel/kernel.go index b4c0c70b..9f451e42 100644 --- a/internal/pkg/kernel/kernel.go +++ b/internal/pkg/kernel/kernel.go @@ -32,29 +32,20 @@ func Build(kernelVersion string) error { } if _, err := os.Stat(kernelImage); err == nil { - if util.PathIsNewer(kernelImage, kernelDestination) { - wwlog.Printf(wwlog.INFO, "%-45s: Skipping, kernel is current\n", "vmlinuz-"+kernelVersion) - } else { - err := util.CopyFile(kernelImage, kernelDestination) - if err != nil { - return err - } - wwlog.Printf(wwlog.INFO, "%-45s: Done\n", "vmlinuz-"+kernelVersion) + err := util.CopyFile(kernelImage, kernelDestination) + if err != nil { + return err } + wwlog.Printf(wwlog.INFO, "%-45s: Done\n", "vmlinuz-"+kernelVersion) } if _, err := os.Stat(kernelDrivers); err == nil { - if util.PathIsNewer(kernelDrivers, driversDestination) { - wwlog.Printf(wwlog.INFO, "%-45s: Skipping, drivers are current\n", "kmods-"+kernelVersion+".img") - - } else { - cmd := fmt.Sprintf("cd /; find .%s | cpio --quiet -o -H newc -F \"%s\"", kernelDrivers, driversDestination) - err := exec.Command("/bin/sh", "-c", cmd).Run() - if err != nil { - return err - } - wwlog.Printf(wwlog.INFO, "%-45s: Done\n", "kmods-"+kernelVersion+".img") + cmd := fmt.Sprintf("cd /; find .%s | cpio --quiet -o -H newc -F \"%s\"", kernelDrivers, driversDestination) + err := exec.Command("/bin/sh", "-c", cmd).Run() + if err != nil { + return err } + wwlog.Printf(wwlog.INFO, "%-45s: Done\n", "kmods-"+kernelVersion+".img") } return nil From dba9de2c8b13499dd533cabdc7942a0b2baa1c8f Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Thu, 26 Nov 2020 19:16:55 -0800 Subject: [PATCH 07/32] Updates to overlay for NodeDB updates --- internal/pkg/overlay/funcmap.go | 7 +- internal/pkg/overlay/overlay.go | 365 ++++++++++++++++++-------------- 2 files changed, 205 insertions(+), 167 deletions(-) diff --git a/internal/pkg/overlay/funcmap.go b/internal/pkg/overlay/funcmap.go index 0ed1c5cd..572fcef3 100644 --- a/internal/pkg/overlay/funcmap.go +++ b/internal/pkg/overlay/funcmap.go @@ -21,15 +21,16 @@ func templateFileInclude(path string) string { 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 { + if vnfsname == "" { + wwlog.Printf(wwlog.WARN, "VNFS not set for template: %s\n", filepath) return "" } + v, _ := vnfs.Load(vnfsname) vnfsDir := v.Chroot if util.IsDir(vnfsDir) == false { - wwlog.Printf(wwlog.WARN, "Template requesting file from non-imported VNFS: %s (%s)\n", vnfsname, filepath) + wwlog.Printf(wwlog.WARN, "Template requires VNFS (%s) to be imported: %s\n", vnfsname, filepath) return "" } wwlog.Printf(wwlog.DEBUG, "IncludeVnfs file from: %s/%s\n", vnfsDir, filepath) diff --git a/internal/pkg/overlay/overlay.go b/internal/pkg/overlay/overlay.go index e7dee1a7..82e6ab73 100644 --- a/internal/pkg/overlay/overlay.go +++ b/internal/pkg/overlay/overlay.go @@ -1,209 +1,246 @@ package overlay import ( - "bytes" "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" "io/ioutil" "os" "os/exec" "path" + "path/filepath" + "regexp" + "strings" "text/template" ) +type TemplateStruct struct { + Fqdn string + Hostname string + Groupname string + Vnfs string + Netdev map[string]*node.NetDevs +} -func OverlayBuild(nodeList []node.NodeInfo, overlayType string) error { +func BuildSystemOverlay(nodeList []node.NodeInfo) error { + return buildOverlay(nodeList, "system") +} + +func BuildRuntimeOverlay(nodeList []node.NodeInfo) error { + return buildOverlay(nodeList, "runtime") +} + +func FindSystemOverlays() ([]string, error) { + return findAllOverlays("system") +} + +func FindRuntimeOverlays() ([]string, error) { + return findAllOverlays("system") +} + +func SystemOverlayInit(name string) error { + return overlayInit(name, "system") +} + +func RuntimeOverlayInit(name string) error { + return overlayInit(name, "runtime") +} + + + + +func findAllOverlays(overlayType string) ([]string, error) { + config := config.New() + var ret []string + var files []os.FileInfo + var err error + + if overlayType == "system" { + wwlog.Printf(wwlog.DEBUG, "Looking for system overlays...") + files, err = ioutil.ReadDir(config.SystemOverlayDir()) + } else if overlayType == "runtime" { + wwlog.Printf(wwlog.DEBUG, "Looking for runtime overlays...") + files, err = ioutil.ReadDir(config.RuntimeOverlayDir()) + } else { + wwlog.Printf(wwlog.ERROR, "overlayType requested is not supported: %s\n", overlayType) + os.Exit(1) + } + + if err != nil { + return ret, err + } + + for _, file := range files { + wwlog.Printf(wwlog.DEBUG, "Evaluating overlay source: %s\n", file.Name()) + if file.IsDir() == true { + ret = append(ret, file.Name()) + } + } + + return ret, nil +} + + +func overlayInit(name string, overlayType string) error { + var path string config := config.New() - for _, n := range nodeList { - wwlog.Printf(wwlog.DEBUG, "Processing overlay for node: %s\n", n.Fqdn) + if overlayType == "system" { + wwlog.Printf(wwlog.DEBUG, "Looking for system overlays...") + path = config.SystemOverlaySource(name) + } else if overlayType == "runtime" { + wwlog.Printf(wwlog.DEBUG, "Looking for runtime overlays...") + path = config.RuntimeOverlaySource(name) + } else { + wwlog.Printf(wwlog.ERROR, "overlayType requested is not supported: %s\n", overlayType) + os.Exit(1) + } - if util.IsDir(config.VnfsImage(vnfs.CleanName(n.Vnfs))) == false { - wwlog.Printf(wwlog.WARN, "'%s', VNFS not built: %s\n", n.Fqdn, n.Vnfs) -// continue - } + if util.IsDir(path) == true { + return errors.New("Overlay already exists: "+name) + } - var files []node.OverlayEntry + err := os.MkdirAll(path, 0755) - tmpDir, err := ioutil.TempDir(os.TempDir(), ".wwctl-runtime-overlay-") - if err != nil { - continue - } + return err +} - 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 + + + + + +func buildOverlay(nodeList []node.NodeInfo, overlayType string) error { + config := config.New() + + for _, node := range nodeList { + var t TemplateStruct + var OverlayDir string + var OverlayFile string + + if overlayType == "runtime" { + OverlayDir = config.RuntimeOverlaySource(node.RuntimeOverlay.Get()) + OverlayFile = config.RuntimeOverlayImage(node.Fqdn.Get()) + } else if overlayType == "system" { + OverlayDir = config.SystemOverlaySource(node.RuntimeOverlay.Get()) + OverlayFile = config.SystemOverlayImage(node.Fqdn.Get()) } 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) + wwlog.Printf(wwlog.DEBUG, "Processing overlay for node: %s\n", node.Fqdn.Get()) - 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) - } + t.Fqdn = node.Fqdn.Get() + t.Hostname = node.HostName.Get() + t.Groupname = node.GroupName.Get() + t.Vnfs = node.Vnfs.Get() + t.Netdev = node.NetDevs + if overlayType == "runtime" && node.RuntimeOverlay.Defined() == false { + wwlog.Printf(wwlog.WARN, "Undefined runtime overlay, skipping node: %s\n", node.Fqdn.Get()) + } + if overlayType == "system" && node.SystemOverlay.Defined() == false { + wwlog.Printf(wwlog.WARN, "Undefined system overlay, skipping node: %s\n", node.Fqdn.Get()) } - 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) + wwlog.Printf(wwlog.DEBUG, "Checking to see if overlay directory exists: %s\n", OverlayDir) + if util.IsDir(OverlayDir) == false { + wwlog.Printf(wwlog.WARN, "%-35s: Skipped (runtime overlay template not found)\n", node.Fqdn.Get()) continue } + wwlog.Printf(wwlog.DEBUG, "Creating parent directory for OverlayFile: %s\n", path.Dir(OverlayFile)) + err := os.MkdirAll(path.Dir(OverlayFile), 0755) + if err != nil { + return err + } - wwlog.Printf(wwlog.VERBOSE, "Finished generating overlay directory for: %s\n", n.Fqdn) + 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 + } - os.Chmod(tmpDir, 0755) - cmd := fmt.Sprintf("cd \"%s\"; find . | cpio --quiet -o -H newc -F \"%s\"", tmpDir, overlayFile) + wwlog.Printf(wwlog.DEBUG, "Creating temporary directory for overlay files\n") + tmpDir, err := ioutil.TempDir(os.TempDir(), ".wwctl-overlay-") + if err != nil { + return err + } + + wwlog.Printf(wwlog.DEBUG, "Walking the file system: %s\n", OverlayDir) + err = filepath.Walk(".", func(location string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if info.IsDir() { + wwlog.Printf(wwlog.DEBUG, "Found directory: %s\n", location) + + err := os.MkdirAll(path.Join(tmpDir, location), info.Mode()) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + return err + } + + } else if filepath.Ext(location) == ".ww" { + wwlog.Printf(wwlog.DEBUG, "Found template file: %s\n", location) + + destFile := strings.TrimSuffix(location, ".ww") + + tmpl, err := template.New(path.Base(location)).Funcs(template.FuncMap{ + "Include": templateFileInclude, + "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, t) + 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.Get()) + + cmd := fmt.Sprintf("cd \"%s\"; find . | cpio --quiet -o -H newc -F \"%s\"", tmpDir, OverlayFile) wwlog.Printf(wwlog.DEBUG, "RUNNING: %s\n", cmd) err = exec.Command("/bin/sh", "-c", cmd).Run() if err != nil { wwlog.Printf(wwlog.ERROR, "Could not generate runtime image overlay: %s\n", err) - os.RemoveAll(tmpDir) continue } - wwlog.Printf(wwlog.INFO, "%-35s: Done\n", n.Fqdn) + wwlog.Printf(wwlog.INFO, "%-35s: Done\n", node.Fqdn.Get()) wwlog.Printf(wwlog.DEBUG, "Removing temporary directory: %s\n", tmpDir) os.RemoveAll(tmpDir) From 082ab6e5f7707a18f965d71423075fbf9aacd4e3 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Thu, 26 Nov 2020 19:17:09 -0800 Subject: [PATCH 08/32] Updates to Vnfs for nodeDB updates --- internal/pkg/vnfs/vnfs.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/internal/pkg/vnfs/vnfs.go b/internal/pkg/vnfs/vnfs.go index 4c428a4f..bdf8c248 100644 --- a/internal/pkg/vnfs/vnfs.go +++ b/internal/pkg/vnfs/vnfs.go @@ -23,12 +23,18 @@ type VnfsObject struct { func Load (name string) (VnfsObject, error) { config := config.New() var ret VnfsObject + + if name == "" { + wwlog.Printf(wwlog.DEBUG, "Called vnfs.Load() without a name, returning error\n") + return ret, errors.New("Called vnfs.Load() without a VNFS name") + } + pathFriendlyName := CleanName(name) configFile := path.Join(config.VnfsImageDir(pathFriendlyName), "config.yaml") if util.IsFile(configFile) == false { - return ret, errors.New("No Configuration for VNFS name: " + configFile) + return ret, errors.New("VNFS has not been imported: " + name) } data, err := ioutil.ReadFile(configFile) @@ -64,6 +70,11 @@ func New(source string) (VnfsObject, error) { var ret VnfsObject config := config.New() + if source == "" { + wwlog.Printf(wwlog.DEBUG, "Called vnfs.Load() without a name, returning error\n") + return ret, errors.New("Called vnfs.Load() without a VNFS name") + } + pathFriendlyName := CleanName(source) if strings.HasPrefix(source, "/") == true { From 2e11c2156697a6702ff837f3f4b406fcfe5782e3 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Thu, 26 Nov 2020 19:17:19 -0800 Subject: [PATCH 09/32] Additional functions and capabilities in util pkg --- internal/pkg/util/util.go | 40 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/internal/pkg/util/util.go b/internal/pkg/util/util.go index 34b272e6..236109f1 100644 --- a/internal/pkg/util/util.go +++ b/internal/pkg/util/util.go @@ -92,6 +92,9 @@ func CopyFile(source string, dest string) error { func IsDir(path string) (bool) { + if path == "" { + return false + } if stat, err := os.Stat(path); err == nil && stat.IsDir() { return true } @@ -99,6 +102,10 @@ func IsDir(path string) (bool) { } func IsFile(path string) (bool) { + if path == "" { + return false + } + if _, err := os.Stat(path); err == nil { return true } @@ -184,3 +191,36 @@ func ShaSumFile(file string) (string, error) { return fmt.Sprintf("%x", h.Sum(nil)), nil } + + +func SliceRemoveElement(array []string, remove string) []string { + var ret []string + + // Linear time, maintains order + for _, r := range array { + if r != remove { + ret = append(ret, r) + } + } + + return ret +} + +func SliceAddUniqueElement(array []string, add string) []string { + var ret []string + var found bool + + //Linear time, appends + for _, r := range array { + ret = append(ret, r) + if r == add { + found = true + } + } + + if found == false { + ret = append(ret, add) + } + + return ret +} \ No newline at end of file From 4ba0cb7bcde591c8a0da68539a45eb6833c734dd Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Thu, 26 Nov 2020 19:18:13 -0800 Subject: [PATCH 10/32] Updates to vnfs command for NodeDB updates --- internal/app/wwctl/vnfs/build/main.go | 8 ++++++-- internal/app/wwctl/vnfs/list/main.go | 2 +- internal/app/wwctl/vnfs/list/root.go | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/internal/app/wwctl/vnfs/build/main.go b/internal/app/wwctl/vnfs/build/main.go index 8fbd1539..4b48fc09 100644 --- a/internal/app/wwctl/vnfs/build/main.go +++ b/internal/app/wwctl/vnfs/build/main.go @@ -28,7 +28,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } for _, node := range nodes { - set[node.Vnfs.String()] ++ + if node.Vnfs.Defined() == true { + set[node.Vnfs.Get()] ++ + } } } else if BuildAll == true { @@ -40,7 +42,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } for _, node := range nodes { - set[node.Vnfs.String()] ++ + if node.Vnfs.Defined() == true { + set[node.Vnfs.Get()] ++ + } } } else if len(args) == 1 { diff --git a/internal/app/wwctl/vnfs/list/main.go b/internal/app/wwctl/vnfs/list/main.go index 2fa015a5..85bf6296 100644 --- a/internal/app/wwctl/vnfs/list/main.go +++ b/internal/app/wwctl/vnfs/list/main.go @@ -20,7 +20,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { nodemap := make(map[string]int) for _, n := range nodes { - nodemap[n.Vnfs.String()] ++ + nodemap[n.Vnfs.Get()] ++ } images, _ := ioutil.ReadDir(config.VnfsImageParentDir()) diff --git a/internal/app/wwctl/vnfs/list/root.go b/internal/app/wwctl/vnfs/list/root.go index 42ce77dc..58662f4d 100644 --- a/internal/app/wwctl/vnfs/list/root.go +++ b/internal/app/wwctl/vnfs/list/root.go @@ -14,8 +14,8 @@ var ( ) func init() { - baseCmd.PersistentFlags().BoolVarP(&SystemOverlay, "system", "s", false, "Show System Overlays as well") - baseCmd.PersistentFlags().BoolVarP(&BuildAll, "all", "a", false, "Build all overlays (runtime and system)") + //baseCmd.PersistentFlags().BoolVarP(&SystemOverlay, "system", "s", false, "Show System Overlays as well") + //baseCmd.PersistentFlags().BoolVarP(&BuildAll, "all", "a", false, "Build all overlays (runtime and system)") } From 3caeac0c9d3af56aa40888ab96998b7561e7684e Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Thu, 26 Nov 2020 19:18:28 -0800 Subject: [PATCH 11/32] Updates to overlay cli for NodeDB updates --- internal/app/wwctl/overlay/build/main.go | 4 ++-- internal/app/wwctl/overlay/chmod/main.go | 4 ++-- internal/app/wwctl/overlay/create/main.go | 4 ++-- internal/app/wwctl/overlay/delete/main.go | 4 ++-- internal/app/wwctl/overlay/edit/main.go | 4 ++-- internal/app/wwctl/overlay/imprt/main.go | 4 ++-- internal/app/wwctl/overlay/list/main.go | 12 ++++++------ internal/app/wwctl/overlay/mkdir/main.go | 4 ++-- internal/app/wwctl/overlay/root.go | 2 -- 9 files changed, 20 insertions(+), 22 deletions(-) diff --git a/internal/app/wwctl/overlay/build/main.go b/internal/app/wwctl/overlay/build/main.go index 24ed4561..bf8a3b4f 100644 --- a/internal/app/wwctl/overlay/build/main.go +++ b/internal/app/wwctl/overlay/build/main.go @@ -43,7 +43,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { wwlog.Printf(wwlog.DEBUG, "Checking on system overlay update\n") if SystemOverlay == true || BuildAll == true { wwlog.Printf(wwlog.INFO, "Updating System Overlays...\n") - err := overlay.SystemBuild(updateNodes, true) + err := overlay.BuildSystemOverlay(updateNodes) if err != nil { wwlog.Printf(wwlog.WARN, "Some system overlays failed to be generated: %s\n", err) } @@ -52,7 +52,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { wwlog.Printf(wwlog.DEBUG, "Checking on system overlay update\n") if SystemOverlay == false || BuildAll == true { wwlog.Printf(wwlog.INFO, "Updating Runtime Overlays...\n") - err := overlay.RuntimeBuild(updateNodes, true) + err := overlay.BuildRuntimeOverlay(updateNodes) if err != nil { wwlog.Printf(wwlog.WARN, "Some runtime overlays failed to be generated\n") } diff --git a/internal/app/wwctl/overlay/chmod/main.go b/internal/app/wwctl/overlay/chmod/main.go index bd8352ba..a13b480b 100644 --- a/internal/app/wwctl/overlay/chmod/main.go +++ b/internal/app/wwctl/overlay/chmod/main.go @@ -73,10 +73,10 @@ func CobraRunE(cmd *cobra.Command, args []string) error { if SystemOverlay == true { wwlog.Printf(wwlog.INFO, "Updating System Overlays...\n") - return overlay.SystemBuild(updateNodes, true) + return overlay.BuildSystemOverlay(updateNodes) } else { wwlog.Printf(wwlog.INFO, "Updating Runtime Overlays...\n") - return overlay.RuntimeBuild(updateNodes, true) + return overlay.BuildRuntimeOverlay(updateNodes) } } diff --git a/internal/app/wwctl/overlay/create/main.go b/internal/app/wwctl/overlay/create/main.go index 237341cb..c4a62062 100644 --- a/internal/app/wwctl/overlay/create/main.go +++ b/internal/app/wwctl/overlay/create/main.go @@ -57,10 +57,10 @@ func CobraRunE(cmd *cobra.Command, args []string) error { if SystemOverlay == true { wwlog.Printf(wwlog.INFO, "Updating System Overlays...\n") - return overlay.SystemBuild(updateNodes, true) + return overlay.BuildSystemOverlay(updateNodes) } else { wwlog.Printf(wwlog.INFO, "Updating Runtime Overlays...\n") - return overlay.RuntimeBuild(updateNodes, true) + return overlay.BuildRuntimeOverlay(updateNodes) } } diff --git a/internal/app/wwctl/overlay/delete/main.go b/internal/app/wwctl/overlay/delete/main.go index a59e8c61..a8199efb 100644 --- a/internal/app/wwctl/overlay/delete/main.go +++ b/internal/app/wwctl/overlay/delete/main.go @@ -119,10 +119,10 @@ func CobraRunE(cmd *cobra.Command, args []string) error { if SystemOverlay == true { wwlog.Printf(wwlog.INFO, "Updating System Overlays...\n") - return overlay.SystemBuild(updateNodes, true) + return overlay.BuildSystemOverlay(updateNodes) } else { wwlog.Printf(wwlog.INFO, "Updating Runtime Overlays...\n") - return overlay.RuntimeBuild(updateNodes, true) + return overlay.BuildRuntimeOverlay(updateNodes) } } diff --git a/internal/app/wwctl/overlay/edit/main.go b/internal/app/wwctl/overlay/edit/main.go index cebe1021..836c96fe 100644 --- a/internal/app/wwctl/overlay/edit/main.go +++ b/internal/app/wwctl/overlay/edit/main.go @@ -117,10 +117,10 @@ func CobraRunE(cmd *cobra.Command, args []string) error { if SystemOverlay == true { wwlog.Printf(wwlog.INFO, "Updating System Overlays...\n") - return overlay.SystemBuild(updateNodes, true) + return overlay.BuildSystemOverlay(updateNodes) } else { wwlog.Printf(wwlog.INFO, "Updating Runtime Overlays...\n") - return overlay.RuntimeBuild(updateNodes, true) + return overlay.BuildRuntimeOverlay(updateNodes) } } diff --git a/internal/app/wwctl/overlay/imprt/main.go b/internal/app/wwctl/overlay/imprt/main.go index 8374736f..9b1228ee 100644 --- a/internal/app/wwctl/overlay/imprt/main.go +++ b/internal/app/wwctl/overlay/imprt/main.go @@ -69,10 +69,10 @@ func CobraRunE(cmd *cobra.Command, args []string) error { if SystemOverlay == true { wwlog.Printf(wwlog.INFO, "Updating System Overlays...\n") - return overlay.SystemBuild(updateNodes, true) + return overlay.BuildSystemOverlay(updateNodes) } else { wwlog.Printf(wwlog.INFO, "Updating Runtime Overlays...\n") - return overlay.RuntimeBuild(updateNodes, true) + return overlay.BuildRuntimeOverlay(updateNodes) } } diff --git a/internal/app/wwctl/overlay/list/main.go b/internal/app/wwctl/overlay/list/main.go index 0266ac14..c5a7bfdc 100644 --- a/internal/app/wwctl/overlay/list/main.go +++ b/internal/app/wwctl/overlay/list/main.go @@ -31,14 +31,14 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } else { fmt.Printf("%-10s %5s %-5s %-18s %s\n", "PERM MODE", "UID", "GID", "SYSTEM-OVERLAY", "FILE PATH") } - o, err = overlay.FindAllSystemOverlays() + o, err = overlay.FindSystemOverlays() } else { if ListLong == false { fmt.Printf("%-30s %-12s %-12s\n", "RUNTIME OVERLAY NAME", "NODES", "FILES/DIRS") } else { fmt.Printf("%-10s %5s %-5s %-18s %s\n", "PERM MODE", "UID", "GID", "RUNTIME-OVERLAY", "FILE PATH") } - o, err = overlay.FindAllRuntimeOverlays() + o, err = overlay.FindRuntimeOverlays() } if err != nil { wwlog.Printf(wwlog.ERROR, "Could not get system overlays: %s\n", err) @@ -53,12 +53,12 @@ func CobraRunE(cmd *cobra.Command, args []string) error { for _, node := range nodeList { if SystemOverlay == true { - if node.SystemOverlay.String() != "" { - set[node.SystemOverlay.String()] ++ + if node.SystemOverlay.Get() != "" { + set[node.SystemOverlay.Get()] ++ } } else { - if node.RuntimeOverlay.String() != "" { - set[node.RuntimeOverlay.String()] ++ + if node.RuntimeOverlay.Get() != "" { + set[node.RuntimeOverlay.Get()] ++ } } } diff --git a/internal/app/wwctl/overlay/mkdir/main.go b/internal/app/wwctl/overlay/mkdir/main.go index ef38ae0f..3cb77f6d 100644 --- a/internal/app/wwctl/overlay/mkdir/main.go +++ b/internal/app/wwctl/overlay/mkdir/main.go @@ -66,10 +66,10 @@ func CobraRunE(cmd *cobra.Command, args []string) error { if SystemOverlay == true { wwlog.Printf(wwlog.INFO, "Updating System Overlays...\n") - return overlay.SystemBuild(updateNodes, true) + return overlay.BuildSystemOverlay(updateNodes) } else { wwlog.Printf(wwlog.INFO, "Updating Runtime Overlays...\n") - return overlay.RuntimeBuild(updateNodes, true) + return overlay.BuildRuntimeOverlay(updateNodes) } } diff --git a/internal/app/wwctl/overlay/root.go b/internal/app/wwctl/overlay/root.go index 7223f4ad..87e3abb5 100644 --- a/internal/app/wwctl/overlay/root.go +++ b/internal/app/wwctl/overlay/root.go @@ -10,7 +10,6 @@ import ( "github.com/hpcng/warewulf/internal/app/wwctl/overlay/list" "github.com/hpcng/warewulf/internal/app/wwctl/overlay/mkdir" "github.com/hpcng/warewulf/internal/app/wwctl/overlay/show" - "github.com/spf13/cobra" ) @@ -35,7 +34,6 @@ func init() { baseCmd.AddCommand(build.GetCommand()) baseCmd.AddCommand(imprt.GetCommand()) baseCmd.AddCommand(chmod.GetCommand()) - } // GetRootCommand returns the root cobra.Command for the application. From 1a332e42a365fdbd00d9598fc215dc57c3546f9d Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Thu, 26 Nov 2020 19:19:16 -0800 Subject: [PATCH 12/32] Updates to kernel cli for NodeDB --- internal/app/wwctl/kernel/build/main.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/internal/app/wwctl/kernel/build/main.go b/internal/app/wwctl/kernel/build/main.go index ae9e7844..9d40d23f 100644 --- a/internal/app/wwctl/kernel/build/main.go +++ b/internal/app/wwctl/kernel/build/main.go @@ -27,7 +27,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } for _, node := range nodes { - set[node.KernelVersion.String()] ++ + if node.KernelVersion.Defined() == true { + set[node.KernelVersion.Get()] ++ + } } } else if BuildAll == true { @@ -39,7 +41,10 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } for _, node := range nodes { - set[node.KernelVersion.String()] ++ + wwlog.Printf(wwlog.DEBUG, "evaluating node/kernel: %s/%s\n", node.Fqdn.Get(), node.KernelVersion.String()) + if node.KernelVersion.Defined() == true { + set[node.KernelVersion.Get()] ++ + } } } else if len(args) == 1 { @@ -50,6 +55,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } for k := range set { + wwlog.Printf(wwlog.INFO, "Building kernel: %s\n", k) err := kernel.Build(k) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) From ef64ff280c96dc30f30e7b801f24d1a93b436fda Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Thu, 26 Nov 2020 19:19:36 -0800 Subject: [PATCH 13/32] Disabling the commands that still need updating for nodeDB updates --- internal/app/wwctl/root.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/internal/app/wwctl/root.go b/internal/app/wwctl/root.go index cd1b64c3..973e5dfa 100644 --- a/internal/app/wwctl/root.go +++ b/internal/app/wwctl/root.go @@ -1,12 +1,10 @@ package wwctl import ( - "github.com/hpcng/warewulf/internal/app/wwctl/build" - "github.com/hpcng/warewulf/internal/app/wwctl/group" "github.com/hpcng/warewulf/internal/app/wwctl/kernel" - "github.com/hpcng/warewulf/internal/app/wwctl/node" "github.com/hpcng/warewulf/internal/app/wwctl/overlay" "github.com/hpcng/warewulf/internal/app/wwctl/vnfs" + "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" ) @@ -26,12 +24,12 @@ func init() { rootCmd.PersistentFlags().BoolVarP(&verboseArg, "verbose", "v", false, "Run with increased verbosity.") rootCmd.PersistentFlags().BoolVarP(&debugArg, "debug", "d", false, "Run with debugging messages enabled.") - rootCmd.AddCommand(build.GetCommand()) rootCmd.AddCommand(overlay.GetCommand()) + //rootCmd.AddCommand(build.GetCommand()) rootCmd.AddCommand(vnfs.GetCommand()) - rootCmd.AddCommand(node.GetCommand()) + //rootCmd.AddCommand(node.GetCommand()) rootCmd.AddCommand(kernel.GetCommand()) - rootCmd.AddCommand(group.GetCommand()) + //rootCmd.AddCommand(group.GetCommand()) } From 1b7dbefd4f9240919ea77fb25ae9634c7bc3320e Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Thu, 26 Nov 2020 19:21:09 -0800 Subject: [PATCH 14/32] Configuration updates for NodeDB --- etc/nodes.conf | 45 +++++++++++++++------------------------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/etc/nodes.conf b/etc/nodes.conf index 586c9ce5..8bce1c10 100644 --- a/etc/nodes.conf +++ b/etc/nodes.conf @@ -1,52 +1,38 @@ -profiles: +nodeprofiles: default: - vnfs: docker://warewulf/centos-8 + comment: "" + vnfs: "" 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 - + comment: "" + vnfs: docker://warewulf/centos-7 nodegroups: default: comment: This is the default group - domain suffix: default + domain name: cluster01 + profiles: + - default nodes: n0000: hostname: n0000 - profiles: [default, test] + profiles: + - test netdevs: eth0: + type: ethernet hwaddr: 00:0c:29:23:8b:48 ipaddr: 192.168.1.100 netmask: 255.255.255.0 gateway: 192.168.1.1 - type: ethernet ib0: + type: infiniband hwaddr: aa:bb:cc:dd:ee:a0 ipaddr: 192.168.10.100 netmask: 255.255.255.0 - type: infiniband n0001: hostname: n0001 ipmi ipaddr: x.x.x.x - kernel version: BOOO netdevs: eth0: hwaddr: aa:bb:cc:dd:ee:b0 @@ -59,13 +45,12 @@ nodegroups: netmask: 255.255.255.0 group_1: comment: This is the group 1 - vnfs: /var/chroots/centos-7 - runtime overlay: default - domain suffix: group1 + domain name: group1 + profiles: + - default nodes: n0000: hostname: localtest - system overlay: test netdevs: eth0: hwaddr: aa:bb:cc:dd:ee:c0 From 5368998c3b0d6c96e220bb4df83c6b1db4759b77 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Thu, 26 Nov 2020 19:21:34 -0800 Subject: [PATCH 15/32] Remove extra slash in default ipxe template --- etc/ipxe/default.ipxe | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/ipxe/default.ipxe b/etc/ipxe/default.ipxe index e2aac7a9..2df1f61c 100644 --- a/etc/ipxe/default.ipxe +++ b/etc/ipxe/default.ipxe @@ -6,7 +6,7 @@ echo Warewulf v4 now booting: {{.Fqdn}} echo echo -set base http://{{.Ipaddr}}:{{.Port}}/ +set base http://{{.Ipaddr}}:{{.Port}} kernel ${base}/kernel/{{.Hwaddr}} {{.Kernelargs}} || reboot initrd ${base}/vnfs/{{.Hwaddr}} || reboot From f092c3abf37230c0006b2fc8f494684b68a4b843 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Thu, 26 Nov 2020 20:36:44 -0800 Subject: [PATCH 16/32] Fixups for Groups --- internal/app/wwctl/group/list/main.go | 4 +- internal/app/wwctl/group/set/main.go | 188 +++----------------------- 2 files changed, 18 insertions(+), 174 deletions(-) diff --git a/internal/app/wwctl/group/list/main.go b/internal/app/wwctl/group/list/main.go index 9abbc31e..97a5370b 100644 --- a/internal/app/wwctl/group/list/main.go +++ b/internal/app/wwctl/group/list/main.go @@ -33,9 +33,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } } } else { - fmt.Printf("%-22s %-16s %-30s %-30s %-16s\n", "GROUP NAME", "DOMAINNAME", "KERNEL VERSION", "VNFS IMAGE", "RUNTIME OVERLAY") + fmt.Printf("%-22s %-16s %s\n", "GROUP NAME", "DOMAINNAME", "PROFILES") for _, g := range groups { - fmt.Printf("%-22s %-16s %-30s %-30s %-16s\n", g.GroupName.String(), g.DomainName.String(), g.KernelVersion.String(), g.Vnfs.String(), g.RuntimeOverlay.String()) + fmt.Printf("%-22s %-16s %s\n", g.Id, g.DomainName, g.Profiles) } } diff --git a/internal/app/wwctl/group/set/main.go b/internal/app/wwctl/group/set/main.go index e572e600..467e077f 100644 --- a/internal/app/wwctl/group/set/main.go +++ b/internal/app/wwctl/group/set/main.go @@ -46,7 +46,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { for _, a := range args { for _, g := range tmp { - if g.Id.String() == a { + if g.Id == a { groups = append(groups, g) } } @@ -58,183 +58,27 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } for _, g := range groups { - if SetVnfs != "" { - wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting vnfs to: %s\n", g.Id, SetVnfs) - err := nodeDB.SetGroupVal(g.Id.String(), "vnfs", SetVnfs) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(1) - } - - if SetClearNodes == true { - nodes, err := nodeDB.FindAllNodes() - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(1) - } - for _, n := range nodes { - _ = nodeDB.SetNodeVal(g.Id.String(), n.Id.String(), "vnfs", "") - } - } - } - - if SetKernel != "" { - wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting kernel to: %s\n", g.Id, SetVnfs) - err := nodeDB.SetGroupVal(g.Id.String(), "kernel", SetKernel) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(1) - } - - if SetClearNodes == true { - nodes, err := nodeDB.FindAllNodes() - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(1) - } - for _, n := range nodes { - _ = nodeDB.SetNodeVal(g.Id.String(), n.Id.String(), "kernel", "") - } - } - } if SetDomainName != "" { wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting domain name to: %s\n", g.Id, SetDomainName) - err := nodeDB.SetGroupVal(g.Id.String(), "domain", SetDomainName) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(1) - } +// err := nodeDB.SetGroupVal(g.Id.String(), "domain", SetDomainName) +// if err != nil { +// wwlog.Printf(wwlog.ERROR, "%s\n", err) +// os.Exit(1) +// } - if SetClearNodes == true { - nodes, err := nodeDB.FindAllNodes() - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(1) - } - for _, n := range nodes { - _ = nodeDB.SetNodeVal(g.Id.String(), n.Id.String(), "domain", "") - } - } +// if SetClearNodes == true { +// nodes, err := nodeDB.FindAllNodes() +// if err != nil { +// wwlog.Printf(wwlog.ERROR, "%s\n", err) +// os.Exit(1) +// } +// for _, n := range nodes { +// _ = nodeDB.SetNodeVal(g.Id.String(), n.Id.String(), "domain", "") +// } +// } } - if SetIpxe != "" { - wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting iPXE template to: %s\n", g.Id, SetIpxe) - err := nodeDB.SetGroupVal(g.Id.String(), "ipxe", SetIpxe) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(1) - } - - if SetClearNodes == true { - nodes, err := nodeDB.FindAllNodes() - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(1) - } - for _, n := range nodes { - _ = nodeDB.SetNodeVal(g.Id.String(), n.Id.String(), "ipxe", "") - } - } - } - - if SetRuntimeOverlay != "" { - wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting runtime overlay to: %s\n", g.Id, SetRuntimeOverlay) - err := nodeDB.SetGroupVal(g.Id.String(), "runtimeoverlay", SetRuntimeOverlay) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(1) - } - if SetClearNodes == true { - nodes, err := nodeDB.FindAllNodes() - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(1) - } - for _, n := range nodes { - _ = nodeDB.SetNodeVal(g.Id.String(), n.Id.String(), "runtimeoverlay", "") - } - } - } - - if SetSystemOverlay != "" { - wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting system overlay to: %s\n", g.Id, SetSystemOverlay) - err := nodeDB.SetGroupVal(g.Id.String(), "systemoverlay", SetSystemOverlay) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(1) - } - if SetClearNodes == true { - nodes, err := nodeDB.FindAllNodes() - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(1) - } - for _, n := range nodes { - _ = nodeDB.SetNodeVal(g.Id.String(), n.Id.String(), "systemoverlay", "") - } - } - } - if SetIpmiIpaddr != "" { - wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting IPMI IP address to: %s\n", g.Id, SetIpmiIpaddr) - err := nodeDB.SetGroupVal(g.Id.String(), "ipmiipaddr", SetIpmiIpaddr) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(1) - } - if SetClearNodes == true { - nodes, err := nodeDB.FindAllNodes() - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(1) - } - for _, n := range nodes { - _ = nodeDB.SetNodeVal(g.Id.String(), n.Id.String(), "ipmiipaddr", "") - } - } - } - if SetIpmiUsername != "" { - wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting IPMI IP username to: %s\n", g.Id, SetIpmiUsername) - err := nodeDB.SetGroupVal(g.Id.String(), "ipmiusername", SetIpmiUsername) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(1) - } - if SetClearNodes == true { - nodes, err := nodeDB.FindAllNodes() - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(1) - } - for _, n := range nodes { - _ = nodeDB.SetNodeVal(g.Id.String(), n.Id.String(), "ipmiusername", "") - } - } - } - if SetIpmiPassword != "" { - wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting IPMI IP password to: %s\n", g.Id, SetIpmiPassword) - err := nodeDB.SetGroupVal(g.Id.String(), "ipmipassword", SetIpmiPassword) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(1) - } - if SetClearNodes == true { - nodes, err := nodeDB.FindAllNodes() - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(1) - } - for _, n := range nodes { - _ = nodeDB.SetNodeVal(g.Id.String(), n.Id.String(), "ipmipassword", "") - } - } - } - - - - - - } if len(groups) > 0 { From 2812a70fd0279727baf1f120c450509c99cca11f Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Thu, 26 Nov 2020 20:36:56 -0800 Subject: [PATCH 17/32] Fixup for node command --- internal/app/wwctl/node/list/main.go | 14 ++--- internal/app/wwctl/node/set/main.go | 86 ++++++++++++++++++++++------ 2 files changed, 77 insertions(+), 23 deletions(-) diff --git a/internal/app/wwctl/node/list/main.go b/internal/app/wwctl/node/list/main.go index a2cfff35..db8564c0 100644 --- a/internal/app/wwctl/node/list/main.go +++ b/internal/app/wwctl/node/list/main.go @@ -40,7 +40,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { fmt.Printf("################################################################################\n") for i := 0; i< v.NumField(); i++ { //TODO: Fix for NetDevs and Interface should print Fprint() method - fmt.Printf("%-25s %s = %v\n", node.Fqdn.String(), typeOfS.Field(i).Name, v.Field(i).Interface()) + fmt.Printf("%-25s %s = %#v\n", node.Fqdn.Get(), typeOfS.Field(i).Name, v.Field(i).Interface()) } } @@ -51,10 +51,10 @@ func CobraRunE(cmd *cobra.Command, args []string) error { for _, node := range nodes { if len(node.NetDevs) > 0 { for name, dev := range node.NetDevs { - fmt.Printf("%-22s %-6s %-18s %-15s %-15s\n", node.Fqdn.String(), name, dev.Hwaddr, dev.Ipaddr, dev.Gateway) + fmt.Printf("%-22s %-6s %-18s %-15s %-15s\n", node.Fqdn.Get(), name, dev.Hwaddr, dev.Ipaddr, dev.Gateway) } } else { - fmt.Printf("%-22s %-6s %-18s %-15s %-15s\n", node.Fqdn.String(), "--", "--", "--", "--") + fmt.Printf("%-22s %-6s %-18s %-15s %-15s\n", node.Fqdn.Get(), "--", "--", "--", "--") } } @@ -63,7 +63,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { fmt.Println(strings.Repeat("=", 80)) for _, node := range nodes { - fmt.Printf("%-22s %-16s %-20s %-20s\n", node.Fqdn.String(), node.IpmiIpaddr.Fprint(), node.IpmiUserName.Fprint(), node.IpmiPassword.Fprint()) + fmt.Printf("%-22s %-16s %-20s %-20s\n", node.Fqdn.Get(), node.IpmiIpaddr.Get(), node.IpmiUserName.Get(), node.IpmiPassword.Get()) } } else if ShowLong == true { @@ -71,15 +71,15 @@ func CobraRunE(cmd *cobra.Command, args []string) error { fmt.Println(strings.Repeat("=", 120)) for _, node := range nodes { - 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()) + fmt.Printf("%-22s %-12s %-26s %-35s %s\n", node.Fqdn.Get(), node.GroupName.Get(), node.KernelVersion.Get(), node.Vnfs.Get(), node.SystemOverlay.Get() +"/"+ node.RuntimeOverlay.Get()) } } else { - fmt.Printf("%-22s %-26s %-30s\n", "NODE NAME", "KERNEL VERSION", "VNFS IMAGE") + fmt.Printf("%-22s %s\n", "NODE NAME", "PROFILES") fmt.Println(strings.Repeat("=", 80)) for _, node := range nodes { - fmt.Printf("%-22s %-26s %-30s\n", node.Fqdn.String(), node.KernelVersion.Fprint(), node.Vnfs.Fprint()) + fmt.Printf("%-22s %s\n", node.Fqdn.Get(), append(node.GroupProfiles, node.Profiles...)) } } diff --git a/internal/app/wwctl/node/set/main.go b/internal/app/wwctl/node/set/main.go index 8c76889f..874333bd 100644 --- a/internal/app/wwctl/node/set/main.go +++ b/internal/app/wwctl/node/set/main.go @@ -46,7 +46,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error { wwlog.Printf(wwlog.VERBOSE, "Evaluating node: %s\n", n.Fqdn.String()) if SetVnfs != "" { wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting vnfs to: %s\n", n.Fqdn.String(), SetVnfs) - err := nodeDB.SetNodeVal(n.Gid.String(), n.Id.String(), "vnfs", SetVnfs) + + n.Vnfs.Set(SetVnfs) + err := nodeDB.NodeUpdate(n) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -54,7 +56,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } if SetKernel != "" { wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting kernel to: %s\n", n.Fqdn.String(), SetKernel) - err := nodeDB.SetNodeVal(n.Gid.String(), n.Id.String(), "kernel", SetKernel) + + n.KernelVersion.Set(SetKernel) + err := nodeDB.NodeUpdate(n) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -62,7 +66,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } if SetDomainName != "" { wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting domain name to: %s\n", n.Fqdn, SetDomainName) - err := nodeDB.SetNodeVal(n.Gid.String(), n.Id.String(), "domain", SetDomainName) + + n.DomainName.Set(SetDomainName) + err := nodeDB.NodeUpdate(n) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -70,7 +76,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } if SetIpxe != "" { wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting iPXE template to: %s\n", n.Fqdn, SetIpxe) - err := nodeDB.SetNodeVal(n.Gid.String(), n.Id.String(), "ipxe", SetIpxe) + + n.Ipxe.Set(SetIpxe) + err := nodeDB.NodeUpdate(n) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -78,7 +86,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } if SetRuntimeOverlay != "" { wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting runtime overlay to: %s\n", n.Fqdn, SetRuntimeOverlay) - err := nodeDB.SetNodeVal(n.Gid.String(), n.Id.String(), "runtimeoverlay", SetRuntimeOverlay) + + n.RuntimeOverlay.Set(SetRuntimeOverlay) + err := nodeDB.NodeUpdate(n) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -86,7 +96,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } if SetSystemOverlay != "" { wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting system overlay to: %s\n", n.Fqdn, SetSystemOverlay) - err := nodeDB.SetNodeVal(n.Gid.String(), n.Id.String(), "systemoverlay", SetSystemOverlay) + + n.SystemOverlay.Set(SetSystemOverlay) + err := nodeDB.NodeUpdate(n) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -94,7 +106,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } if SetHostname != "" { wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting hostname to: %s\n", n.Fqdn, SetHostname) - err := nodeDB.SetNodeVal(n.Gid.String(), n.Id.String(), "hostname", SetHostname) + + n.HostName.Set(SetHostname) + err := nodeDB.NodeUpdate(n) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -102,7 +116,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } if SetIpmiIpaddr != "" { wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting IPMI IP address to: %s\n", n.Fqdn, SetIpmiIpaddr) - err := nodeDB.SetNodeVal(n.Gid.String(), n.Id.String(), "ipmiipaddr", SetIpmiIpaddr) + + n.IpmiIpaddr.Set(SetIpmiIpaddr) + err := nodeDB.NodeUpdate(n) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -110,7 +126,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } if SetIpmiUsername != "" { wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting IPMI IP username to: %s\n", n.Fqdn, SetIpmiUsername) - err := nodeDB.SetNodeVal(n.Gid.String(), n.Id.String(), "ipmiusername", SetIpmiUsername) + + n.IpmiUserName.Set(SetIpmiUsername) + err := nodeDB.NodeUpdate(n) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -118,7 +136,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } if SetIpmiPassword != "" { wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting IPMI IP password to: %s\n", n.Fqdn, SetIpmiPassword) - err := nodeDB.SetNodeVal(n.Gid.String(), n.Id.String(), "ipmipassword", SetIpmiPassword) + + n.IpmiPassword.Set(SetIpmiPassword) + err := nodeDB.NodeUpdate(n) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -133,20 +153,33 @@ func CobraRunE(cmd *cobra.Command, args []string) error { os.Exit(1) } wwlog.Printf(wwlog.VERBOSE, "Node: %s, Deleting network device: %s\n", n.Fqdn, SetNetDev) - err := nodeDB.DelNodeNet(n.Gid.String(), n.Id.String(), SetNetDev) + + if _, ok := n.NetDevs[SetNetDev]; !ok { + wwlog.Printf(wwlog.ERROR, "Network Device doesn't exist: %s\n", SetNetDev) + os.Exit(1) + } + + delete(n.NetDevs, SetNetDev) + err := nodeDB.NodeUpdate(n) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) } - } if SetIpaddr != "" { if SetNetDev == "" { wwlog.Printf(wwlog.ERROR, "You must include the '--netdev' option\n") os.Exit(1) } + + if _, ok := n.NetDevs[SetNetDev]; !ok { + wwlog.Printf(wwlog.ERROR, "Network Device doesn't exist: %s\n", SetNetDev) + os.Exit(1) + } wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting Ipaddr to: %s\n", n.Fqdn, SetNetDev, SetIpaddr) - err := nodeDB.SetNodeNet(n.Gid.String(), n.Id.String(), SetNetDev, "ipaddr", SetIpaddr) + + n.NetDevs[SetNetDev].Ipaddr = SetIpaddr + err := nodeDB.NodeUpdate(n) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -157,8 +190,15 @@ func CobraRunE(cmd *cobra.Command, args []string) error { wwlog.Printf(wwlog.ERROR, "You must include the '--netdev' option\n") os.Exit(1) } + + if _, ok := n.NetDevs[SetNetDev]; !ok { + wwlog.Printf(wwlog.ERROR, "Network Device doesn't exist: %s\n", SetNetDev) + os.Exit(1) + } wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting netmask to: %s\n", n.Fqdn, SetNetDev, SetNetmask) - err := nodeDB.SetNodeNet(n.Gid.String(), n.Id.String(), SetNetDev, "netmask", SetNetmask) + + n.NetDevs[SetNetDev].Netmask = SetNetmask + err := nodeDB.NodeUpdate(n) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -169,8 +209,15 @@ func CobraRunE(cmd *cobra.Command, args []string) error { wwlog.Printf(wwlog.ERROR, "You must include the '--netdev' option\n") os.Exit(1) } + + if _, ok := n.NetDevs[SetNetDev]; !ok { + wwlog.Printf(wwlog.ERROR, "Network Device doesn't exist: %s\n", SetNetDev) + os.Exit(1) + } wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting gateway to: %s\n", n.Fqdn, SetNetDev, SetGateway) - err := nodeDB.SetNodeNet(n.Gid.String(), n.Id.String(), SetNetDev, "gateway", SetGateway) + + n.NetDevs[SetNetDev].Gateway = SetGateway + err := nodeDB.NodeUpdate(n) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) @@ -181,8 +228,15 @@ func CobraRunE(cmd *cobra.Command, args []string) error { wwlog.Printf(wwlog.ERROR, "You must include the '--netdev' option\n") os.Exit(1) } + + if _, ok := n.NetDevs[SetNetDev]; !ok { + wwlog.Printf(wwlog.ERROR, "Network Device doesn't exist: %s\n", SetNetDev) + os.Exit(1) + } wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting HW address to: %s\n", n.Fqdn, SetNetDev, SetHwaddr) - err := nodeDB.SetNodeNet(n.Gid.String(), n.Id.String(), SetNetDev, "hwaddr", SetHwaddr) + + n.NetDevs[SetNetDev].Hwaddr = SetHwaddr + err := nodeDB.NodeUpdate(n) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) From 3ab02c3055b24413f663d64df64256bf16c1aa64 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Thu, 26 Nov 2020 20:37:11 -0800 Subject: [PATCH 18/32] Add node and groups back into wwctl command --- internal/app/wwctl/root.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/internal/app/wwctl/root.go b/internal/app/wwctl/root.go index 973e5dfa..3aeb3733 100644 --- a/internal/app/wwctl/root.go +++ b/internal/app/wwctl/root.go @@ -1,7 +1,9 @@ package wwctl import ( + "github.com/hpcng/warewulf/internal/app/wwctl/group" "github.com/hpcng/warewulf/internal/app/wwctl/kernel" + "github.com/hpcng/warewulf/internal/app/wwctl/node" "github.com/hpcng/warewulf/internal/app/wwctl/overlay" "github.com/hpcng/warewulf/internal/app/wwctl/vnfs" @@ -27,9 +29,9 @@ func init() { rootCmd.AddCommand(overlay.GetCommand()) //rootCmd.AddCommand(build.GetCommand()) rootCmd.AddCommand(vnfs.GetCommand()) - //rootCmd.AddCommand(node.GetCommand()) + rootCmd.AddCommand(node.GetCommand()) rootCmd.AddCommand(kernel.GetCommand()) - //rootCmd.AddCommand(group.GetCommand()) + rootCmd.AddCommand(group.GetCommand()) } From 38ce92563953e52ddff3cedfd8f673eae4313060 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Thu, 26 Nov 2020 20:37:28 -0800 Subject: [PATCH 19/32] Minor updates/fixes to NodeDB --- internal/pkg/node/constructors.go | 1 + internal/pkg/node/datastructure.go | 1 + internal/pkg/node/methods.go | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/internal/pkg/node/constructors.go b/internal/pkg/node/constructors.go index 11018d65..a0416b86 100644 --- a/internal/pkg/node/constructors.go +++ b/internal/pkg/node/constructors.go @@ -47,6 +47,7 @@ func (self *nodeYaml) FindAllNodes() ([]NodeInfo, error) { n.IpmiIpaddr.Set(node.IpmiIpaddr) n.Profiles = node.Profiles + n.GroupProfiles = group.Profiles allProfiles = append(allProfiles, group.Profiles...) allProfiles = append(allProfiles, node.Profiles...) diff --git a/internal/pkg/node/datastructure.go b/internal/pkg/node/datastructure.go index 4ce7acca..cf9d5a04 100644 --- a/internal/pkg/node/datastructure.go +++ b/internal/pkg/node/datastructure.go @@ -85,6 +85,7 @@ type NodeInfo struct { RuntimeOverlay NodeInfoEntry SystemOverlay NodeInfoEntry Profiles []string + GroupProfiles []string NetDevs map[string]*NetDevs } diff --git a/internal/pkg/node/methods.go b/internal/pkg/node/methods.go index dfc25789..39b8d8d5 100644 --- a/internal/pkg/node/methods.go +++ b/internal/pkg/node/methods.go @@ -1,5 +1,7 @@ package node +import "strings" + func (self *NodeInfoEntry) String() string { if self.value != "" { return "node=" + self.value @@ -64,6 +66,8 @@ func (self *NodeInfoEntry) SetProfile(value string) { func (self *NodeInfoEntry) Set(value string) { if value == "" { return + } else if strings.ToUpper(value) == "UNDEF" { + value = "" } self.value = value } From 41dd2e3a59d90c7eb8a5c9f204d4917df625447e Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Fri, 27 Nov 2020 16:37:56 -0800 Subject: [PATCH 20/32] Added basic profile handling CLI --- internal/app/wwctl/profile/add/main.go | 28 ++++ internal/app/wwctl/profile/add/root.go | 20 +++ internal/app/wwctl/profile/delete/main.go | 85 +++++++++++ internal/app/wwctl/profile/delete/root.go | 20 +++ internal/app/wwctl/profile/list/main.go | 36 +++++ internal/app/wwctl/profile/list/root.go | 20 +++ internal/app/wwctl/profile/root.go | 30 ++++ internal/app/wwctl/profile/set/main.go | 164 ++++++++++++++++++++++ internal/app/wwctl/profile/set/root.go | 40 ++++++ internal/app/wwctl/root.go | 2 + 10 files changed, 445 insertions(+) create mode 100644 internal/app/wwctl/profile/add/main.go create mode 100644 internal/app/wwctl/profile/add/root.go create mode 100644 internal/app/wwctl/profile/delete/main.go create mode 100644 internal/app/wwctl/profile/delete/root.go create mode 100644 internal/app/wwctl/profile/list/main.go create mode 100644 internal/app/wwctl/profile/list/root.go create mode 100644 internal/app/wwctl/profile/root.go create mode 100644 internal/app/wwctl/profile/set/main.go create mode 100644 internal/app/wwctl/profile/set/root.go diff --git a/internal/app/wwctl/profile/add/main.go b/internal/app/wwctl/profile/add/main.go new file mode 100644 index 00000000..b5c61387 --- /dev/null +++ b/internal/app/wwctl/profile/add/main.go @@ -0,0 +1,28 @@ +package add + +import ( + "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "github.com/spf13/cobra" + "os" +) + +func CobraRunE(cmd *cobra.Command, args []string) error { + nodeDB, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Failed opening node database: %s\n", err) + os.Exit(1) + } + + for _, p := range args { + err = nodeDB.AddProfile(p) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + + nodeDB.Persist() + + return nil +} \ No newline at end of file diff --git a/internal/app/wwctl/profile/add/root.go b/internal/app/wwctl/profile/add/root.go new file mode 100644 index 00000000..756e829f --- /dev/null +++ b/internal/app/wwctl/profile/add/root.go @@ -0,0 +1,20 @@ +package add + +import "github.com/spf13/cobra" + +var ( + baseCmd = &cobra.Command{ + Use: "add", + Short: "Add profiles", + Long: "Profile configurations ", + RunE: CobraRunE, + } +) + +func init() { +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/profile/delete/main.go b/internal/app/wwctl/profile/delete/main.go new file mode 100644 index 00000000..ffab3be5 --- /dev/null +++ b/internal/app/wwctl/profile/delete/main.go @@ -0,0 +1,85 @@ +package delete + +import ( + "fmt" + "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/util" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "github.com/manifoldco/promptui" + "github.com/spf13/cobra" + "os" +) + +func CobraRunE(cmd *cobra.Command, args []string) error { + var count int + var numNodes int + var numGroups int + + + nodeDB, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Failed to open node database: %s\n", err) + os.Exit(1) + } + + nodes, err := nodeDB.FindAllNodes() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not load all nodes: %s\n", err) + os.Exit(1) + } + groups, err := nodeDB.FindAllGroups() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not load all groups: %s\n", err) + os.Exit(1) + } + + + for _, p := range args { + err := nodeDB.DelProfile(p) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + continue + } + for _, n := range nodes { + for _, np := range n.Profiles { + if np == p { + numNodes++ + wwlog.Printf(wwlog.VERBOSE, "Removing profile from node %s: %s\n", n.Fqdn.Get(), p) + n.Profiles = util.SliceRemoveElement(n.Profiles, p) + nodeDB.NodeUpdate(n) + } + } + } + for _, g := range groups { + for _, np := range g.Profiles { + if np == p { + numGroups++ + wwlog.Printf(wwlog.VERBOSE, "Removing profile from group %s: %s\n", g.Id, p) + g.Profiles = util.SliceRemoveElement(g.Profiles, p) + nodeDB.GroupUpdate(g) + } + } + } + count++ + } + + if count > 0 { + q := fmt.Sprintf("Are you sure you want to delete %d profile(s) (%d groups, %d nodes)", count, numGroups, numNodes) + + prompt := promptui.Prompt{ + Label: q, + IsConfirm: true, + } + + result, _ := prompt.Run() + + if result == "y" || result == "yes" { + nodeDB.Persist() + } + + } else { + wwlog.Printf(wwlog.INFO, "No groups found\n") + } + + return nil +} diff --git a/internal/app/wwctl/profile/delete/root.go b/internal/app/wwctl/profile/delete/root.go new file mode 100644 index 00000000..c2a0cccf --- /dev/null +++ b/internal/app/wwctl/profile/delete/root.go @@ -0,0 +1,20 @@ +package delete + +import "github.com/spf13/cobra" + +var ( + baseCmd = &cobra.Command{ + Use: "delete", + Short: "Delete profiles", + Long: "Profile configurations ", + RunE: CobraRunE, + } +) + +func init() { +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/profile/list/main.go b/internal/app/wwctl/profile/list/main.go new file mode 100644 index 00000000..93a78486 --- /dev/null +++ b/internal/app/wwctl/profile/list/main.go @@ -0,0 +1,36 @@ +package list + +import ( + "fmt" + "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "github.com/spf13/cobra" + "os" + "reflect" +) + +func CobraRunE(cmd *cobra.Command, args []string) error { + + nodeDB, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } + + profiles, err := nodeDB.FindAllProfiles() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not find all nodes: %s\n", err) + os.Exit(1) + } + + for _, group := range profiles { + v := reflect.ValueOf(group) + typeOfS := v.Type() + fmt.Printf("################################################################################\n") + for i := 0; i< v.NumField(); i++ { + fmt.Printf("%-25s %s = %v\n", group.Id, typeOfS.Field(i).Name, v.Field(i).Interface()) + } + } + + return nil +} \ No newline at end of file diff --git a/internal/app/wwctl/profile/list/root.go b/internal/app/wwctl/profile/list/root.go new file mode 100644 index 00000000..1d3a8b8a --- /dev/null +++ b/internal/app/wwctl/profile/list/root.go @@ -0,0 +1,20 @@ +package list + +import "github.com/spf13/cobra" + +var ( + baseCmd = &cobra.Command{ + Use: "list", + Short: "List profiles", + Long: "Profile configurations ", + RunE: CobraRunE, + } +) + +func init() { +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/profile/root.go b/internal/app/wwctl/profile/root.go new file mode 100644 index 00000000..83922375 --- /dev/null +++ b/internal/app/wwctl/profile/root.go @@ -0,0 +1,30 @@ +package profile + +import ( + "github.com/hpcng/warewulf/internal/app/wwctl/profile/add" + "github.com/hpcng/warewulf/internal/app/wwctl/profile/delete" + "github.com/hpcng/warewulf/internal/app/wwctl/profile/list" + "github.com/hpcng/warewulf/internal/app/wwctl/profile/set" + "github.com/spf13/cobra" +) + +var ( + baseCmd = &cobra.Command{ + Use: "profile", + Short: "Management of node configuration profiles", + Long: "Warewulf profiles...", + } + test bool +) + +func init() { + baseCmd.AddCommand(list.GetCommand()) + baseCmd.AddCommand(set.GetCommand()) + baseCmd.AddCommand(add.GetCommand()) + baseCmd.AddCommand(delete.GetCommand()) +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/profile/set/main.go b/internal/app/wwctl/profile/set/main.go new file mode 100644 index 00000000..548b53c2 --- /dev/null +++ b/internal/app/wwctl/profile/set/main.go @@ -0,0 +1,164 @@ +package set + +import ( + "fmt" + "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "github.com/manifoldco/promptui" + "github.com/spf13/cobra" + "os" +) + +func CobraRunE(cmd *cobra.Command, args []string) error { + var err error + var profiles []node.ProfileInfo + + nodeDB, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } + + if err != nil { + wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + os.Exit(1) + } + + if SetAll == true { + var tmp []node.ProfileInfo + tmp, err = nodeDB.FindAllProfiles() + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + + for _, p := range tmp { + profiles = append(profiles, p) + } + + } else if len(args) > 0 { + var tmp []node.ProfileInfo + tmp, err = nodeDB.FindAllProfiles() + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + + for _, a := range args { + for _, p := range tmp { + if p.Id == a { + profiles = append(profiles, p) + } + } + } + + } else { + cmd.Usage() + os.Exit(1) + } + + for _, p := range profiles { + + if SetDomainName != "" { + wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting domain name to: %s\n", p.Id, SetDomainName) + + p.DomainName = SetDomainName + err := nodeDB.ProfileUpdate(p) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetVnfs != "" { + wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting VNFS to: %s\n", p.Id, SetVnfs) + + p.Vnfs = SetVnfs + err := nodeDB.ProfileUpdate(p) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetKernel != "" { + wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting Kernel version to: %s\n", p.Id, SetKernel) + + p.KernelVersion = SetKernel + err := nodeDB.ProfileUpdate(p) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetIpxe != "" { + wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting iPXE template to: %s\n", p.Id, SetIpxe) + + p.Ipxe = SetIpxe + err := nodeDB.ProfileUpdate(p) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetRuntimeOverlay != "" { + wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting runtime overlay to: %s\n", p.Id, SetRuntimeOverlay) + + p.RuntimeOverlay = SetRuntimeOverlay + err := nodeDB.ProfileUpdate(p) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetSystemOverlay != "" { + wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting system overlay to: %s\n", p.Id, SetSystemOverlay) + + p.SystemOverlay = SetSystemOverlay + err := nodeDB.ProfileUpdate(p) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetIpmiUsername != "" { + wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting IPMI username to: %s\n", p.Id, SetIpmiUsername) + + p.IpmiUserName = SetIpmiUsername + err := nodeDB.ProfileUpdate(p) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetIpmiPassword != "" { + wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting IPMI username to: %s\n", p.Id, SetIpmiPassword) + + p.IpmiPassword = SetIpmiPassword + err := nodeDB.ProfileUpdate(p) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + + } + + if len(profiles) > 0 { + q := fmt.Sprintf("Are you sure you want to modify %d group(s)", len(profiles)) + + prompt := promptui.Prompt{ + Label: q, + IsConfirm: true, + } + + result, _ := prompt.Run() + + if result == "y" || result == "yes" { + nodeDB.Persist() + } + + } else { + fmt.Printf("No profiles found\n") + } + + return nil +} \ No newline at end of file diff --git a/internal/app/wwctl/profile/set/root.go b/internal/app/wwctl/profile/set/root.go new file mode 100644 index 00000000..9f32cb39 --- /dev/null +++ b/internal/app/wwctl/profile/set/root.go @@ -0,0 +1,40 @@ +package set + +import "github.com/spf13/cobra" + +var ( + baseCmd = &cobra.Command{ + Use: "set", + Short: "Set profile configurations", + Long: "Profile configurations ", + RunE: CobraRunE, + } + SetAll bool + SetVnfs string + SetKernel string + SetDomainName string + SetIpxe string + SetRuntimeOverlay string + SetSystemOverlay string + SetIpmiUsername string + SetIpmiPassword string + +) + +func init() { + baseCmd.PersistentFlags().StringVarP(&SetVnfs, "vnfs", "V", "", "Set node Virtual Node File System (VNFS)") + baseCmd.PersistentFlags().StringVarP(&SetKernel, "kernel", "K", "", "Set Kernel version for nodes") + baseCmd.PersistentFlags().StringVarP(&SetDomainName, "domain", "D", "", "Set the node's domain name") + baseCmd.PersistentFlags().StringVarP(&SetIpxe, "ipxe", "P", "", "Set the node's iPXE template name") + baseCmd.PersistentFlags().StringVarP(&SetRuntimeOverlay, "runtime", "R", "", "Set the node's runtime overlay") + baseCmd.PersistentFlags().StringVarP(&SetSystemOverlay, "system", "S", "", "Set the node's system overlay") + baseCmd.PersistentFlags().StringVar(&SetIpmiUsername, "ipmiuser", "", "Set the node's IPMI username") + baseCmd.PersistentFlags().StringVar(&SetIpmiPassword, "ipmipass", "", "Set the node's IPMI password") + + baseCmd.PersistentFlags().BoolVarP(&SetAll, "all", "a", false, "Set all profiles") +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/root.go b/internal/app/wwctl/root.go index 3aeb3733..ee52e7dd 100644 --- a/internal/app/wwctl/root.go +++ b/internal/app/wwctl/root.go @@ -5,6 +5,7 @@ import ( "github.com/hpcng/warewulf/internal/app/wwctl/kernel" "github.com/hpcng/warewulf/internal/app/wwctl/node" "github.com/hpcng/warewulf/internal/app/wwctl/overlay" + "github.com/hpcng/warewulf/internal/app/wwctl/profile" "github.com/hpcng/warewulf/internal/app/wwctl/vnfs" "github.com/hpcng/warewulf/internal/pkg/wwlog" @@ -32,6 +33,7 @@ func init() { rootCmd.AddCommand(node.GetCommand()) rootCmd.AddCommand(kernel.GetCommand()) rootCmd.AddCommand(group.GetCommand()) + rootCmd.AddCommand(profile.GetCommand()) } From 7c3d727fbe445a5af83e9a187b7ac0eff4960cb0 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Fri, 27 Nov 2020 16:38:38 -0800 Subject: [PATCH 21/32] Updates to node and group list commands --- internal/app/wwctl/group/list/main.go | 3 +- internal/app/wwctl/node/list/main.go | 40 +++++++++++++++++++++------ 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/internal/app/wwctl/group/list/main.go b/internal/app/wwctl/group/list/main.go index 97a5370b..0d5f88e1 100644 --- a/internal/app/wwctl/group/list/main.go +++ b/internal/app/wwctl/group/list/main.go @@ -7,6 +7,7 @@ import ( "github.com/spf13/cobra" "os" "reflect" + "strings" ) func CobraRunE(cmd *cobra.Command, args []string) error { @@ -35,7 +36,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } else { fmt.Printf("%-22s %-16s %s\n", "GROUP NAME", "DOMAINNAME", "PROFILES") for _, g := range groups { - fmt.Printf("%-22s %-16s %s\n", g.Id, g.DomainName, g.Profiles) + fmt.Printf("%-22s %-16s %s\n", g.Id, g.DomainName, strings.Join(g.Profiles, ",")) } } diff --git a/internal/app/wwctl/node/list/main.go b/internal/app/wwctl/node/list/main.go index db8564c0..77b44758 100644 --- a/internal/app/wwctl/node/list/main.go +++ b/internal/app/wwctl/node/list/main.go @@ -6,7 +6,6 @@ import ( "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" "os" - "reflect" "strings" ) @@ -35,13 +34,36 @@ func CobraRunE(cmd *cobra.Command, args []string) error { if ShowAll == true { for _, node := range nodes { - v := reflect.ValueOf(node) - typeOfS := v.Type() fmt.Printf("################################################################################\n") - for i := 0; i< v.NumField(); i++ { - //TODO: Fix for NetDevs and Interface should print Fprint() method - fmt.Printf("%-25s %s = %#v\n", node.Fqdn.Get(), typeOfS.Field(i).Name, v.Field(i).Interface()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "Id", node.Id.Source(), node.Id.Get()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "Comment", node.Comment.Source(), node.Comment.Get()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "GroupName", node.GroupName.Source(), node.GroupName.Get()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "DomainName", node.DomainName.Source(), node.DomainName.Get()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "Profiles (Group)", "group", strings.Join(node.GroupProfiles, ",")) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "Profiles (Node)", "node", strings.Join(node.Profiles, ",")) + + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "Vnfs", node.Vnfs.Source(), node.Vnfs.Get()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "KernelVersion", node.KernelVersion.Source(), node.KernelVersion.Get()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "KernelArgs", node.KernelArgs.Source(), node.KernelArgs.Get()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "RuntimeOverlay", node.RuntimeOverlay.Source(), node.RuntimeOverlay.Get()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "SystemOverlay", node.SystemOverlay.Source(), node.SystemOverlay.Get()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "IpmiUserName", node.IpmiUserName.Source(), node.IpmiUserName.Get()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "IpmiIpaddr", node.IpmiIpaddr.Source(), node.IpmiIpaddr.Get()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "Ipxe", node.Ipxe.Source(), node.Ipxe.Get()) + + for name, netdev := range node.NetDevs { + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), name +":IPADDR", "node", netdev.Ipaddr) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), name +":NETMASK", "node", netdev.Netmask) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), name +":GATEWAY", "node", netdev.Gateway) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), name +":HWADDR", "node", netdev.Hwaddr) } + + // v := reflect.ValueOf(node) +// typeOfS := v.Type() +// for i := 0; i< v.NumField(); i++ { +// //TODO: Fix for NetDevs and Interface should print Fprint() method +// fmt.Printf("%-25s %s = %#v\n", node.Fqdn.Get(), typeOfS.Field(i).Name, v.Field(i).Interface()) +// } } } else if ShowNet == true { @@ -71,15 +93,15 @@ func CobraRunE(cmd *cobra.Command, args []string) error { fmt.Println(strings.Repeat("=", 120)) for _, node := range nodes { - fmt.Printf("%-22s %-12s %-26s %-35s %s\n", node.Fqdn.Get(), node.GroupName.Get(), node.KernelVersion.Get(), node.Vnfs.Get(), node.SystemOverlay.Get() +"/"+ node.RuntimeOverlay.Get()) + fmt.Printf("%-22s %-12s %-26s %-35s %s\n", node.Fqdn.Get(), node.GroupName.String(), node.KernelVersion.String(), node.Vnfs.String(), node.SystemOverlay.String() +"/"+ node.RuntimeOverlay.String()) } } else { - fmt.Printf("%-22s %s\n", "NODE NAME", "PROFILES") + fmt.Printf("%-22s %-30s %s\n", "NODE NAME", "VNFS", "PROFILES") fmt.Println(strings.Repeat("=", 80)) for _, node := range nodes { - fmt.Printf("%-22s %s\n", node.Fqdn.Get(), append(node.GroupProfiles, node.Profiles...)) + fmt.Printf("%-22s %-30s %s\n", node.Fqdn.Get(), node.Vnfs.String(), strings.Join(append(node.GroupProfiles, node.Profiles...), ",")) } } From e3dd3253d1565599a1d241c2892f2e67be7c4c03 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Fri, 27 Nov 2020 16:39:01 -0800 Subject: [PATCH 22/32] Updates to node and group sets to include profiles --- internal/app/wwctl/group/set/main.go | 106 +++++++++++++++++++++++---- internal/app/wwctl/group/set/root.go | 8 +- internal/app/wwctl/node/set/main.go | 25 +++++++ internal/app/wwctl/node/set/root.go | 5 ++ 4 files changed, 126 insertions(+), 18 deletions(-) diff --git a/internal/app/wwctl/group/set/main.go b/internal/app/wwctl/group/set/main.go index 467e077f..2cc8fcbe 100644 --- a/internal/app/wwctl/group/set/main.go +++ b/internal/app/wwctl/group/set/main.go @@ -3,6 +3,7 @@ package set import ( "fmt" "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/util" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/manifoldco/promptui" "github.com/spf13/cobra" @@ -61,23 +62,98 @@ func CobraRunE(cmd *cobra.Command, args []string) error { if SetDomainName != "" { wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting domain name to: %s\n", g.Id, SetDomainName) -// err := nodeDB.SetGroupVal(g.Id.String(), "domain", SetDomainName) -// if err != nil { -// wwlog.Printf(wwlog.ERROR, "%s\n", err) -// os.Exit(1) -// } -// if SetClearNodes == true { -// nodes, err := nodeDB.FindAllNodes() -// if err != nil { -// wwlog.Printf(wwlog.ERROR, "%s\n", err) -// os.Exit(1) -// } -// for _, n := range nodes { -// _ = nodeDB.SetNodeVal(g.Id.String(), n.Id.String(), "domain", "") -// } -// } + g.DomainName = SetDomainName + err := nodeDB.GroupUpdate(g) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } } + if SetVnfs != "" { + wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting VNFS to: %s\n", g.Id, SetVnfs) + + g.Vnfs = SetVnfs + err := nodeDB.GroupUpdate(g) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetKernel != "" { + wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting kernel to: %s\n", g.Id, SetKernel) + + g.KernelVersion = SetKernel + err := nodeDB.GroupUpdate(g) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetIpmiUsername != "" { + wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting IPMI username to: %s\n", g.Id, SetIpmiUsername) + + g.IpmiUserName = SetIpmiUsername + err := nodeDB.GroupUpdate(g) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetIpmiPassword != "" { + wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting IPMI password to: %s\n", g.Id, SetIpmiPassword) + + g.IpmiPassword = SetIpmiPassword + err := nodeDB.GroupUpdate(g) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetSystemOverlay != "" { + wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting system overlay to: %s\n", g.Id, SetSystemOverlay) + + g.SystemOverlay = SetSystemOverlay + err := nodeDB.GroupUpdate(g) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetRuntimeOverlay != "" { + wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting runtime overlay to: %s\n", g.Id, SetRuntimeOverlay) + + g.RuntimeOverlay = SetRuntimeOverlay + err := nodeDB.GroupUpdate(g) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + + if len(SetAddProfile) > 0 { + for _, p := range SetAddProfile { + wwlog.Printf(wwlog.VERBOSE, "Adding profile to '%s': '%s'\n", g.Id, p) + g.Profiles = util.SliceAddUniqueElement(g.Profiles, p) + } + err := nodeDB.GroupUpdate(g) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if len(SetDelProfile) > 0 { + for _, p := range SetDelProfile { + wwlog.Printf(wwlog.VERBOSE, "Removing profile to '%s': '%s'\n", g.Id, p) + g.Profiles = util.SliceRemoveElement(g.Profiles, p) + } + err := nodeDB.GroupUpdate(g) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + } diff --git a/internal/app/wwctl/group/set/root.go b/internal/app/wwctl/group/set/root.go index d4378b52..0871d209 100644 --- a/internal/app/wwctl/group/set/root.go +++ b/internal/app/wwctl/group/set/root.go @@ -15,12 +15,12 @@ var ( SetIpxe string SetRuntimeOverlay string SetSystemOverlay string - SetHostname string SetClearNodes bool - SetIpmiIpaddr string SetIpmiUsername string SetIpmiPassword string SetGroupAll bool + SetAddProfile []string + SetDelProfile []string ) func init() { @@ -30,10 +30,12 @@ func init() { baseCmd.PersistentFlags().StringVarP(&SetIpxe, "ipxe", "P", "", "Set the node's iPXE template name") baseCmd.PersistentFlags().StringVarP(&SetRuntimeOverlay, "runtime", "R", "", "Set the node's runtime overlay") baseCmd.PersistentFlags().StringVarP(&SetSystemOverlay, "system", "S", "", "Set the node's system overlay") - baseCmd.PersistentFlags().StringVar(&SetIpmiIpaddr, "ipmi", "", "Set the node's IPMI address") baseCmd.PersistentFlags().StringVar(&SetIpmiUsername, "ipmiuser", "", "Set the node's IPMI username") baseCmd.PersistentFlags().StringVar(&SetIpmiPassword, "ipmipass", "", "Set the node's IPMI password") + baseCmd.PersistentFlags().StringSliceVarP(&SetAddProfile, "addprofile", "p", []string{}, "Add Profile(s) to group") + baseCmd.PersistentFlags().StringSliceVarP(&SetDelProfile, "delprofile", "r", []string{}, "Remove Profile(s) to group") + baseCmd.PersistentFlags().BoolVarP(&SetClearNodes, "clear", "c", false, "Clear node configurations when setting parent group") baseCmd.PersistentFlags().BoolVarP(&SetGroupAll, "all", "a", false, "Set all nodes") diff --git a/internal/app/wwctl/node/set/main.go b/internal/app/wwctl/node/set/main.go index 874333bd..10bbf269 100644 --- a/internal/app/wwctl/node/set/main.go +++ b/internal/app/wwctl/node/set/main.go @@ -3,6 +3,7 @@ package set import ( "fmt" "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/util" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/manifoldco/promptui" "github.com/spf13/cobra" @@ -44,6 +45,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { for _, n := range nodes { wwlog.Printf(wwlog.VERBOSE, "Evaluating node: %s\n", n.Fqdn.String()) + if SetVnfs != "" { wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting vnfs to: %s\n", n.Fqdn.String(), SetVnfs) @@ -145,6 +147,29 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } } + if len(SetAddProfile) > 0 { + for _, p := range SetAddProfile { + wwlog.Printf(wwlog.VERBOSE, "Node: %s, adding profile to '%s'\n", n.Fqdn, p) + n.Profiles = util.SliceAddUniqueElement(n.Profiles, p) + } + err := nodeDB.NodeUpdate(n) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if len(SetDelProfile) > 0 { + for _, p := range SetDelProfile { + wwlog.Printf(wwlog.VERBOSE, "Node: %s, deleting profile from '%s'\n", n.Fqdn, p) + n.Profiles = util.SliceRemoveElement(n.Profiles, p) + } + err := nodeDB.NodeUpdate(n) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetNetDevDel == true { diff --git a/internal/app/wwctl/node/set/root.go b/internal/app/wwctl/node/set/root.go index f65ec18d..937b6025 100644 --- a/internal/app/wwctl/node/set/root.go +++ b/internal/app/wwctl/node/set/root.go @@ -27,6 +27,8 @@ var ( SetIpmiPassword string SetNodeAll bool SetYes bool + SetAddProfile []string + SetDelProfile []string ) func init() { @@ -41,6 +43,9 @@ func init() { baseCmd.PersistentFlags().StringVar(&SetIpmiUsername, "ipmiuser", "", "Set the node's IPMI username") baseCmd.PersistentFlags().StringVar(&SetIpmiPassword, "ipmipass", "", "Set the node's IPMI password") + baseCmd.PersistentFlags().StringSliceVarP(&SetAddProfile, "addprofile", "p", []string{}, "Add Profile(s) to node") + baseCmd.PersistentFlags().StringSliceVarP(&SetDelProfile, "delprofile", "r", []string{}, "Remove Profile(s) to node") + baseCmd.PersistentFlags().StringVarP(&SetNetDev, "netdev", "n", "", "Define the network device to configure") baseCmd.PersistentFlags().StringVarP(&SetIpaddr, "ipaddr", "I", "", "Set the node's network device IP address") baseCmd.PersistentFlags().StringVarP(&SetNetmask, "netmask", "M", "", "Set the node's network device netmask") From f74826bc8766f33ce76aefc7e3afe72e4d345c27 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Fri, 27 Nov 2020 16:39:27 -0800 Subject: [PATCH 23/32] Various nodeDB updates --- internal/pkg/node/constructors.go | 53 +++++++++++++++++++----------- internal/pkg/node/datastructure.go | 20 +++++++++-- internal/pkg/node/methods.go | 18 ++++++---- internal/pkg/node/modifiers.go | 10 ++++++ 4 files changed, 72 insertions(+), 29 deletions(-) diff --git a/internal/pkg/node/constructors.go b/internal/pkg/node/constructors.go index a0416b86..9b143f94 100644 --- a/internal/pkg/node/constructors.go +++ b/internal/pkg/node/constructors.go @@ -45,9 +45,33 @@ func (self *nodeYaml) FindAllNodes() ([]NodeInfo, error) { n.GroupName.Set(groupname) n.HostName.Set(node.Hostname) n.IpmiIpaddr.Set(node.IpmiIpaddr) + n.DomainName.Set(node.DomainName) + n.Vnfs.Set(node.Vnfs) + n.KernelVersion.Set(node.KernelVersion) + n.KernelArgs.Set(node.KernelArgs) + n.Ipxe.Set(node.Ipxe) + n.IpmiUserName.Set(node.IpmiUserName) + n.IpmiPassword.Set(node.IpmiPassword) + n.SystemOverlay.Set(node.SystemOverlay) + n.RuntimeOverlay.Set(node.RuntimeOverlay) + + n.DomainName.SetGroup(group.DomainName) + n.Vnfs.SetGroup(group.Vnfs) + n.KernelVersion.SetGroup(group.KernelVersion) + n.KernelArgs.SetGroup(group.KernelArgs) + n.Ipxe.SetGroup(group.Ipxe) + n.IpmiUserName.SetGroup(group.IpmiUserName) + n.IpmiPassword.SetGroup(group.IpmiPassword) + n.SystemOverlay.SetGroup(group.SystemOverlay) + n.RuntimeOverlay.SetGroup(group.RuntimeOverlay) + + n.RuntimeOverlay.SetDefault("default") + n.SystemOverlay.SetDefault("default") + n.Ipxe.SetDefault("default") + n.KernelArgs.SetDefault("crashkernel=no quiet") - n.Profiles = node.Profiles n.GroupProfiles = group.Profiles + n.Profiles = node.Profiles allProfiles = append(allProfiles, group.Profiles...) allProfiles = append(allProfiles, node.Profiles...) @@ -58,34 +82,17 @@ func (self *nodeYaml) FindAllNodes() ([]NodeInfo, error) { continue } + n.DomainName.SetProfile(self.NodeProfiles[p].DomainName) n.Vnfs.SetProfile(self.NodeProfiles[p].Vnfs) n.KernelVersion.SetProfile(self.NodeProfiles[p].KernelVersion) n.KernelArgs.SetProfile(self.NodeProfiles[p].KernelArgs) n.Ipxe.SetProfile(self.NodeProfiles[p].Ipxe) n.IpmiUserName.SetProfile(self.NodeProfiles[p].IpmiUserName) n.IpmiPassword.SetProfile(self.NodeProfiles[p].IpmiPassword) - n.DomainName.SetProfile(self.NodeProfiles[p].DomainName) n.SystemOverlay.SetProfile(self.NodeProfiles[p].SystemOverlay) n.RuntimeOverlay.SetProfile(self.NodeProfiles[p].RuntimeOverlay) } - n.DomainName.Set(node.DomainName) - n.DomainName.SetGroup(group.DomainName) - n.Vnfs.Set(node.Vnfs) - n.KernelVersion.Set(node.KernelVersion) - n.KernelArgs.Set(node.KernelArgs) - n.Ipxe.Set(node.Ipxe) - n.IpmiUserName.Set(node.IpmiUserName) - n.IpmiPassword.Set(node.IpmiPassword) - - n.RuntimeOverlay.SetDefault("default") - n.SystemOverlay.SetDefault("default") - n.Ipxe.SetDefault("default") - n.KernelArgs.SetDefault("crashkernel=no quiet") - - // config := config.New() - // n.VnfsRoot = config.VnfsChroot(vnfs.CleanName(n.Vnfs)) - if n.DomainName.Defined() == true { n.Fqdn.Set(node.Hostname +"."+ n.DomainName.Get()) } else { @@ -109,8 +116,14 @@ func (self *nodeYaml) FindAllGroups() ([]GroupInfo, error) { g.Id = groupname g.DomainName = group.DomainName - g.Disabled = group.Disabled g.Comment = group.Comment + g.Vnfs = group.Vnfs + g.KernelVersion = group.KernelVersion + g.KernelArgs = group.KernelArgs + g.IpmiPassword = group.IpmiPassword + g.IpmiUserName = group.IpmiUserName + g.SystemOverlay = group.SystemOverlay + g.RuntimeOverlay = group.RuntimeOverlay g.Profiles = group.Profiles diff --git a/internal/pkg/node/datastructure.go b/internal/pkg/node/datastructure.go index cf9d5a04..7e23a72e 100644 --- a/internal/pkg/node/datastructure.go +++ b/internal/pkg/node/datastructure.go @@ -28,6 +28,14 @@ type GroupConf struct { Comment string `yaml:"comment"` Disabled bool `yaml:"disabled,omitempty"` DomainName string `yaml:"domain name"` + Vnfs string `yaml:"vnfs,omitempty"` + Ipxe string `yaml:"ipxe template,omitempty"` + KernelVersion string `yaml:"kernel version,omitempty"` + KernelArgs string `yaml:"kernel args,omitempty"` + IpmiUserName string `yaml:"ipmi username,omitempty"` + IpmiPassword string `yaml:"ipmi password,omitempty"` + RuntimeOverlay string `yaml:"runtime overlay files,omitempty"` + SystemOverlay string `yaml:"system overlay files,omitempty"` Profiles []string `yaml:"profiles,omitempty"` Nodes map[string]*NodeConf } @@ -36,13 +44,13 @@ type NodeConf struct { Comment string `yaml:"comment,omitempty"` Disabled bool `yaml:"disabled,omitempty"` Hostname string `yaml:"hostname,omitempty"` + DomainName string `yaml:"domain name,omitempty"` Vnfs string `yaml:"vnfs,omitempty"` Ipxe string `yaml:"ipxe template,omitempty"` KernelVersion string `yaml:"kernel version,omitempty"` KernelArgs string `yaml:"kernel args,omitempty"` IpmiUserName string `yaml:"ipmi username,omitempty"` IpmiPassword string `yaml:"ipmi password,omitempty"` - DomainName string `yaml:"domain name,omitempty"` IpmiIpaddr string `yaml:"ipmi ipaddr,omitempty"` RuntimeOverlay string `yaml:"runtime overlay files,omitempty"` SystemOverlay string `yaml:"system overlay files,omitempty"` @@ -75,7 +83,6 @@ type NodeInfo struct { Fqdn NodeInfoEntry DomainName NodeInfoEntry Vnfs NodeInfoEntry - VnfsRoot NodeInfoEntry Ipxe NodeInfoEntry KernelVersion NodeInfoEntry KernelArgs NodeInfoEntry @@ -92,8 +99,15 @@ type NodeInfo struct { type GroupInfo struct { Id string Comment string - Disabled bool + Vnfs string + Ipxe string + KernelVersion string + KernelArgs string + IpmiUserName string + IpmiPassword string DomainName string + RuntimeOverlay string + SystemOverlay string Profiles []string } diff --git a/internal/pkg/node/methods.go b/internal/pkg/node/methods.go index 39b8d8d5..7cbce368 100644 --- a/internal/pkg/node/methods.go +++ b/internal/pkg/node/methods.go @@ -1,21 +1,27 @@ package node -import "strings" +import ( + "strings" +) func (self *NodeInfoEntry) String() string { + return self.Get() +} + +func (self *NodeInfoEntry) Source() string { if self.value != "" { - return "node=" + self.value + return "node" } if self.group != "" { - return "group=" + self.group + return "group" } if self.profile != "" { - return "profile=" + self.profile + return "profile" } if self.def != "" { - return "default=" + self.def + return "default" } - return "--" + return "" } func (self *NodeInfoEntry) Get() string { diff --git a/internal/pkg/node/modifiers.go b/internal/pkg/node/modifiers.go index 3a07df51..870e69a1 100644 --- a/internal/pkg/node/modifiers.go +++ b/internal/pkg/node/modifiers.go @@ -95,6 +95,7 @@ func (self *nodeYaml) AddGroup(groupID string) error { self.NodeGroups[groupID] = &group self.NodeGroups[groupID].DomainName = groupID + self.NodeGroups[groupID].Profiles = []string{"default"} return nil } @@ -119,6 +120,15 @@ func(self *nodeYaml) GroupUpdate(group GroupInfo) error { } self.NodeGroups[groupID].DomainName = group.DomainName + self.NodeGroups[groupID].Vnfs = group.Vnfs + self.NodeGroups[groupID].KernelVersion = group.KernelVersion + self.NodeGroups[groupID].KernelArgs = group.KernelArgs + self.NodeGroups[groupID].Ipxe = group.Ipxe + self.NodeGroups[groupID].IpmiUserName = group.IpmiUserName + self.NodeGroups[groupID].IpmiPassword = group.IpmiPassword + self.NodeGroups[groupID].RuntimeOverlay = group.RuntimeOverlay + self.NodeGroups[groupID].SystemOverlay = group.SystemOverlay + self.NodeGroups[groupID].Profiles = group.Profiles return nil } From 2ba40c0e65ace3a92310d0784064a87970cb54e9 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Fri, 27 Nov 2020 16:39:39 -0800 Subject: [PATCH 24/32] Fixup to slice manipulation functions --- internal/pkg/util/util.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/pkg/util/util.go b/internal/pkg/util/util.go index 236109f1..a25896c7 100644 --- a/internal/pkg/util/util.go +++ b/internal/pkg/util/util.go @@ -200,6 +200,8 @@ func SliceRemoveElement(array []string, remove string) []string { for _, r := range array { if r != remove { ret = append(ret, r) + } else { + wwlog.Printf(wwlog.DEBUG, "Removing slice from array: %s\n", remove) } } From 9b87bbc6bd1f403c4bce206eb35ad2f2fb0dbdd5 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Fri, 27 Nov 2020 16:40:08 -0800 Subject: [PATCH 25/32] Go file updates when playing with colorization --- go.mod | 1 + go.sum | 1 + 2 files changed, 2 insertions(+) diff --git a/go.mod b/go.mod index a9c1f20b..99e999cb 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.15 require ( github.com/containers/image/v5 v5.7.0 + github.com/fatih/color v1.9.0 github.com/kelseyhightower/envconfig v1.4.0 github.com/manifoldco/promptui v0.8.0 github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6 diff --git a/go.sum b/go.sum index 17ed50fd..94f25fa8 100644 --- a/go.sum +++ b/go.sum @@ -106,6 +106,7 @@ github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNE github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= From b12f6860e10414550f9a7ccfb8122e09c053de47 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Fri, 27 Nov 2020 17:09:48 -0800 Subject: [PATCH 26/32] Changed default nodes.conf file --- etc/nodes.conf | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/etc/nodes.conf b/etc/nodes.conf index 8bce1c10..e28002f1 100644 --- a/etc/nodes.conf +++ b/etc/nodes.conf @@ -1,12 +1,7 @@ nodeprofiles: default: comment: "" - vnfs: "" - kernel version: 3.10.0-1127.el7.x86_64 kernel args: crashkernel=no quiet - test: - comment: "" - vnfs: docker://warewulf/centos-7 nodegroups: default: comment: This is the default group @@ -16,8 +11,6 @@ nodegroups: nodes: n0000: hostname: n0000 - profiles: - - test netdevs: eth0: type: ethernet @@ -50,7 +43,7 @@ nodegroups: - default nodes: n0000: - hostname: localtest + hostname: n0000 netdevs: eth0: hwaddr: aa:bb:cc:dd:ee:c0 From d8ce0157c1f828087ece6346c2ee96208eef9e47 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Fri, 27 Nov 2020 17:10:07 -0800 Subject: [PATCH 27/32] Cleaned node list output --- internal/app/wwctl/node/list/main.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/internal/app/wwctl/node/list/main.go b/internal/app/wwctl/node/list/main.go index 77b44758..921e8832 100644 --- a/internal/app/wwctl/node/list/main.go +++ b/internal/app/wwctl/node/list/main.go @@ -35,21 +35,21 @@ func CobraRunE(cmd *cobra.Command, args []string) error { if ShowAll == true { for _, node := range nodes { fmt.Printf("################################################################################\n") - fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "Id", node.Id.Source(), node.Id.Get()) - fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "Comment", node.Comment.Source(), node.Comment.Get()) - fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "GroupName", node.GroupName.Source(), node.GroupName.Get()) - fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "DomainName", node.DomainName.Source(), node.DomainName.Get()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "Id", node.Id.Source(), node.Id.String()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "Comment", node.Comment.Source(), node.Comment.String()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "GroupName", node.GroupName.Source(), node.GroupName.String()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "DomainName", node.DomainName.Source(), node.DomainName.String()) fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "Profiles (Group)", "group", strings.Join(node.GroupProfiles, ",")) fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "Profiles (Node)", "node", strings.Join(node.Profiles, ",")) - fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "Vnfs", node.Vnfs.Source(), node.Vnfs.Get()) - fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "KernelVersion", node.KernelVersion.Source(), node.KernelVersion.Get()) - fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "KernelArgs", node.KernelArgs.Source(), node.KernelArgs.Get()) - fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "RuntimeOverlay", node.RuntimeOverlay.Source(), node.RuntimeOverlay.Get()) - fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "SystemOverlay", node.SystemOverlay.Source(), node.SystemOverlay.Get()) - fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "IpmiUserName", node.IpmiUserName.Source(), node.IpmiUserName.Get()) - fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "IpmiIpaddr", node.IpmiIpaddr.Source(), node.IpmiIpaddr.Get()) - fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "Ipxe", node.Ipxe.Source(), node.Ipxe.Get()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "Vnfs", node.Vnfs.Source(), node.Vnfs.String()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "KernelVersion", node.KernelVersion.Source(), node.KernelVersion.String()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "KernelArgs", node.KernelArgs.Source(), node.KernelArgs.String()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "RuntimeOverlay", node.RuntimeOverlay.Source(), node.RuntimeOverlay.String()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "SystemOverlay", node.SystemOverlay.Source(), node.SystemOverlay.String()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "IpmiUserName", node.IpmiUserName.Source(), node.IpmiUserName.String()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "IpmiIpaddr", node.IpmiIpaddr.Source(), node.IpmiIpaddr.String()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "Ipxe", node.Ipxe.Source(), node.Ipxe.String()) for name, netdev := range node.NetDevs { fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), name +":IPADDR", "node", netdev.Ipaddr) @@ -85,7 +85,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { fmt.Println(strings.Repeat("=", 80)) for _, node := range nodes { - fmt.Printf("%-22s %-16s %-20s %-20s\n", node.Fqdn.Get(), node.IpmiIpaddr.Get(), node.IpmiUserName.Get(), node.IpmiPassword.Get()) + fmt.Printf("%-22s %-16s %-20s %-20s\n", node.Fqdn.Get(), node.IpmiIpaddr.String(), node.IpmiUserName.String(), node.IpmiPassword.String()) } } else if ShowLong == true { From 68ec517ebbab474deed0d8dd6fe468602497880b Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Fri, 27 Nov 2020 17:10:20 -0800 Subject: [PATCH 28/32] Fixed string() method for node configurations --- internal/pkg/node/methods.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/internal/pkg/node/methods.go b/internal/pkg/node/methods.go index 7cbce368..8ccbb6f5 100644 --- a/internal/pkg/node/methods.go +++ b/internal/pkg/node/methods.go @@ -5,7 +5,19 @@ import ( ) func (self *NodeInfoEntry) String() string { - return self.Get() + if self.value != "" { + return self.value + } + if self.group != "" { + return self.group + } + if self.profile != "" { + return self.profile + } + if self.def != "" { + return self.def + } + return "--" } func (self *NodeInfoEntry) Source() string { From 3a5497000e4324539d891c53a7b6857ec94c8e8f Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Fri, 27 Nov 2020 17:17:29 -0800 Subject: [PATCH 29/32] Update the README.md with new install/work flow --- README.md | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index c1f7dfd4..b8cad6ba 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,35 @@ # warewulf v4 WIP -This is built on CentOS-7. More needs to be done to make it work on other +This is built on CentOS-7/8. More needs to be done to make it work on other distributions and versions specifically with the system service components. In a nutshell, to install and start provisioning nodes, do the following: -1. `make` -2. `sudo make install` -3. `vi /etc/warewulf/warewulf.conf` -4. `vi /etc/warewulf/nodes.conf` -5. `sudo singularity build --sandbox /var/chroots/centos-7 centos-7.def` -6. `sudo ./wwbuild vnfs` -7. `sudo ./wwbuild kernel` -8. `sudo ./wwbuild overlay` -9. `./warewulfd` -10. Boot your compute node +1. Build Warewulf and dependencies: + + `make all` + +1. Install Warewulf onto your host system: + + `sudo make install` + +1. Set the master's kernel and default VNFS into your "default" node profile: + + `sudo ./wwctl profile set -K $(uname -r) -V docker://warewulf/centos-8 default` + + +1. Build the kernel, VNFS, and overlays: + + `sudo ./wwctl kernel build -a` + + `sudo ./wwctl vnfs build -a` + + `sudo ./wwctl overlay build -sa` + +1. Start the Warewulf daemon: + + `./warewulfd` + +1. Boot your compute node and watch it boot From ace5bf0b8ad6ae39a5d623233ecab30dce9182b5 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Fri, 27 Nov 2020 17:19:31 -0800 Subject: [PATCH 30/32] Cleanup the code portions of the README --- README.md | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index b8cad6ba..80ac5a2d 100644 --- a/README.md +++ b/README.md @@ -8,28 +8,36 @@ In a nutshell, to install and start provisioning nodes, do the following: 1. Build Warewulf and dependencies: - `make all` +``` +make all +``` 1. Install Warewulf onto your host system: - `sudo make install` +``` +sudo make install +``` 1. Set the master's kernel and default VNFS into your "default" node profile: - `sudo ./wwctl profile set -K $(uname -r) -V docker://warewulf/centos-8 default` +``` +sudo ./wwctl profile set -K $(uname -r) -V docker://warewulf/centos-8 default +``` 1. Build the kernel, VNFS, and overlays: - `sudo ./wwctl kernel build -a` - - `sudo ./wwctl vnfs build -a` - - `sudo ./wwctl overlay build -sa` +``` +sudo ./wwctl kernel build -a +sudo ./wwctl vnfs build -a +sudo ./wwctl overlay build -sa +``` 1. Start the Warewulf daemon: - `./warewulfd` +``` +./warewulfd +``` 1. Boot your compute node and watch it boot From 210d0044a52f0ea73f38ddfd136304c21a9d3310 Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Fri, 27 Nov 2020 17:20:47 -0800 Subject: [PATCH 31/32] Minor chnage in the VNFS `CleanName()` function. --- internal/pkg/vnfs/vnfs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/pkg/vnfs/vnfs.go b/internal/pkg/vnfs/vnfs.go index bdf8c248..11d67ad0 100644 --- a/internal/pkg/vnfs/vnfs.go +++ b/internal/pkg/vnfs/vnfs.go @@ -61,7 +61,7 @@ func CleanName(source string) string { tmp = strings.ReplaceAll(tmp, "://", "-") tmp = strings.ReplaceAll(tmp, "/", ".") - tmp = strings.ReplaceAll(tmp, ":", ".") + tmp = strings.ReplaceAll(tmp, ":", "-") return tmp } From 4d752a67db5275508e1872b95383b8adfbb593ef Mon Sep 17 00:00:00 2001 From: Gregory Kurtzer Date: Mon, 30 Nov 2020 23:07:42 -0800 Subject: [PATCH 32/32] Added controllers, services, and lots of various optimizations and fixes --- README.md | 2 + etc/{dhcpd.conf => dhcp/default-dhcpd.conf} | 28 +- etc/nodes.conf | 131 +++++---- internal/app/wwctl/controller/add/main.go | 29 ++ internal/app/wwctl/controller/add/root.go | 23 ++ internal/app/wwctl/controller/delete/main.go | 61 +++++ internal/app/wwctl/controller/delete/root.go | 23 ++ internal/app/wwctl/controller/list/main.go | 45 +++ internal/app/wwctl/controller/list/root.go | 23 ++ internal/app/wwctl/controller/root.go | 30 ++ internal/app/wwctl/controller/set/main.go | 94 +++++++ internal/app/wwctl/controller/set/root.go | 26 ++ internal/app/wwctl/group/add/main.go | 2 +- internal/app/wwctl/group/add/root.go | 7 +- internal/app/wwctl/group/delete/main.go | 4 +- internal/app/wwctl/group/delete/root.go | 7 +- internal/app/wwctl/group/list/main.go | 4 +- internal/app/wwctl/node/add/main.go | 2 +- internal/app/wwctl/node/add/root.go | 4 +- internal/app/wwctl/node/delete/main.go | 6 +- internal/app/wwctl/node/delete/root.go | 2 + internal/app/wwctl/node/list/main.go | 4 +- internal/app/wwctl/node/set/root.go | 4 +- internal/app/wwctl/overlay/edit/main.go | 4 +- internal/app/wwctl/profile/set/main.go | 2 +- internal/app/wwctl/root.go | 19 +- internal/app/wwctl/services/dhcp/main.go | 109 ++++++++ internal/app/wwctl/services/dhcp/root.go | 23 ++ internal/app/wwctl/services/root.go | 23 ++ internal/pkg/node/constructors.go | 224 +++++++++------ internal/pkg/node/datastructure.go | 273 ++++++++++++------- internal/pkg/node/methods.go | 16 ++ internal/pkg/node/modifiers.go | 206 ++++++++++---- internal/pkg/overlay/overlay.go | 38 ++- internal/pkg/vnfs/vnfs.go | 14 +- 35 files changed, 1147 insertions(+), 365 deletions(-) rename etc/{dhcpd.conf => dhcp/default-dhcpd.conf} (66%) create mode 100644 internal/app/wwctl/controller/add/main.go create mode 100644 internal/app/wwctl/controller/add/root.go create mode 100644 internal/app/wwctl/controller/delete/main.go create mode 100644 internal/app/wwctl/controller/delete/root.go create mode 100644 internal/app/wwctl/controller/list/main.go create mode 100644 internal/app/wwctl/controller/list/root.go create mode 100644 internal/app/wwctl/controller/root.go create mode 100644 internal/app/wwctl/controller/set/main.go create mode 100644 internal/app/wwctl/controller/set/root.go create mode 100644 internal/app/wwctl/services/dhcp/main.go create mode 100644 internal/app/wwctl/services/dhcp/root.go create mode 100644 internal/app/wwctl/services/root.go diff --git a/README.md b/README.md index 80ac5a2d..d334bdf3 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ sudo make install ``` sudo ./wwctl profile set -K $(uname -r) -V docker://warewulf/centos-8 default +sudo ./wwctl node add [node name] +sudo ./wwctl node set --netdev eth0 -I 192.168.1.10 -M 255.255.255.0 -G 192.168.1.1 -H aa:bb:cc:dd:ee:ff ``` diff --git a/etc/dhcpd.conf b/etc/dhcp/default-dhcpd.conf similarity index 66% rename from etc/dhcpd.conf rename to etc/dhcp/default-dhcpd.conf index 0c3349fc..ea5e9f72 100644 --- a/etc/dhcpd.conf +++ b/etc/dhcp/default-dhcpd.conf @@ -1,4 +1,3 @@ - allow booting; allow bootp; ddns-update-style interim; @@ -13,8 +12,6 @@ option ipxe.no-pxedhcp 1; option architecture-type code 93 = unsigned integer 16; if exists user-class and option user-class = "iPXE" { - #filename "http://192.168.1.1/WW4/ipxe/${mac:hexhyp}"; - #filename "http://192.168.1.1:9873/ipxe?hwaddr=${mac:hexhyp}"; filename "http://192.168.1.1:9873/ipxe/${mac:hexhyp}"; } else { if option architecture-type = 00:0B { @@ -32,23 +29,14 @@ if exists user-class and option user-class = "iPXE" { } } -subnet 192.168.1.0 netmask 255.255.255.0 { - range 192.168.1.10 192.168.1.99; +subnet {{.Ipaddr}} netmask {{.Netmask}} { + range {{.RangeStart}} {{.RangeEnd}}; next-server 192.168.1.1; -} +} - -#subnet 192.168.1.0 netmask 255.255.255.0 { -# not authoritative; -# option subnet-mask 255.255.255.0; -#} - -#group { -# host n0000_localdomain-eth0 { -# option host-name n0000; -# option domain-name "localdomain"; -# hardware ethernet 00:0c:29:c3:bf:42; -# fixed-address 192.168.1.100; -# next-server 192.168.1.1; -# } +{{range .Nodes}} +#host {{.Fqdn}} { +# hardware ethernet {{.NetDevs.eth0.Hwaddr}} +# filed-address {{.NetDevs.eth0.Ipaddr}} #} +{{end}} diff --git a/etc/nodes.conf b/etc/nodes.conf index e28002f1..444d8364 100644 --- a/etc/nodes.conf +++ b/etc/nodes.conf @@ -1,52 +1,87 @@ nodeprofiles: default: comment: "" + vnfs: "" + kernel version: "" kernel args: crashkernel=no quiet -nodegroups: - default: - comment: This is the default group - domain name: cluster01 - profiles: - - default - nodes: - n0000: - hostname: n0000 - netdevs: - eth0: - type: ethernet - hwaddr: 00:0c:29:23:8b:48 - ipaddr: 192.168.1.100 - netmask: 255.255.255.0 - gateway: 192.168.1.1 - ib0: - type: infiniband - hwaddr: aa:bb:cc:dd:ee:a0 - ipaddr: 192.168.10.100 - netmask: 255.255.255.0 - n0001: - hostname: n0001 - ipmi ipaddr: x.x.x.x - netdevs: - eth0: - hwaddr: aa:bb:cc:dd:ee:b0 - ipaddr: 192.168.1.101 - netmask: 255.255.255.0 - gateway: 192.168.1.1 - ib0: - hwaddr: aa:bb:cc:dd:ee:b1 - ipaddr: 192.168.10.100 - netmask: 255.255.255.0 - group_1: - comment: This is the group 1 - domain name: group1 - profiles: - - default - nodes: - n0000: - hostname: n0000 - netdevs: - eth0: - hwaddr: aa:bb:cc:dd:ee:c0 - ipaddr: 192.168.2.100 - netmask: 255.255.255.0 - gateway: 192.168.2.1 + +control: + headnode01: + comment: This is the first control system + ipaddr: 192.168.1.1 + services: + warewulfd: + port: 9873 + secure: true + dhcp: + enabled: true + range start: 192.168.1.100 + range end: 192.168.1.250 + assign static: false + config file: /etc/dhcp/dhcpd.conf + start command: service dhcp start + restart command: killall dhcpd -HUP + enable command: chkconfig dhcp on + tftp: + enabled: true + tftproot: /var/lib/tftproot + start command: service tftp start + restart command: service tftp restart + enable command: chkconfig tftp on + nfs: + enabled: true + config file: /etc/exports + exports: + - /var/warewulf 192.168.1.1/255.255.255.0(ro,no_root_squash) + - /home 192.168.1.1/255.255.255.0(rw,no_root_squash) + start command: service nfs start + restart command: service nfs restart + enable command: chkconfig nfs on + nodegroups: + default: + comment: This is the default group + domain name: cluster01 + profiles: + - default + nodes: + n0000: + hostname: n0000 + netdevs: + eth0: + type: ethernet + hwaddr: 00:0c:29:23:8b:48 + ipaddr: 192.168.1.100 + netmask: 255.255.255.0 + gateway: 192.168.1.1 + ib0: + type: infiniband + hwaddr: aa:bb:cc:dd:ee:a0 + ipaddr: 192.168.10.100 + netmask: 255.255.255.0 + n0001: + hostname: n0001 + ipmi ipaddr: x.x.x.x + netdevs: + eth0: + hwaddr: aa:bb:cc:dd:ee:b0 + ipaddr: 192.168.1.101 + netmask: 255.255.255.0 + gateway: 192.168.1.1 + ib0: + hwaddr: aa:bb:cc:dd:ee:b1 + ipaddr: 192.168.10.100 + netmask: 255.255.255.0 + group_1: + comment: This is the group 1 + domain name: group1 + profiles: + - default + nodes: + n0000: + hostname: n0000 + netdevs: + eth0: + hwaddr: aa:bb:cc:dd:ee:c0 + ipaddr: 192.168.2.100 + netmask: 255.255.255.0 + gateway: 192.168.2.1 diff --git a/internal/app/wwctl/controller/add/main.go b/internal/app/wwctl/controller/add/main.go new file mode 100644 index 00000000..f7231a4a --- /dev/null +++ b/internal/app/wwctl/controller/add/main.go @@ -0,0 +1,29 @@ +package add + +import ( + "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "github.com/spf13/cobra" + "os" +) + +func CobraRunE(cmd *cobra.Command, args []string) error { + + nodeDB, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Failed opening node database: %s\n", err) + os.Exit(1) + } + + for _, c := range args { + err = nodeDB.AddController(c) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + + nodeDB.Persist() + + return nil +} \ No newline at end of file diff --git a/internal/app/wwctl/controller/add/root.go b/internal/app/wwctl/controller/add/root.go new file mode 100644 index 00000000..f26c860d --- /dev/null +++ b/internal/app/wwctl/controller/add/root.go @@ -0,0 +1,23 @@ +package add + +import "github.com/spf13/cobra" + +var ( + baseCmd = &cobra.Command{ + Use: "add", + Short: "Add", + Long: "Add", + RunE: CobraRunE, + Args: cobra.MinimumNArgs(1), + } + SetController string +) + +func init() { + +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/controller/delete/main.go b/internal/app/wwctl/controller/delete/main.go new file mode 100644 index 00000000..4939940a --- /dev/null +++ b/internal/app/wwctl/controller/delete/main.go @@ -0,0 +1,61 @@ +package delete + +import ( + "fmt" + "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "github.com/manifoldco/promptui" + "github.com/spf13/cobra" + "os" +) + +func CobraRunE(cmd *cobra.Command, args []string) error { + var count int + var numNodes int + + nodeDB, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Failed to open node database: %s\n", err) + os.Exit(1) + } + + nodes, err := nodeDB. FindAllNodes() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not load all nodes: %s\n", err) + os.Exit(1) + } + + for _, c := range args { + err := nodeDB.DelController(c) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + } else { + for _, n := range nodes { + if n.Cid.Get() == c { + numNodes ++ + } + } + count ++ + } + } + + if count > 0 { + q := fmt.Sprintf("Are you sure you want to delete %d controllers(s) (%d nodes)", count, numNodes) + + prompt := promptui.Prompt{ + Label: q, + IsConfirm: true, + } + + result, _ := prompt.Run() + + if result == "y" || result == "yes" { + nodeDB.Persist() + } + + } else { + wwlog.Printf(wwlog.INFO, "No controllers found\n") + } + + return nil +} \ No newline at end of file diff --git a/internal/app/wwctl/controller/delete/root.go b/internal/app/wwctl/controller/delete/root.go new file mode 100644 index 00000000..0fc4fdcc --- /dev/null +++ b/internal/app/wwctl/controller/delete/root.go @@ -0,0 +1,23 @@ +package delete + +import "github.com/spf13/cobra" + +var ( + baseCmd = &cobra.Command{ + Use: "delete", + Short: "Delete", + Long: "Delete", + RunE: CobraRunE, + Args: cobra.MinimumNArgs(1), + } + SetController string +) + +func init() { + +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/controller/list/main.go b/internal/app/wwctl/controller/list/main.go new file mode 100644 index 00000000..ff2e1396 --- /dev/null +++ b/internal/app/wwctl/controller/list/main.go @@ -0,0 +1,45 @@ +package list + +import "C" +import ( + "fmt" + "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "github.com/spf13/cobra" + "os" + "reflect" +) + +func CobraRunE(cmd *cobra.Command, args []string) error { + nodeDB, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } + + controllers, err := nodeDB.FindAllControllers() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not find all nodes: %s\n", err) + os.Exit(1) + } + + + if ShowAll == true { + for _, controller := range controllers { + v := reflect.ValueOf(controller) + typeOfS := v.Type() + fmt.Printf("################################################################################\n") + for i := 0; i< v.NumField(); i++ { + fmt.Printf("%-25s %s = %v\n", controller.Id, typeOfS.Field(i).Name, v.Field(i).Interface()) + } + } + } else { + fmt.Printf("%-22s\n", "CONTROLLER NAME") + for _, c := range controllers { + fmt.Printf("%-22s\n", c.Id) + } + } + + + return nil +} \ No newline at end of file diff --git a/internal/app/wwctl/controller/list/root.go b/internal/app/wwctl/controller/list/root.go new file mode 100644 index 00000000..583c8fed --- /dev/null +++ b/internal/app/wwctl/controller/list/root.go @@ -0,0 +1,23 @@ +package list + +import "github.com/spf13/cobra" + +var ( + baseCmd = &cobra.Command{ + Use: "list", + Short: "List", + Long: "List", + RunE: CobraRunE, + } + ShowAll bool +) + +func init() { + baseCmd.PersistentFlags().BoolVarP(&ShowAll, "all", "a", false, "Show all node configurations") + +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/controller/root.go b/internal/app/wwctl/controller/root.go new file mode 100644 index 00000000..31e100f5 --- /dev/null +++ b/internal/app/wwctl/controller/root.go @@ -0,0 +1,30 @@ +package controller + +import ( + "github.com/spf13/cobra" + "github.com/hpcng/warewulf/internal/app/wwctl/controller/add" + "github.com/hpcng/warewulf/internal/app/wwctl/controller/delete" + "github.com/hpcng/warewulf/internal/app/wwctl/controller/list" + "github.com/hpcng/warewulf/internal/app/wwctl/controller/set" + +) + +var ( + baseCmd = &cobra.Command{ + Use: "controller", + Short: "Controller management", + Long: "Management of group settings and power management", + } +) + +func init() { + baseCmd.AddCommand(list.GetCommand()) + baseCmd.AddCommand(set.GetCommand()) + baseCmd.AddCommand(add.GetCommand()) + baseCmd.AddCommand(delete.GetCommand()) +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/controller/set/main.go b/internal/app/wwctl/controller/set/main.go new file mode 100644 index 00000000..4740acfe --- /dev/null +++ b/internal/app/wwctl/controller/set/main.go @@ -0,0 +1,94 @@ +package set + +import ( + "fmt" + "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "github.com/manifoldco/promptui" + "github.com/spf13/cobra" + "os" +) + +func CobraRunE(cmd *cobra.Command, args []string) error { + var err error + var controllers []node.ControllerInfo + + nodeDB, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } + + if err != nil { + wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + os.Exit(1) + } + + if SetAll == true { + var tmp []node.ControllerInfo + tmp, err = nodeDB.FindAllControllers() + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + + for _, c := range tmp { + controllers = append(controllers, c) + } + + } else if len(args) > 0 { + var tmp []node.ControllerInfo + tmp, err = nodeDB.FindAllControllers() + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + + for _, a := range args { + for _, c := range tmp { + if c.Id == a { + controllers = append(controllers, c) + } + } + } + + } else { + cmd.Usage() + os.Exit(1) + } + + for _, c := range controllers { + + if SetIpaddr != "" { + wwlog.Printf(wwlog.VERBOSE, "Controller: %s, Setting IP Addr to: %s\n", c.Id, SetIpaddr) + + c.Ipaddr = SetIpaddr + err := nodeDB.ControllerUpdate(c) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + + } + + if len(controllers) > 0 { + q := fmt.Sprintf("Are you sure you want to modify %d group(s)", len(controllers)) + + prompt := promptui.Prompt{ + Label: q, + IsConfirm: true, + } + + result, _ := prompt.Run() + + if result == "y" || result == "yes" { + nodeDB.Persist() + } + + } else { + fmt.Printf("No controllers found\n") + } + + return nil +} diff --git a/internal/app/wwctl/controller/set/root.go b/internal/app/wwctl/controller/set/root.go new file mode 100644 index 00000000..5f1b5499 --- /dev/null +++ b/internal/app/wwctl/controller/set/root.go @@ -0,0 +1,26 @@ +package set + +import "github.com/spf13/cobra" + +var ( + baseCmd = &cobra.Command{ + Use: "set", + Short: "Set", + Long: "Set", + RunE: CobraRunE, + Args: cobra.MinimumNArgs(1), + } + SetAll bool + SetIpaddr string +) + +func init() { + baseCmd.PersistentFlags().BoolVarP(&SetAll, "all", "a", false, "Set all controllers") + baseCmd.PersistentFlags().StringVarP(&SetIpaddr, "ipaddr", "i", "", "Set the controller's IP address") + +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/group/add/main.go b/internal/app/wwctl/group/add/main.go index ab092f67..8b4bdadb 100644 --- a/internal/app/wwctl/group/add/main.go +++ b/internal/app/wwctl/group/add/main.go @@ -15,7 +15,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } for _, g := range args { - err = nodeDB.AddGroup(g) + err = nodeDB.AddGroup(SetController, g) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) diff --git a/internal/app/wwctl/group/add/root.go b/internal/app/wwctl/group/add/root.go index 35070791..972e1fe0 100644 --- a/internal/app/wwctl/group/add/root.go +++ b/internal/app/wwctl/group/add/root.go @@ -10,13 +10,12 @@ var ( RunE: CobraRunE, Args: cobra.MinimumNArgs(1), } - SetVnfs string - SetKernel string + SetController string ) func init() { - baseCmd.PersistentFlags().StringVarP(&SetVnfs, "vnfs", "V", "", "Set node Virtual Node File System (VNFS)") - baseCmd.PersistentFlags().StringVarP(&SetKernel, "kernel", "K", "", "Set Kernel version for nodes") + baseCmd.PersistentFlags().StringVarP(&SetController, "controller", "c", "default", "Controller to add group to") + } // GetRootCommand returns the root cobra.Command for the application. diff --git a/internal/app/wwctl/group/delete/main.go b/internal/app/wwctl/group/delete/main.go index 71ee3fd4..5e3120c5 100644 --- a/internal/app/wwctl/group/delete/main.go +++ b/internal/app/wwctl/group/delete/main.go @@ -26,12 +26,12 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } for _, g := range args { - err := nodeDB.DelGroup(g) + err := nodeDB.DelGroup(SetController, g) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) } else { for _, n := range nodes { - if n.GroupName.String() == g { + if n.Gid.Get() == g { numNodes ++ } } diff --git a/internal/app/wwctl/group/delete/root.go b/internal/app/wwctl/group/delete/root.go index a4a58522..bb343acd 100644 --- a/internal/app/wwctl/group/delete/root.go +++ b/internal/app/wwctl/group/delete/root.go @@ -9,14 +9,11 @@ var ( Long: "Add a new node group ", RunE: CobraRunE, } - SetVnfs string - SetKernel string - // SetGroupLevel bool + SetController string ) func init() { - baseCmd.PersistentFlags().StringVarP(&SetVnfs, "vnfs", "V", "", "Set node Virtual Node File System (VNFS)") - baseCmd.PersistentFlags().StringVarP(&SetKernel, "kernel", "K", "", "Set Kernel version for nodes") + baseCmd.PersistentFlags().StringVarP(&SetController, "controller", "c", "default", "Controller to add group to") } // GetRootCommand returns the root cobra.Command for the application. diff --git a/internal/app/wwctl/group/list/main.go b/internal/app/wwctl/group/list/main.go index 0d5f88e1..cbe06514 100644 --- a/internal/app/wwctl/group/list/main.go +++ b/internal/app/wwctl/group/list/main.go @@ -34,9 +34,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } } } else { - fmt.Printf("%-22s %-16s %s\n", "GROUP NAME", "DOMAINNAME", "PROFILES") + fmt.Printf("%-22s %-16s %-16s %s\n", "GROUP NAME", "DOMAINNAME", "CONTROLLER", "PROFILES") for _, g := range groups { - fmt.Printf("%-22s %-16s %s\n", g.Id, g.DomainName, strings.Join(g.Profiles, ",")) + fmt.Printf("%-22s %-16s %-16s %s\n", g.Id, g.DomainName, g.Cid, strings.Join(g.Profiles, ",")) } } diff --git a/internal/app/wwctl/node/add/main.go b/internal/app/wwctl/node/add/main.go index ad4d3a49..232ee268 100644 --- a/internal/app/wwctl/node/add/main.go +++ b/internal/app/wwctl/node/add/main.go @@ -16,7 +16,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } for _, a := range args { - err = nodeDB.AddNode(SetGroup, a) + err = nodeDB.AddNode(SetController, SetGroup, a) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) os.Exit(1) diff --git a/internal/app/wwctl/node/add/root.go b/internal/app/wwctl/node/add/root.go index b95a8b90..e394fa72 100644 --- a/internal/app/wwctl/node/add/root.go +++ b/internal/app/wwctl/node/add/root.go @@ -11,10 +11,12 @@ var ( Args: cobra.MinimumNArgs(1), } SetGroup string + SetController string ) func init() { - baseCmd.PersistentFlags().StringVarP(&SetGroup, "group", "g", "default", "Set group to add nodes to") + baseCmd.PersistentFlags().StringVarP(&SetGroup, "group", "g", "default", "Group to add nodes to") + baseCmd.PersistentFlags().StringVarP(&SetController, "controller", "c", "default", "Controller to add nodes to") } // GetRootCommand returns the root cobra.Command for the application. diff --git a/internal/app/wwctl/node/delete/main.go b/internal/app/wwctl/node/delete/main.go index f036e7c4..e20ea7f9 100644 --- a/internal/app/wwctl/node/delete/main.go +++ b/internal/app/wwctl/node/delete/main.go @@ -21,11 +21,11 @@ func CobraRunE(cmd *cobra.Command, args []string) error { nodeList, err := nodeDB.SearchByNameList(args) for _, n := range nodeList { - if SetGroup != "" && SetGroup != n.GroupName.String() { - wwlog.Printf(wwlog.DEBUG, "skipping node of different group: %s/%s\n", n.GroupName, n.Id) + if SetGroup != "" && SetGroup != n.Gid.String() { + wwlog.Printf(wwlog.DEBUG, "skipping node of different group: %s/%s\n", n.Gid, n.Id) continue } - err := nodeDB.DelNode(n.GroupName.String(), n.Id.String()) + err := nodeDB.DelNode(n.Cid.Get(), n.Gid.Get(), n.Id.Get()) if err != nil { wwlog.Printf(wwlog.ERROR, "%s\n", err) } else { diff --git a/internal/app/wwctl/node/delete/root.go b/internal/app/wwctl/node/delete/root.go index ded732bf..9a7b5a7d 100644 --- a/internal/app/wwctl/node/delete/root.go +++ b/internal/app/wwctl/node/delete/root.go @@ -11,11 +11,13 @@ var ( } SetForce string SetGroup string + SetController string ) func init() { baseCmd.PersistentFlags().StringVarP(&SetForce, "force", "f", "", "Force node delete") baseCmd.PersistentFlags().StringVarP(&SetGroup, "group", "g", "default", "Set group to delete nodes from") + baseCmd.PersistentFlags().StringVarP(&SetController, "controller", "c", "default", "Controller to add nodes to") } diff --git a/internal/app/wwctl/node/list/main.go b/internal/app/wwctl/node/list/main.go index 921e8832..ff449667 100644 --- a/internal/app/wwctl/node/list/main.go +++ b/internal/app/wwctl/node/list/main.go @@ -37,7 +37,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { fmt.Printf("################################################################################\n") fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "Id", node.Id.Source(), node.Id.String()) fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "Comment", node.Comment.Source(), node.Comment.String()) - fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "GroupName", node.GroupName.Source(), node.GroupName.String()) + fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "GroupName", node.Gid.Source(), node.Gid.String()) fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "DomainName", node.DomainName.Source(), node.DomainName.String()) fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "Profiles (Group)", "group", strings.Join(node.GroupProfiles, ",")) fmt.Printf("%-20s %-18s %8s: %s\n", node.Fqdn.Get(), "Profiles (Node)", "node", strings.Join(node.Profiles, ",")) @@ -93,7 +93,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { fmt.Println(strings.Repeat("=", 120)) for _, node := range nodes { - fmt.Printf("%-22s %-12s %-26s %-35s %s\n", node.Fqdn.Get(), node.GroupName.String(), node.KernelVersion.String(), node.Vnfs.String(), node.SystemOverlay.String() +"/"+ node.RuntimeOverlay.String()) + fmt.Printf("%-22s %-12s %-26s %-35s %s\n", node.Fqdn.Get(), node.Gid.String(), node.KernelVersion.String(), node.Vnfs.String(), node.SystemOverlay.String() +"/"+ node.RuntimeOverlay.String()) } } else { diff --git a/internal/app/wwctl/node/set/root.go b/internal/app/wwctl/node/set/root.go index 937b6025..2c5a429f 100644 --- a/internal/app/wwctl/node/set/root.go +++ b/internal/app/wwctl/node/set/root.go @@ -38,7 +38,7 @@ func init() { baseCmd.PersistentFlags().StringVarP(&SetIpxe, "ipxe", "P", "", "Set the node's iPXE template name") baseCmd.PersistentFlags().StringVarP(&SetRuntimeOverlay, "runtime", "R", "", "Set the node's runtime overlay") baseCmd.PersistentFlags().StringVarP(&SetSystemOverlay, "system", "S", "", "Set the node's system overlay") - baseCmd.PersistentFlags().StringVarP(&SetHostname, "hostname", "H", "", "Set the node's hostname") + baseCmd.PersistentFlags().StringVarP(&SetHostname, "hostname", "N", "", "Set the node's hostname") baseCmd.PersistentFlags().StringVar(&SetIpmiIpaddr, "ipmi", "", "Set the node's IPMI address") baseCmd.PersistentFlags().StringVar(&SetIpmiUsername, "ipmiuser", "", "Set the node's IPMI username") baseCmd.PersistentFlags().StringVar(&SetIpmiPassword, "ipmipass", "", "Set the node's IPMI password") @@ -50,7 +50,7 @@ func init() { baseCmd.PersistentFlags().StringVarP(&SetIpaddr, "ipaddr", "I", "", "Set the node's network device IP address") baseCmd.PersistentFlags().StringVarP(&SetNetmask, "netmask", "M", "", "Set the node's network device netmask") baseCmd.PersistentFlags().StringVarP(&SetGateway, "gateway", "G", "", "Set the node's network device gateway") - baseCmd.PersistentFlags().StringVarP(&SetHwaddr, "hwaddr", "N", "", "Set the node's network device HW address") + baseCmd.PersistentFlags().StringVarP(&SetHwaddr, "hwaddr", "H", "", "Set the node's network device HW address") baseCmd.PersistentFlags().BoolVar(&SetNetDevDel, "delete", false, "Delete the node's network device") baseCmd.PersistentFlags().BoolVarP(&SetNodeAll, "all", "a", false, "Set all nodes") diff --git a/internal/app/wwctl/overlay/edit/main.go b/internal/app/wwctl/overlay/edit/main.go index 836c96fe..89e08d27 100644 --- a/internal/app/wwctl/overlay/edit/main.go +++ b/internal/app/wwctl/overlay/edit/main.go @@ -69,7 +69,6 @@ func CobraRunE(cmd *cobra.Command, args []string) error { fmt.Fprintf(w, "\n") } - shasum1, err := util.ShaSumFile(overlayFile) if err != nil { wwlog.Printf(wwlog.WARN, "Could not open overlay file for checksum: %s\n", err) @@ -80,7 +79,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { wwlog.Printf(wwlog.ERROR, "Editor process existed with non-zero\n") os.Exit(1) } - wwlog.Printf(wwlog.INFO, "Updated: %s %s\n", args[0], args[1] ) + wwlog.Printf(wwlog.INFO, "Updated: %s %s\n", args[0], args[1]) shasum2, err := util.ShaSumFile(overlayFile) if err != nil { @@ -126,4 +125,3 @@ func CobraRunE(cmd *cobra.Command, args []string) error { return nil } - diff --git a/internal/app/wwctl/profile/set/main.go b/internal/app/wwctl/profile/set/main.go index 548b53c2..8a95673a 100644 --- a/internal/app/wwctl/profile/set/main.go +++ b/internal/app/wwctl/profile/set/main.go @@ -143,7 +143,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } if len(profiles) > 0 { - q := fmt.Sprintf("Are you sure you want to modify %d group(s)", len(profiles)) + q := fmt.Sprintf("Are you sure you want to modify %d profile(s)", len(profiles)) prompt := promptui.Prompt{ Label: q, diff --git a/internal/app/wwctl/root.go b/internal/app/wwctl/root.go index ee52e7dd..05f732f3 100644 --- a/internal/app/wwctl/root.go +++ b/internal/app/wwctl/root.go @@ -1,11 +1,13 @@ package wwctl import ( + "github.com/hpcng/warewulf/internal/app/wwctl/controller" "github.com/hpcng/warewulf/internal/app/wwctl/group" "github.com/hpcng/warewulf/internal/app/wwctl/kernel" "github.com/hpcng/warewulf/internal/app/wwctl/node" "github.com/hpcng/warewulf/internal/app/wwctl/overlay" "github.com/hpcng/warewulf/internal/app/wwctl/profile" + "github.com/hpcng/warewulf/internal/app/wwctl/services" "github.com/hpcng/warewulf/internal/app/wwctl/vnfs" "github.com/hpcng/warewulf/internal/pkg/wwlog" @@ -14,26 +16,29 @@ import ( var ( rootCmd = &cobra.Command{ - Use: "wwctl", - Short: "Warewulf Control", - Long: "Control interface to the Cluster Warewulf Provisioning System.", - PersistentPreRunE: rootPersistentPreRunE, + Use: "wwctl", + Short: "Warewulf Control", + Long: "Control interface to the Cluster Warewulf Provisioning System.", + PersistentPreRunE: rootPersistentPreRunE, } verboseArg bool - debugArg bool + debugArg bool ) func init() { rootCmd.PersistentFlags().BoolVarP(&verboseArg, "verbose", "v", false, "Run with increased verbosity.") rootCmd.PersistentFlags().BoolVarP(&debugArg, "debug", "d", false, "Run with debugging messages enabled.") - rootCmd.AddCommand(overlay.GetCommand()) //rootCmd.AddCommand(build.GetCommand()) + + rootCmd.AddCommand(overlay.GetCommand()) + rootCmd.AddCommand(controller.GetCommand()) rootCmd.AddCommand(vnfs.GetCommand()) rootCmd.AddCommand(node.GetCommand()) rootCmd.AddCommand(kernel.GetCommand()) rootCmd.AddCommand(group.GetCommand()) rootCmd.AddCommand(profile.GetCommand()) + rootCmd.AddCommand(services.GetCommand()) } @@ -51,4 +56,4 @@ func rootPersistentPreRunE(cmd *cobra.Command, args []string) error { wwlog.SetLevel(wwlog.INFO) } return nil -} \ No newline at end of file +} diff --git a/internal/app/wwctl/services/dhcp/main.go b/internal/app/wwctl/services/dhcp/main.go new file mode 100644 index 00000000..88d9b7e5 --- /dev/null +++ b/internal/app/wwctl/services/dhcp/main.go @@ -0,0 +1,109 @@ +package dhcp + +import ( + "fmt" + "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "github.com/spf13/cobra" + "net" + "os" + "text/template" +) + +type dhcpTemplate struct { + Ipaddr string + RangeStart string + RangeEnd string + Netmask string + Nodes []node.NodeInfo +} + +func CobraRunE(cmd *cobra.Command, args []string) error { + + nodeDB, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } + + controllers, err := nodeDB.FindAllControllers() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not find all controllers: %s\n", err) + os.Exit(1) + } + + for _, controller := range controllers { + var d dhcpTemplate + var configured bool + + addrs, err := net.InterfaceAddrs() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not get network interfaces: %s\n", err) + os.Exit(1) + } + + for _, address := range addrs { + if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { + if ipnet.IP.String() == controller.Ipaddr { + mask := ipnet.IP.DefaultMask() + d.Ipaddr = ipnet.IP.String() + d.Netmask = fmt.Sprintf("%d.%d.%d.%d", mask[0], mask[1], mask[2], mask[3]) + d.RangeStart = controller.Services.Dhcp.RangeStart + d.RangeEnd = controller.Services.Dhcp.RangeEnd + configured = true + fmt.Printf("%#v\n", d) + break + } + } + } + + if configured == false { + wwlog.Printf(wwlog.ERROR, "Could not identify this system in the Warewulf configuration by it's IP address\n") + os.Exit(1) + } + + if controller.Services.Dhcp.ConfigFile == "" { + wwlog.Printf(wwlog.ERROR, "Could not locate the DHCP configuration file for this controller\n") + os.Exit(1) + } + + if _, ok := nodeDB.Controllers[controller.Id]; !ok { + wwlog.Printf(wwlog.ERROR, "We should never get here, but since we did, Hello! %s\n", err) + os.Exit(1) + } + + nodes, err := nodeDB.FindAllNodes() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not find all controllers: %s\n", err) + os.Exit(1) + } + + for _, node := range nodes { + d.Nodes = append(d.Nodes, node) + } + + tmpl, err := template.New("default-dhcpd.conf").ParseFiles("/etc/warewulf/dhcp/default-dhcpd.conf") + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + + // w, err := os.OpenFile(controller.Services.Dhcp.ConfigFile, os.O_RDWR|os.O_CREATE, 0640) + // if err != nil { + // wwlog.Printf(wwlog.ERROR, "%s\n", err) + // os.Exit(1) + // } + // defer w.Close() + + err = tmpl.Execute(os.Stdout, d) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + + // Just in case we get here, we've now finished the loop + break + } + + return nil +} diff --git a/internal/app/wwctl/services/dhcp/root.go b/internal/app/wwctl/services/dhcp/root.go new file mode 100644 index 00000000..189f85db --- /dev/null +++ b/internal/app/wwctl/services/dhcp/root.go @@ -0,0 +1,23 @@ +package dhcp + +import ( + "github.com/spf13/cobra" +) + +var ( + baseCmd = &cobra.Command{ + Use: "dhcp", + Short: "DHCP configuration", + Long: "DHCP Config", + RunE: CobraRunE, + } + test bool +) + +func init() { +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/services/root.go b/internal/app/wwctl/services/root.go new file mode 100644 index 00000000..fa6a5c9b --- /dev/null +++ b/internal/app/wwctl/services/root.go @@ -0,0 +1,23 @@ +package services + +import ( + "github.com/hpcng/warewulf/internal/app/wwctl/services/dhcp" + "github.com/spf13/cobra" +) + +var ( + baseCmd = &cobra.Command{ + Use: "services", + Short: "Initialize Warewulf services", + Long: "Warewulf Initialization", + } +) + +func init() { + baseCmd.AddCommand(dhcp.GetCommand()) +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/pkg/node/constructors.go b/internal/pkg/node/constructors.go index 9b143f94..5ac16bd2 100644 --- a/internal/pkg/node/constructors.go +++ b/internal/pkg/node/constructors.go @@ -30,78 +30,80 @@ func New() (nodeYaml, error) { func (self *nodeYaml) FindAllNodes() ([]NodeInfo, error) { var ret []NodeInfo - for groupname, group := range self.NodeGroups { - for nodename, node := range group.Nodes { - var n NodeInfo - var allProfiles []string + for controllername, controller := range self.Controllers { + for groupname, group := range controller.NodeGroups { + for nodename, node := range group.Nodes { + var n NodeInfo + var allProfiles []string - if node.Disabled == true || group.Disabled == true { - wwlog.Printf(wwlog.VERBOSE, "Skipping disabled node: %s/%s\n", groupname, nodename) - continue - } - - n.Id.Set(nodename) - n.Gid.Set(groupname) - n.GroupName.Set(groupname) - n.HostName.Set(node.Hostname) - n.IpmiIpaddr.Set(node.IpmiIpaddr) - n.DomainName.Set(node.DomainName) - n.Vnfs.Set(node.Vnfs) - n.KernelVersion.Set(node.KernelVersion) - n.KernelArgs.Set(node.KernelArgs) - n.Ipxe.Set(node.Ipxe) - n.IpmiUserName.Set(node.IpmiUserName) - n.IpmiPassword.Set(node.IpmiPassword) - n.SystemOverlay.Set(node.SystemOverlay) - n.RuntimeOverlay.Set(node.RuntimeOverlay) - - n.DomainName.SetGroup(group.DomainName) - n.Vnfs.SetGroup(group.Vnfs) - n.KernelVersion.SetGroup(group.KernelVersion) - n.KernelArgs.SetGroup(group.KernelArgs) - n.Ipxe.SetGroup(group.Ipxe) - n.IpmiUserName.SetGroup(group.IpmiUserName) - n.IpmiPassword.SetGroup(group.IpmiPassword) - n.SystemOverlay.SetGroup(group.SystemOverlay) - n.RuntimeOverlay.SetGroup(group.RuntimeOverlay) - - n.RuntimeOverlay.SetDefault("default") - n.SystemOverlay.SetDefault("default") - n.Ipxe.SetDefault("default") - n.KernelArgs.SetDefault("crashkernel=no quiet") - - n.GroupProfiles = group.Profiles - n.Profiles = node.Profiles - - allProfiles = append(allProfiles, group.Profiles...) - allProfiles = append(allProfiles, node.Profiles...) - - for _, p := range allProfiles { - if _, ok := self.NodeProfiles[p]; !ok { - wwlog.Printf(wwlog.WARN, "Profile not found for node '%s': %s\n", nodename, p) + if node.Disabled == true || group.Disabled == true { + wwlog.Printf(wwlog.VERBOSE, "Skipping disabled node: %s/%s\n", groupname, nodename) continue } - n.DomainName.SetProfile(self.NodeProfiles[p].DomainName) - n.Vnfs.SetProfile(self.NodeProfiles[p].Vnfs) - n.KernelVersion.SetProfile(self.NodeProfiles[p].KernelVersion) - n.KernelArgs.SetProfile(self.NodeProfiles[p].KernelArgs) - n.Ipxe.SetProfile(self.NodeProfiles[p].Ipxe) - n.IpmiUserName.SetProfile(self.NodeProfiles[p].IpmiUserName) - n.IpmiPassword.SetProfile(self.NodeProfiles[p].IpmiPassword) - n.SystemOverlay.SetProfile(self.NodeProfiles[p].SystemOverlay) - n.RuntimeOverlay.SetProfile(self.NodeProfiles[p].RuntimeOverlay) + n.Id.Set(nodename) + n.Gid.Set(groupname) + n.Cid.Set(controllername) + n.HostName.Set(node.Hostname) + n.IpmiIpaddr.Set(node.IpmiIpaddr) + n.DomainName.Set(node.DomainName) + n.Vnfs.Set(node.Vnfs) + n.KernelVersion.Set(node.KernelVersion) + n.KernelArgs.Set(node.KernelArgs) + n.Ipxe.Set(node.Ipxe) + n.IpmiUserName.Set(node.IpmiUserName) + n.IpmiPassword.Set(node.IpmiPassword) + n.SystemOverlay.Set(node.SystemOverlay) + n.RuntimeOverlay.Set(node.RuntimeOverlay) + + n.DomainName.SetGroup(group.DomainName) + n.Vnfs.SetGroup(group.Vnfs) + n.KernelVersion.SetGroup(group.KernelVersion) + n.KernelArgs.SetGroup(group.KernelArgs) + n.Ipxe.SetGroup(group.Ipxe) + n.IpmiUserName.SetGroup(group.IpmiUserName) + n.IpmiPassword.SetGroup(group.IpmiPassword) + n.SystemOverlay.SetGroup(group.SystemOverlay) + n.RuntimeOverlay.SetGroup(group.RuntimeOverlay) + + n.RuntimeOverlay.SetDefault("default") + n.SystemOverlay.SetDefault("default") + n.Ipxe.SetDefault("default") + n.KernelArgs.SetDefault("crashkernel=no quiet") + + n.GroupProfiles = group.Profiles + n.Profiles = node.Profiles + + allProfiles = append(allProfiles, group.Profiles...) + allProfiles = append(allProfiles, node.Profiles...) + + for _, p := range allProfiles { + if _, ok := self.NodeProfiles[p]; !ok { + wwlog.Printf(wwlog.WARN, "Profile not found for node '%s': %s\n", nodename, p) + continue + } + + n.DomainName.SetProfile(self.NodeProfiles[p].DomainName) + n.Vnfs.SetProfile(self.NodeProfiles[p].Vnfs) + n.KernelVersion.SetProfile(self.NodeProfiles[p].KernelVersion) + n.KernelArgs.SetProfile(self.NodeProfiles[p].KernelArgs) + n.Ipxe.SetProfile(self.NodeProfiles[p].Ipxe) + n.IpmiUserName.SetProfile(self.NodeProfiles[p].IpmiUserName) + n.IpmiPassword.SetProfile(self.NodeProfiles[p].IpmiPassword) + n.SystemOverlay.SetProfile(self.NodeProfiles[p].SystemOverlay) + n.RuntimeOverlay.SetProfile(self.NodeProfiles[p].RuntimeOverlay) + } + + if n.DomainName.Defined() == true { + n.Fqdn.Set(node.Hostname + "." + n.DomainName.Get()) + } else { + n.Fqdn.Set(node.Hostname) + } + + n.NetDevs = node.NetDevs + + ret = append(ret, n) } - - if n.DomainName.Defined() == true { - n.Fqdn.Set(node.Hostname +"."+ n.DomainName.Get()) - } else { - n.Fqdn.Set(node.Hostname) - } - - n.NetDevs = node.NetDevs - - ret = append(ret, n) } } @@ -111,25 +113,76 @@ func (self *nodeYaml) FindAllNodes() ([]NodeInfo, error) { func (self *nodeYaml) FindAllGroups() ([]GroupInfo, error) { var ret []GroupInfo - for groupname, group := range self.NodeGroups { - var g GroupInfo + for controllername, controller := range self.Controllers { + for groupname, group := range controller.NodeGroups { + var g GroupInfo - g.Id = groupname - g.DomainName = group.DomainName - g.Comment = group.Comment - g.Vnfs = group.Vnfs - g.KernelVersion = group.KernelVersion - g.KernelArgs = group.KernelArgs - g.IpmiPassword = group.IpmiPassword - g.IpmiUserName = group.IpmiUserName - g.SystemOverlay = group.SystemOverlay - g.RuntimeOverlay = group.RuntimeOverlay + g.Id = groupname + g.Cid = controllername + g.DomainName = group.DomainName + g.Comment = group.Comment + g.Vnfs = group.Vnfs + g.KernelVersion = group.KernelVersion + g.KernelArgs = group.KernelArgs + g.IpmiPassword = group.IpmiPassword + g.IpmiUserName = group.IpmiUserName + g.SystemOverlay = group.SystemOverlay + g.RuntimeOverlay = group.RuntimeOverlay - g.Profiles = group.Profiles + g.Profiles = group.Profiles + + // TODO: Validate or die on all inputs + + ret = append(ret, g) + } + } + return ret, nil +} + +func (self *nodeYaml) FindAllControllers() ([]ControllerInfo, error) { + var ret []ControllerInfo + + for controllername, controller := range self.Controllers { + var c ControllerInfo + + c.Id = controllername + c.Ipaddr = controller.Ipaddr + c.Services = struct { + Warewulfd struct { + Port string + Secure string + StartCmd string + RestartCmd string + EnableCmd string + } + Dhcp struct { + Enabled bool + RangeStart string + RangeEnd string + ConfigFile string + StartCmd string + RestartCmd string + EnableCmd string + } + Tftp struct { + Enabled bool + TftpRoot string + StartCmd string + RestartCmd string + EnableCmd string + } + Nfs struct { + Enabled bool + Exports []string + StartCmd string + RestartCmd string + EnableCmd string + } + }(controller.Services) // TODO: Validate or die on all inputs - ret = append(ret, g) + ret = append(ret, c) } return ret, nil } @@ -159,8 +212,6 @@ func (self *nodeYaml) FindAllProfiles() ([]ProfileInfo, error) { return ret, nil } - - func (self *nodeYaml) FindByHwaddr(hwa string) (NodeInfo, error) { var ret NodeInfo @@ -193,13 +244,6 @@ func (self *nodeYaml) FindByIpaddr(ipaddr string) (NodeInfo, error) { return ret, errors.New("No nodes found with IP Addr: " + ipaddr) } - - - - - - - func (nodes *nodeYaml) SearchByName(search string) ([]NodeInfo, error) { var ret []NodeInfo diff --git a/internal/pkg/node/datastructure.go b/internal/pkg/node/datastructure.go index 7e23a72e..fed2145c 100644 --- a/internal/pkg/node/datastructure.go +++ b/internal/pkg/node/datastructure.go @@ -6,127 +6,212 @@ import ( "os" ) +/****** + * YAML data representations + ******/ + type nodeYaml struct { - NodeProfiles map[string]*ProfileConf - NodeGroups map[string]*GroupConf + NodeProfiles map[string]*ProfileConf + Controllers map[string]*ControllerConf `yaml:"control"` } type ProfileConf struct { - Comment string `yaml:"comment"` - Vnfs string `yaml:"vnfs,omitempty"` - Ipxe string `yaml:"ipxe template,omitempty"` - KernelVersion string `yaml:"kernel version,omitempty"` - KernelArgs string `yaml:"kernel args,omitempty"` - IpmiUserName string `yaml:"ipmi username,omitempty"` - IpmiPassword string `yaml:"ipmi password,omitempty"` - DomainName string `yaml:"domain name,omitempty"` - RuntimeOverlay string `yaml:"runtime overlay files,omitempty"` - SystemOverlay string `yaml:"system overlay files,omitempty"` + Comment string `yaml:"comment"` + Vnfs string `yaml:"vnfs,omitempty"` + Ipxe string `yaml:"ipxe template,omitempty"` + KernelVersion string `yaml:"kernel version,omitempty"` + KernelArgs string `yaml:"kernel args,omitempty"` + IpmiUserName string `yaml:"ipmi username,omitempty"` + IpmiPassword string `yaml:"ipmi password,omitempty"` + DomainName string `yaml:"domain name,omitempty"` + RuntimeOverlay string `yaml:"runtime overlay files,omitempty"` + SystemOverlay string `yaml:"system overlay files,omitempty"` +} + +type ControllerConf struct { + Comment string `yaml:"comment"` + Ipaddr string `yaml:"ipaddr"` + Services struct { + Warewulfd struct { + Port string `yaml:"port"` + Secure string `yaml:"secure,omitempty"` + StartCmd string `yaml:"start command,omitempty"` + RestartCmd string `yaml:"restart command,omitempty"` + EnableCmd string `yaml:"enable command,omitempty"` + } `yaml:"warewulf"` + Dhcp struct { + Enabled bool `yaml:"enabled,omitempty"` + RangeStart string `yaml:"range start,omitempty"` + RangeEnd string `yaml:"range end,omitempty"` + ConfigFile string `yaml:"config file,omitempty"` + StartCmd string `yaml:"start command,omitempty"` + RestartCmd string `yaml:"restart command,omitempty"` + EnableCmd string `yaml:"enable command,omitempty"` + } `yaml:"dhcp,omitempty"` + Tftp struct { + Enabled bool `yaml:"enabled,omitempty"` + TftpRoot string `yaml:"tftp root,omitempty"` + StartCmd string `yaml:"start command,omitempty"` + RestartCmd string `yaml:"restart command,omitempty"` + EnableCmd string `yaml:"enable command,omitempty"` + } `yaml:"tftp,omitempty"` + Nfs struct { + Enabled bool `yaml:"enabled,omitempty"` + Exports []string `yaml:"exports,omitempty"` + StartCmd string `yaml:"start command,omitempty"` + RestartCmd string `yaml:"restart command,omitempty"` + EnableCmd string `yaml:"enable command,omitempty"` + } `yaml:"nfs,omitempty"` + } `yaml:"services"` + NodeGroups map[string]*GroupConf } type GroupConf struct { - Comment string `yaml:"comment"` - Disabled bool `yaml:"disabled,omitempty"` - DomainName string `yaml:"domain name"` - Vnfs string `yaml:"vnfs,omitempty"` - Ipxe string `yaml:"ipxe template,omitempty"` - KernelVersion string `yaml:"kernel version,omitempty"` - KernelArgs string `yaml:"kernel args,omitempty"` - IpmiUserName string `yaml:"ipmi username,omitempty"` - IpmiPassword string `yaml:"ipmi password,omitempty"` - RuntimeOverlay string `yaml:"runtime overlay files,omitempty"` - SystemOverlay string `yaml:"system overlay files,omitempty"` - Profiles []string `yaml:"profiles,omitempty"` - Nodes map[string]*NodeConf + Comment string `yaml:"comment"` + Disabled bool `yaml:"disabled,omitempty"` + DomainName string `yaml:"domain name"` + Vnfs string `yaml:"vnfs,omitempty"` + Ipxe string `yaml:"ipxe template,omitempty"` + KernelVersion string `yaml:"kernel version,omitempty"` + KernelArgs string `yaml:"kernel args,omitempty"` + IpmiUserName string `yaml:"ipmi username,omitempty"` + IpmiPassword string `yaml:"ipmi password,omitempty"` + RuntimeOverlay string `yaml:"runtime overlay files,omitempty"` + SystemOverlay string `yaml:"system overlay files,omitempty"` + Profiles []string `yaml:"profiles,omitempty"` + Nodes map[string]*NodeConf } type NodeConf struct { - Comment string `yaml:"comment,omitempty"` - Disabled bool `yaml:"disabled,omitempty"` - Hostname string `yaml:"hostname,omitempty"` - DomainName string `yaml:"domain name,omitempty"` - Vnfs string `yaml:"vnfs,omitempty"` - Ipxe string `yaml:"ipxe template,omitempty"` - KernelVersion string `yaml:"kernel version,omitempty"` - KernelArgs string `yaml:"kernel args,omitempty"` - IpmiUserName string `yaml:"ipmi username,omitempty"` - IpmiPassword string `yaml:"ipmi password,omitempty"` - IpmiIpaddr string `yaml:"ipmi ipaddr,omitempty"` - RuntimeOverlay string `yaml:"runtime overlay files,omitempty"` - SystemOverlay string `yaml:"system overlay files,omitempty"` - Profiles []string `yaml:"profiles,omitempty"` - NetDevs map[string]*NetDevs + Comment string `yaml:"comment,omitempty"` + Disabled bool `yaml:"disabled,omitempty"` + Hostname string `yaml:"hostname,omitempty"` + DomainName string `yaml:"domain name,omitempty"` + Vnfs string `yaml:"vnfs,omitempty"` + Ipxe string `yaml:"ipxe template,omitempty"` + KernelVersion string `yaml:"kernel version,omitempty"` + KernelArgs string `yaml:"kernel args,omitempty"` + IpmiUserName string `yaml:"ipmi username,omitempty"` + IpmiPassword string `yaml:"ipmi password,omitempty"` + IpmiIpaddr string `yaml:"ipmi ipaddr,omitempty"` + RuntimeOverlay string `yaml:"runtime overlay files,omitempty"` + SystemOverlay string `yaml:"system overlay files,omitempty"` + Profiles []string `yaml:"profiles,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 string `yaml:"type,omitempty"` + Hwaddr string + Ipaddr string + Netmask string + Gateway string `yaml:"gateway,omitempty"` } +/****** + * Code internal data representations + ******/ + type NodeInfoEntry struct { - value string - profile string - group string - def string + value string + profile string + group string + controller string + def string } type NodeInfo struct { - Id NodeInfoEntry - Gid NodeInfoEntry - Uid NodeInfoEntry - Comment NodeInfoEntry - GroupName NodeInfoEntry - HostName NodeInfoEntry - Fqdn NodeInfoEntry - DomainName NodeInfoEntry - Vnfs NodeInfoEntry - Ipxe NodeInfoEntry - KernelVersion NodeInfoEntry - KernelArgs NodeInfoEntry - IpmiIpaddr NodeInfoEntry - IpmiUserName NodeInfoEntry - IpmiPassword NodeInfoEntry - RuntimeOverlay NodeInfoEntry - SystemOverlay NodeInfoEntry - Profiles []string - GroupProfiles []string - NetDevs map[string]*NetDevs + Id NodeInfoEntry + Gid NodeInfoEntry + Cid NodeInfoEntry + Comment NodeInfoEntry + HostName NodeInfoEntry + Fqdn NodeInfoEntry + DomainName NodeInfoEntry + Vnfs NodeInfoEntry + Ipxe NodeInfoEntry + KernelVersion NodeInfoEntry + KernelArgs NodeInfoEntry + IpmiIpaddr NodeInfoEntry + IpmiUserName NodeInfoEntry + IpmiPassword NodeInfoEntry + RuntimeOverlay NodeInfoEntry + SystemOverlay NodeInfoEntry + Profiles []string + GroupProfiles []string + NetDevs map[string]*NetDevs +} + +type ControllerInfo struct { + Id string + Comment string + Ipaddr string + Fqdn string + DomainName string + Services struct { + Warewulfd struct { + Port string + Secure string + StartCmd string + RestartCmd string + EnableCmd string + } + Dhcp struct { + Enabled bool + RangeStart string + RangeEnd string + ConfigFile string + StartCmd string + RestartCmd string + EnableCmd string + } + Tftp struct { + Enabled bool + TftpRoot string + StartCmd string + RestartCmd string + EnableCmd string + } + Nfs struct { + Enabled bool + Exports []string + StartCmd string + RestartCmd string + EnableCmd string + } + } } type GroupInfo struct { - Id string - Comment string - Vnfs string - Ipxe string - KernelVersion string - KernelArgs string - IpmiUserName string - IpmiPassword string - DomainName string - RuntimeOverlay string - SystemOverlay string - Profiles []string + Id string + Cid string + Comment string + Vnfs string + Ipxe string + KernelVersion string + KernelArgs string + IpmiUserName string + IpmiPassword string + DomainName string + RuntimeOverlay string + SystemOverlay string + Profiles []string } type ProfileInfo struct { - Id string - Comment string - Vnfs string - Ipxe string - KernelVersion string - KernelArgs string - IpmiUserName string - IpmiPassword string - DomainName string - RuntimeOverlay string - SystemOverlay string + Id string + Comment string + Vnfs string + Ipxe string + KernelVersion string + KernelArgs string + IpmiUserName string + IpmiPassword string + DomainName string + RuntimeOverlay string + SystemOverlay string } - - const ConfigFile = "/etc/warewulf/nodes.conf" func init() { diff --git a/internal/pkg/node/methods.go b/internal/pkg/node/methods.go index 8ccbb6f5..011b9026 100644 --- a/internal/pkg/node/methods.go +++ b/internal/pkg/node/methods.go @@ -14,6 +14,9 @@ func (self *NodeInfoEntry) String() string { if self.profile != "" { return self.profile } + if self.controller != "" { + return self.controller + } if self.def != "" { return self.def } @@ -30,6 +33,9 @@ func (self *NodeInfoEntry) Source() string { if self.profile != "" { return "profile" } + if self.controller != "" { + return "controller" + } if self.def != "" { return "default" } @@ -46,6 +52,9 @@ func (self *NodeInfoEntry) Get() string { if self.profile != "" { return self.profile } + if self.controller != "" { + return self.controller + } if self.def != "" { return self.def } @@ -81,6 +90,13 @@ func (self *NodeInfoEntry) SetProfile(value string) { self.profile = value } +func (self *NodeInfoEntry) SetController(value string) { + if value == "" { + return + } + self.controller = value +} + func (self *NodeInfoEntry) Set(value string) { if value == "" { return diff --git a/internal/pkg/node/modifiers.go b/internal/pkg/node/modifiers.go index 870e69a1..094ab51c 100644 --- a/internal/pkg/node/modifiers.go +++ b/internal/pkg/node/modifiers.go @@ -14,64 +14,79 @@ import ( * ****/ -func (self *nodeYaml) AddNode(groupID string, nodeID string) error { +func (self *nodeYaml) AddNode(controllerID string, groupID string, nodeID string) error { var node NodeConf wwlog.Printf(wwlog.VERBOSE, "Adding new node: %s/%s\n", groupID, nodeID) - if _, ok := self.NodeGroups[groupID]; !ok { + if _, ok := self.Controllers[controllerID]; ! ok { + return errors.New("Controller does not exist: " + controllerID) + } + + if _, ok := self.Controllers[controllerID].NodeGroups[groupID]; ! ok { return errors.New("Group does not exist: " + groupID) } - if _, ok := self.NodeGroups[groupID].Nodes[groupID]; ok { + if _, ok := self.Controllers[controllerID].NodeGroups[groupID].Nodes[groupID]; ok { return errors.New("Nodename already exists in group: " + nodeID) } - self.NodeGroups[groupID].Nodes[nodeID] = &node - self.NodeGroups[groupID].Nodes[nodeID].Hostname = nodeID + self.Controllers[controllerID].NodeGroups[groupID].Nodes[nodeID] = &node + self.Controllers[controllerID].NodeGroups[groupID].Nodes[nodeID].Hostname = nodeID return nil } -func (self *nodeYaml) DelNode(groupID string, nodeID string) error { +func (self *nodeYaml) DelNode(controllerID string, groupID string, nodeID string) error { - if _, ok := self.NodeGroups[groupID]; !ok { - return errors.New("Group '" + groupID + "' was not found") + if _, ok := self.Controllers[controllerID]; ! ok { + return errors.New("Controller does not exist: " + controllerID) } - if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; !ok { - return errors.New("Node '" + nodeID + "' was not found in group '" + groupID + "'") + + if _, ok := self.Controllers[controllerID].NodeGroups[groupID]; ! ok { + return errors.New("Group does not exist: " + groupID) + } + + if _, ok := self.Controllers[controllerID].NodeGroups[groupID].Nodes[groupID]; ok { + return errors.New("Nodename does not exist in group: " + nodeID) } wwlog.Printf(wwlog.VERBOSE, "Deleting node network device: %s/%s\n", groupID, nodeID) - delete(self.NodeGroups[groupID].Nodes, nodeID) + delete(self.Controllers[controllerID].NodeGroups[groupID].Nodes, nodeID) return nil } func(self *nodeYaml) NodeUpdate(node NodeInfo) error { + controllerID := node.Cid.Get() groupID := node.Gid.Get() nodeID := node.Id.Get() - if _, ok := self.NodeGroups[groupID]; !ok { - return errors.New("Group '" + groupID + "' was not found") - } - if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; !ok { - return errors.New("Node '" + nodeID + "' was not found in group '" + groupID + "'") + if _, ok := self.Controllers[controllerID]; ! ok { + return errors.New("Controller does not exist: " + controllerID) } - self.NodeGroups[groupID].Nodes[nodeID].Hostname = node.HostName.GetReal() - self.NodeGroups[groupID].Nodes[nodeID].Vnfs = node.Vnfs.GetReal() - self.NodeGroups[groupID].Nodes[nodeID].DomainName = node.DomainName.GetReal() - self.NodeGroups[groupID].Nodes[nodeID].Ipxe = node.Ipxe.GetReal() - self.NodeGroups[groupID].Nodes[nodeID].KernelVersion = node.KernelVersion.GetReal() - self.NodeGroups[groupID].Nodes[nodeID].KernelArgs = node.KernelArgs.GetReal() - self.NodeGroups[groupID].Nodes[nodeID].IpmiIpaddr = node.IpmiIpaddr.GetReal() - self.NodeGroups[groupID].Nodes[nodeID].IpmiUserName = node.IpmiUserName.GetReal() - self.NodeGroups[groupID].Nodes[nodeID].IpmiPassword = node.IpmiPassword.GetReal() - self.NodeGroups[groupID].Nodes[nodeID].RuntimeOverlay = node.RuntimeOverlay.GetReal() - self.NodeGroups[groupID].Nodes[nodeID].SystemOverlay = node.SystemOverlay.GetReal() - self.NodeGroups[groupID].Nodes[nodeID].Profiles = node.Profiles - self.NodeGroups[groupID].Nodes[nodeID].NetDevs = node.NetDevs + if _, ok := self.Controllers[controllerID].NodeGroups[groupID]; ! ok { + return errors.New("Group does not exist: " + groupID) + } + + if _, ok := self.Controllers[controllerID].NodeGroups[groupID].Nodes[groupID]; ! ok { + return errors.New("Nodename does not exist in group: " + nodeID) + } + + self.Controllers[controllerID].NodeGroups[groupID].Nodes[nodeID].Hostname = node.HostName.GetReal() + self.Controllers[controllerID].NodeGroups[groupID].Nodes[nodeID].Vnfs = node.Vnfs.GetReal() + self.Controllers[controllerID].NodeGroups[groupID].Nodes[nodeID].DomainName = node.DomainName.GetReal() + self.Controllers[controllerID].NodeGroups[groupID].Nodes[nodeID].Ipxe = node.Ipxe.GetReal() + self.Controllers[controllerID].NodeGroups[groupID].Nodes[nodeID].KernelVersion = node.KernelVersion.GetReal() + self.Controllers[controllerID].NodeGroups[groupID].Nodes[nodeID].KernelArgs = node.KernelArgs.GetReal() + self.Controllers[controllerID].NodeGroups[groupID].Nodes[nodeID].IpmiIpaddr = node.IpmiIpaddr.GetReal() + self.Controllers[controllerID].NodeGroups[groupID].Nodes[nodeID].IpmiUserName = node.IpmiUserName.GetReal() + self.Controllers[controllerID].NodeGroups[groupID].Nodes[nodeID].IpmiPassword = node.IpmiPassword.GetReal() + self.Controllers[controllerID].NodeGroups[groupID].Nodes[nodeID].RuntimeOverlay = node.RuntimeOverlay.GetReal() + self.Controllers[controllerID].NodeGroups[groupID].Nodes[nodeID].SystemOverlay = node.SystemOverlay.GetReal() + self.Controllers[controllerID].NodeGroups[groupID].Nodes[nodeID].Profiles = node.Profiles + self.Controllers[controllerID].NodeGroups[groupID].Nodes[nodeID].NetDevs = node.NetDevs return nil } @@ -84,51 +99,140 @@ func(self *nodeYaml) NodeUpdate(node NodeInfo) error { * ****/ -func (self *nodeYaml) AddGroup(groupID string) error { +func (self *nodeYaml) AddGroup(controllerID string, groupID string) error { var group GroupConf wwlog.Printf(wwlog.VERBOSE, "Adding new group: %s/%s\n", groupID) - if _, ok := self.NodeGroups[groupID]; ok { - return errors.New("Group name already exists: " + groupID) + if _, ok := self.Controllers[controllerID]; ! ok { + return errors.New("Controller does not exist: " + controllerID) } - self.NodeGroups[groupID] = &group - self.NodeGroups[groupID].DomainName = groupID - self.NodeGroups[groupID].Profiles = []string{"default"} + if _, ok := self.Controllers[controllerID].NodeGroups[groupID]; ok { + return errors.New("Group already exists: " + groupID) + } + + self.Controllers[controllerID].NodeGroups[groupID] = &group + self.Controllers[controllerID].NodeGroups[groupID].DomainName = groupID + self.Controllers[controllerID].NodeGroups[groupID].Profiles = []string{"default"} return nil } -func (self *nodeYaml) DelGroup(groupID string) error { - if _, ok := self.NodeGroups[groupID]; !ok { +func (self *nodeYaml) DelGroup(controllerID string, groupID string) error { - return errors.New("Group '" + groupID + "' was not found") + if _, ok := self.Controllers[controllerID]; ! ok { + return errors.New("Controller does not exist: " + controllerID) + } + + if _, ok := self.Controllers[controllerID].NodeGroups[groupID]; ! ok { + return errors.New("Group does not exist: " + groupID) } wwlog.Printf(wwlog.VERBOSE, "Deleting group: %s\n", groupID) - delete(self.NodeGroups, groupID) + delete(self.Controllers[controllerID].NodeGroups, groupID) return nil } func(self *nodeYaml) GroupUpdate(group GroupInfo) error { + controllerID := group.Cid groupID := group.Id - if _, ok := self.NodeGroups[groupID]; !ok { - return errors.New("Group '" + groupID + "' was not found") + if _, ok := self.Controllers[controllerID]; ! ok { + return errors.New("Controller does not exist: " + controllerID) } - self.NodeGroups[groupID].DomainName = group.DomainName - self.NodeGroups[groupID].Vnfs = group.Vnfs - self.NodeGroups[groupID].KernelVersion = group.KernelVersion - self.NodeGroups[groupID].KernelArgs = group.KernelArgs - self.NodeGroups[groupID].Ipxe = group.Ipxe - self.NodeGroups[groupID].IpmiUserName = group.IpmiUserName - self.NodeGroups[groupID].IpmiPassword = group.IpmiPassword - self.NodeGroups[groupID].RuntimeOverlay = group.RuntimeOverlay - self.NodeGroups[groupID].SystemOverlay = group.SystemOverlay - self.NodeGroups[groupID].Profiles = group.Profiles + if _, ok := self.Controllers[controllerID].NodeGroups[groupID]; ! ok { + return errors.New("Group does not exist: " + groupID) + } + + self.Controllers[controllerID].NodeGroups[groupID].DomainName = group.DomainName + self.Controllers[controllerID].NodeGroups[groupID].Vnfs = group.Vnfs + self.Controllers[controllerID].NodeGroups[groupID].KernelVersion = group.KernelVersion + self.Controllers[controllerID].NodeGroups[groupID].KernelArgs = group.KernelArgs + self.Controllers[controllerID].NodeGroups[groupID].Ipxe = group.Ipxe + self.Controllers[controllerID].NodeGroups[groupID].IpmiUserName = group.IpmiUserName + self.Controllers[controllerID].NodeGroups[groupID].IpmiPassword = group.IpmiPassword + self.Controllers[controllerID].NodeGroups[groupID].RuntimeOverlay = group.RuntimeOverlay + self.Controllers[controllerID].NodeGroups[groupID].SystemOverlay = group.SystemOverlay + self.Controllers[controllerID].NodeGroups[groupID].Profiles = group.Profiles + + return nil +} + + + +/**** + * + * CONTROLLER MODIFIERS + * +****/ + +func (self *nodeYaml) AddController(controllerID string) error { + var controller ControllerConf + var group GroupConf + + wwlog.Printf(wwlog.VERBOSE, "Adding new controller: %s/%s\n", controllerID) + + if _, ok := self.Controllers[controllerID]; ok { + return errors.New("Controller already exists: " + controllerID) + } + + self.Controllers[controllerID] = &controller + self.Controllers[controllerID].NodeGroups = make(map[string]*GroupConf) + self.Controllers[controllerID].NodeGroups["default"] = &group + + return nil +} + +func (self *nodeYaml) DelController(controllerID string) error { + + if _, ok := self.Controllers[controllerID]; ! ok { + return errors.New("Controller does not exist: " + controllerID) + } + + wwlog.Printf(wwlog.VERBOSE, "Deleting controller: %s\n", controllerID) + delete(self.Controllers, controllerID) + + return nil +} + +func(self *nodeYaml) ControllerUpdate(controller ControllerInfo) error { + controllerID := controller.Id + + if _, ok := self.Controllers[controllerID]; ! ok { + return errors.New("Controller does not exist: " + controllerID) + } + + self.Controllers[controllerID].Ipaddr = controller.Ipaddr + self.Controllers[controllerID].Comment = controller.Comment + + self.Controllers[controllerID].Services.Warewulfd.Port = controller.Services.Warewulfd.Port + self.Controllers[controllerID].Services.Warewulfd.Secure = controller.Services.Warewulfd.Secure + self.Controllers[controllerID].Services.Warewulfd.StartCmd = controller.Services.Warewulfd.StartCmd + self.Controllers[controllerID].Services.Warewulfd.RestartCmd = controller.Services.Warewulfd.RestartCmd + self.Controllers[controllerID].Services.Warewulfd.EnableCmd = controller.Services.Warewulfd.EnableCmd + + self.Controllers[controllerID].Services.Dhcp.Enabled = controller.Services.Dhcp.Enabled + self.Controllers[controllerID].Services.Dhcp.ConfigFile = controller.Services.Dhcp.ConfigFile + self.Controllers[controllerID].Services.Dhcp.RangeStart = controller.Services.Dhcp.RangeStart + self.Controllers[controllerID].Services.Dhcp.RangeEnd = controller.Services.Dhcp.RangeEnd + self.Controllers[controllerID].Services.Dhcp.StartCmd = controller.Services.Dhcp.StartCmd + self.Controllers[controllerID].Services.Dhcp.RestartCmd = controller.Services.Dhcp.RestartCmd + self.Controllers[controllerID].Services.Dhcp.EnableCmd = controller.Services.Dhcp.EnableCmd + + self.Controllers[controllerID].Services.Nfs.Enabled = controller.Services.Nfs.Enabled + self.Controllers[controllerID].Services.Nfs.Exports = controller.Services.Nfs.Exports + self.Controllers[controllerID].Services.Nfs.StartCmd = controller.Services.Nfs.StartCmd + self.Controllers[controllerID].Services.Nfs.RestartCmd = controller.Services.Nfs.RestartCmd + self.Controllers[controllerID].Services.Nfs.EnableCmd = controller.Services.Nfs.EnableCmd + + self.Controllers[controllerID].Services.Tftp.Enabled = controller.Services.Tftp.Enabled + self.Controllers[controllerID].Services.Tftp.TftpRoot = controller.Services.Tftp.TftpRoot + self.Controllers[controllerID].Services.Tftp.StartCmd = controller.Services.Tftp.StartCmd + self.Controllers[controllerID].Services.Tftp.RestartCmd = controller.Services.Tftp.RestartCmd + self.Controllers[controllerID].Services.Tftp.EnableCmd = controller.Services.Tftp.EnableCmd return nil } diff --git a/internal/pkg/overlay/overlay.go b/internal/pkg/overlay/overlay.go index 82e6ab73..f2346d68 100644 --- a/internal/pkg/overlay/overlay.go +++ b/internal/pkg/overlay/overlay.go @@ -18,11 +18,14 @@ import ( ) type TemplateStruct struct { - Fqdn string - Hostname string - Groupname string - Vnfs string - Netdev map[string]*node.NetDevs + Self struct { + Fqdn string + Hostname string + GroupName string + Vnfs string + NetDevs map[string]*node.NetDevs + } + AllNodes []node.NodeInfo } func BuildSystemOverlay(nodeList []node.NodeInfo) error { @@ -49,9 +52,6 @@ func RuntimeOverlayInit(name string) error { return overlayInit(name, "runtime") } - - - func findAllOverlays(overlayType string) ([]string, error) { config := config.New() var ret []string @@ -83,7 +83,6 @@ func findAllOverlays(overlayType string) ([]string, error) { return ret, nil } - func overlayInit(name string, overlayType string) error { var path string config := config.New() @@ -100,7 +99,7 @@ func overlayInit(name string, overlayType string) error { } if util.IsDir(path) == true { - return errors.New("Overlay already exists: "+name) + return errors.New("Overlay already exists: " + name) } err := os.MkdirAll(path, 0755) @@ -108,13 +107,10 @@ func overlayInit(name string, overlayType string) error { return err } - - - - - func buildOverlay(nodeList []node.NodeInfo, overlayType string) error { config := config.New() + nodeDB, _ := node.New() + allNodes, _ := nodeDB.FindAllNodes() for _, node := range nodeList { var t TemplateStruct @@ -134,11 +130,12 @@ func buildOverlay(nodeList []node.NodeInfo, overlayType string) error { wwlog.Printf(wwlog.DEBUG, "Processing overlay for node: %s\n", node.Fqdn.Get()) - t.Fqdn = node.Fqdn.Get() - t.Hostname = node.HostName.Get() - t.Groupname = node.GroupName.Get() - t.Vnfs = node.Vnfs.Get() - t.Netdev = node.NetDevs + t.Self.Fqdn = node.Fqdn.Get() + t.Self.Hostname = node.HostName.Get() + t.Self.GroupName = node.Gid.Get() + t.Self.Vnfs = node.Vnfs.Get() + t.Self.NetDevs = node.NetDevs + t.AllNodes = allNodes if overlayType == "runtime" && node.RuntimeOverlay.Defined() == false { wwlog.Printf(wwlog.WARN, "Undefined runtime overlay, skipping node: %s\n", node.Fqdn.Get()) @@ -230,7 +227,6 @@ func buildOverlay(nodeList []node.NodeInfo, overlayType string) error { return nil }) - wwlog.Printf(wwlog.VERBOSE, "Finished generating overlay directory for: %s\n", node.Fqdn.Get()) cmd := fmt.Sprintf("cd \"%s\"; find . | cpio --quiet -o -H newc -F \"%s\"", tmpDir, OverlayFile) diff --git a/internal/pkg/vnfs/vnfs.go b/internal/pkg/vnfs/vnfs.go index 11d67ad0..5bcf49f4 100644 --- a/internal/pkg/vnfs/vnfs.go +++ b/internal/pkg/vnfs/vnfs.go @@ -59,9 +59,9 @@ func CleanName(source string) string { tmp = source } - tmp = strings.ReplaceAll(tmp, "://", "-") - tmp = strings.ReplaceAll(tmp, "/", ".") - tmp = strings.ReplaceAll(tmp, ":", "-") + tmp = strings.ReplaceAll(tmp, "://", ":") + tmp = strings.ReplaceAll(tmp, "/", "-") + tmp = strings.ReplaceAll(tmp, ":", ":") return tmp } @@ -75,6 +75,10 @@ func New(source string) (VnfsObject, error) { return ret, errors.New("Called vnfs.Load() without a VNFS name") } + if util.IsFile(ret.Config) { + return Load(source) + } + pathFriendlyName := CleanName(source) if strings.HasPrefix(source, "/") == true { @@ -92,10 +96,6 @@ func New(source string) (VnfsObject, error) { 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 }