diff --git a/internal/app/wwctl/overlay/chmod/root.go b/internal/app/wwctl/overlay/chmod/root.go index 44fabc95..b6f5f016 100644 --- a/internal/app/wwctl/overlay/chmod/root.go +++ b/internal/app/wwctl/overlay/chmod/root.go @@ -1,6 +1,7 @@ package chmod import ( + "github.com/hpcng/warewulf/internal/pkg/overlay" "github.com/spf13/cobra" ) @@ -13,6 +14,13 @@ var ( Example: "wwctl overlay chmod default /etc/hostname.ww 0660", RunE: CobraRunE, Args: cobra.ExactArgs(3), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 0 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + list, _ := overlay.FindOverlays() + return list, cobra.ShellCompDirectiveNoFileComp + }, } ) diff --git a/internal/app/wwctl/overlay/chown/root.go b/internal/app/wwctl/overlay/chown/root.go index 31b2e40d..fc8fe5c3 100644 --- a/internal/app/wwctl/overlay/chown/root.go +++ b/internal/app/wwctl/overlay/chown/root.go @@ -1,6 +1,9 @@ package chown -import "github.com/spf13/cobra" +import ( + "github.com/hpcng/warewulf/internal/pkg/overlay" + "github.com/spf13/cobra" +) var ( baseCmd = &cobra.Command{ @@ -10,6 +13,13 @@ var ( Long: "This command changes the ownership of a FILE within the system or runtime OVERLAY_NAME\nto the user specified by UID. Optionally, it will also change group ownership to GID.", RunE: CobraRunE, Args: cobra.RangeArgs(3, 4), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 0 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + list, _ := overlay.FindOverlays() + return list, cobra.ShellCompDirectiveNoFileComp + }, } ) diff --git a/internal/app/wwctl/overlay/delete/root.go b/internal/app/wwctl/overlay/delete/root.go index 90ec39fe..ba2f75f5 100644 --- a/internal/app/wwctl/overlay/delete/root.go +++ b/internal/app/wwctl/overlay/delete/root.go @@ -1,6 +1,7 @@ package delete import ( + "github.com/hpcng/warewulf/internal/pkg/overlay" "github.com/spf13/cobra" ) @@ -13,6 +14,13 @@ var ( RunE: CobraRunE, Args: cobra.RangeArgs(1, 2), Aliases: []string{"rm", "del"}, + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 0 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + list, _ := overlay.FindOverlays() + return list, cobra.ShellCompDirectiveNoFileComp + }, } Force bool Parents bool diff --git a/internal/app/wwctl/overlay/edit/root.go b/internal/app/wwctl/overlay/edit/root.go index b3d7c9f0..2e265a60 100644 --- a/internal/app/wwctl/overlay/edit/root.go +++ b/internal/app/wwctl/overlay/edit/root.go @@ -1,6 +1,7 @@ package edit import ( + "github.com/hpcng/warewulf/internal/pkg/overlay" "github.com/spf13/cobra" ) @@ -12,6 +13,13 @@ var ( Long: "This command will open the FILE for editing or create a new file within the\nOVERLAY_NAME. Note: files created with a '.ww' suffix will always be\nparsed as Warewulf template files, and the suffix will be removed automatically.", RunE: CobraRunE, Args: cobra.ExactArgs(2), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 0 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + list, _ := overlay.FindOverlays() + return list, cobra.ShellCompDirectiveNoFileComp + }, } ListFiles bool CreateDirs bool diff --git a/internal/app/wwctl/overlay/imprt/root.go b/internal/app/wwctl/overlay/imprt/root.go index 2d41343c..4dc89acb 100644 --- a/internal/app/wwctl/overlay/imprt/root.go +++ b/internal/app/wwctl/overlay/imprt/root.go @@ -1,6 +1,9 @@ package imprt -import "github.com/spf13/cobra" +import ( + "github.com/hpcng/warewulf/internal/pkg/overlay" + "github.com/spf13/cobra" +) var ( baseCmd = &cobra.Command{ @@ -11,6 +14,13 @@ var ( RunE: CobraRunE, Args: cobra.RangeArgs(2, 3), Aliases: []string{"cp"}, + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 0 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + list, _ := overlay.FindOverlays() + return list, cobra.ShellCompDirectiveNoFileComp + }, } PermMode int32 NoOverlayUpdate bool diff --git a/internal/app/wwctl/overlay/list/root.go b/internal/app/wwctl/overlay/list/root.go index 0048d7f2..dbb9b46e 100644 --- a/internal/app/wwctl/overlay/list/root.go +++ b/internal/app/wwctl/overlay/list/root.go @@ -1,6 +1,7 @@ package list import ( + "github.com/hpcng/warewulf/internal/pkg/overlay" "github.com/spf13/cobra" ) @@ -14,6 +15,13 @@ var ( Args: cobra.MinimumNArgs(0), Aliases: []string{"ls"}, ValidArgs: []string{"system", "runtime"}, + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 0 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + list, _ := overlay.FindOverlays() + return list, cobra.ShellCompDirectiveNoFileComp + }, } ListContents bool ListLong bool diff --git a/internal/app/wwctl/overlay/root.go b/internal/app/wwctl/overlay/root.go index 4bb1cd95..b3713a7c 100644 --- a/internal/app/wwctl/overlay/root.go +++ b/internal/app/wwctl/overlay/root.go @@ -17,9 +17,9 @@ import ( var ( baseCmd = &cobra.Command{ DisableFlagsInUseLine: true, - Use: "overlay COMMAND [OPTIONS]", - Short: "Warewulf Overlay Management", - Long: "Management interface for Warewulf overlays", + Use: "overlay COMMAND [OPTIONS]", + Short: "Warewulf Overlay Management", + Long: "Management interface for Warewulf overlays", } ) @@ -34,6 +34,7 @@ func init() { baseCmd.AddCommand(imprt.GetCommand()) baseCmd.AddCommand(chmod.GetCommand()) baseCmd.AddCommand(chown.GetCommand()) + } // GetRootCommand returns the root cobra.Command for the application. diff --git a/internal/app/wwctl/overlay/show/main.go b/internal/app/wwctl/overlay/show/main.go index dac7c150..42775c29 100644 --- a/internal/app/wwctl/overlay/show/main.go +++ b/internal/app/wwctl/overlay/show/main.go @@ -1,11 +1,17 @@ package show import ( + "bufio" + "bytes" "fmt" "io/ioutil" "os" "path" + "path/filepath" + "regexp" + "strings" + "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/overlay" "github.com/hpcng/warewulf/internal/pkg/util" "github.com/hpcng/warewulf/internal/pkg/wwlog" @@ -17,7 +23,6 @@ func CobraRunE(cmd *cobra.Command, args []string) error { overlayName := args[0] fileName := args[1] - overlaySourceDir = overlay.OverlaySourceDir(overlayName) if !util.IsDir(overlaySourceDir) { @@ -32,13 +37,77 @@ func CobraRunE(cmd *cobra.Command, args []string) error { os.Exit(1) } - f, err := ioutil.ReadFile(overlayFile) - if err != nil { - wwlog.Printf(wwlog.ERROR, "Could not read file: %s\n", err) - os.Exit(1) + if NodeName == "" { + f, err := ioutil.ReadFile(overlayFile) + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not read file: %s\n", err) + os.Exit(1) + } + + fmt.Print(string(f)) + } else { + var host node.NodeInfo + nodeDB, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } + nodes, err := nodeDB.FindAllNodes() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err) + os.Exit(1) + } + node := node.FilterByName(nodes, []string{NodeName}) + if len(node) != 1 { + wwlog.Printf(wwlog.ERROR, "%v does not identify a single node\n", NodeName) + os.Exit(1) + } + host = node[0] + + if !util.IsFile(args[0]) { + wwlog.Printf(wwlog.ERROR, "%s is not a file\n", args[0]) + } + tstruct := overlay.InitStruct(host) + tstruct.BuildSource = args[0] + buffer, backupFile, writeFile, err := overlay.RenderTemplateFile(overlayFile, tstruct) + if err != nil { + return err + } + if filepath.Ext(args[0]) != ".ww" { + wwlog.Printf(wwlog.WARN, "%s has not the '.ww' so wont be rendered if in overlay\n", args[0]) + } + var outBuffer bytes.Buffer + // search for magic file name comment + bufferScanner := bufio.NewScanner(bytes.NewReader(buffer.Bytes())) + bufferScanner.Split(overlay.ScanLines) + reg := regexp.MustCompile(`.*{{\s*/\*\s*file\s*["'](.*)["']\s*\*/\s*}}.*`) + foundFileComment := false + destFileName := strings.TrimSuffix(args[0], ".ww") + for bufferScanner.Scan() { + line := bufferScanner.Text() + filenameFromTemplate := reg.FindAllStringSubmatch(line, -1) + if len(filenameFromTemplate) != 0 { + wwlog.Printf(wwlog.DEBUG, "Found multifile comment, new filename %s\n", filenameFromTemplate[0][1]) + if foundFileComment { + if !Quiet { + wwlog.Printf(wwlog.INFO, "backupFile: %v\nwriteFile: %v\n", backupFile, writeFile) + wwlog.Printf(wwlog.INFO, "Filename: %s\n\n", destFileName) + } + wwlog.Printf(wwlog.INFO, "%s", outBuffer.String()) + outBuffer.Reset() + } + destFileName = filenameFromTemplate[0][1] + foundFileComment = true + } else { + _, _ = outBuffer.WriteString(line) + } + } + if !Quiet { + wwlog.Printf(wwlog.INFO, "backupFile: %v\nwriteFile: %v\n", backupFile, writeFile) + wwlog.Printf(wwlog.INFO, "Filename: %s\n\n", destFileName) + } + wwlog.Printf(wwlog.INFO, "%s", outBuffer.String()) + } - - fmt.Print(string(f)) - return nil } diff --git a/internal/app/wwctl/overlay/show/root.go b/internal/app/wwctl/overlay/show/root.go index 168c4059..2dae0e77 100644 --- a/internal/app/wwctl/overlay/show/root.go +++ b/internal/app/wwctl/overlay/show/root.go @@ -1,6 +1,10 @@ package show import ( + "log" + + "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/overlay" "github.com/spf13/cobra" ) @@ -13,10 +17,32 @@ var ( RunE: CobraRunE, Aliases: []string{"cat"}, Args: cobra.ExactArgs(2), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 0 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + list, _ := overlay.FindOverlays() + return list, cobra.ShellCompDirectiveNoFileComp + }, } + NodeName string + Quiet bool ) func init() { + baseCmd.PersistentFlags().StringVarP(&NodeName, "render", "r", "", "node used for the variables in the template") + if err := baseCmd.RegisterFlagCompletionFunc("render", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + nodeDB, _ := node.New() + nodes, _ := nodeDB.FindAllNodes() + var node_names []string + for _, node := range nodes { + node_names = append(node_names, node.Id.Get()) + } + return node_names, cobra.ShellCompDirectiveNoFileComp + }); err != nil { + log.Println(err) + } + baseCmd.PersistentFlags().BoolVarP(&Quiet, "quiet", "q", false, "do not print information if multiple, backup files are written") } // GetRootCommand returns the root cobra.Command for the application. diff --git a/internal/pkg/overlay/datastructure.go b/internal/pkg/overlay/datastructure.go index 70e5f79b..4a0575af 100644 --- a/internal/pkg/overlay/datastructure.go +++ b/internal/pkg/overlay/datastructure.go @@ -1,8 +1,14 @@ package overlay import ( + "net" + "os" + "strconv" + "time" + "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/warewulfconf" + "github.com/hpcng/warewulf/internal/pkg/wwlog" ) /* @@ -38,3 +44,105 @@ type TemplateStruct struct { Nfs warewulfconf.NfsConf Warewulf warewulfconf.WarewulfConf } + +/* +Initialize an TemplateStruct with the given node.NodeInfo +*/ +func InitStruct(nodeInfo node.NodeInfo) TemplateStruct { + var tstruct TemplateStruct + controller, err := warewulfconf.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + nodeDB, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + allNodes, err := nodeDB.FindAllNodes() + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + + tstruct.Kernel = new(node.KernelConf) + tstruct.Ipmi = new(node.IpmiConf) + tstruct.Id = nodeInfo.Id.Get() + tstruct.Hostname = nodeInfo.Id.Get() + tstruct.Id = nodeInfo.Id.Get() + tstruct.Hostname = nodeInfo.Id.Get() + tstruct.ClusterName = nodeInfo.ClusterName.Get() + tstruct.Container = nodeInfo.ContainerName.Get() + tstruct.Kernel.Version = nodeInfo.Kernel.Override.Get() + tstruct.Kernel.Override = nodeInfo.Kernel.Override.Get() + tstruct.Kernel.Args = nodeInfo.Kernel.Args.Get() + tstruct.Init = nodeInfo.Init.Get() + tstruct.Root = nodeInfo.Root.Get() + tstruct.Ipmi.Ipaddr = nodeInfo.Ipmi.Ipaddr.Get() + tstruct.Ipmi.Netmask = nodeInfo.Ipmi.Netmask.Get() + tstruct.Ipmi.Port = nodeInfo.Ipmi.Port.Get() + tstruct.Ipmi.Gateway = nodeInfo.Ipmi.Gateway.Get() + tstruct.Ipmi.UserName = nodeInfo.Ipmi.UserName.Get() + tstruct.Ipmi.Password = nodeInfo.Ipmi.Password.Get() + tstruct.Ipmi.Interface = nodeInfo.Ipmi.Interface.Get() + tstruct.Ipmi.Write = nodeInfo.Ipmi.Write.Get() + tstruct.RuntimeOverlay = nodeInfo.RuntimeOverlay.Print() + tstruct.SystemOverlay = nodeInfo.SystemOverlay.Print() + tstruct.NetDevs = make(map[string]*node.NetDevs) + tstruct.Keys = make(map[string]string) + tstruct.Tags = make(map[string]string) + for devname, netdev := range nodeInfo.NetDevs { + var nd node.NetDevs + tstruct.NetDevs[devname] = &nd + tstruct.NetDevs[devname].Device = netdev.Device.Get() + tstruct.NetDevs[devname].Hwaddr = netdev.Hwaddr.Get() + tstruct.NetDevs[devname].Ipaddr = netdev.Ipaddr.Get() + tstruct.NetDevs[devname].Netmask = netdev.Netmask.Get() + tstruct.NetDevs[devname].Gateway = netdev.Gateway.Get() + tstruct.NetDevs[devname].Type = netdev.Type.Get() + tstruct.NetDevs[devname].OnBoot = netdev.OnBoot.Get() + tstruct.NetDevs[devname].Primary = netdev.Primary.Get() + mask := net.IPMask(net.ParseIP(netdev.Netmask.Get()).To4()) + ipaddr := net.ParseIP(netdev.Ipaddr.Get()).To4() + netaddr := net.IPNet{IP: ipaddr, Mask: mask} + netPrefix, _ := net.IPMask(net.ParseIP(netdev.Netmask.Get()).To4()).Size() + tstruct.NetDevs[devname].Prefix = strconv.Itoa(netPrefix) + tstruct.NetDevs[devname].IpCIDR = netaddr.String() + tstruct.NetDevs[devname].Ipaddr6 = netdev.Ipaddr6.Get() + tstruct.NetDevs[devname].Tags = make(map[string]string) + for key, value := range netdev.Tags { + tstruct.NetDevs[devname].Tags[key] = value.Get() + } + } + // Backwards compatibility for templates using "Keys" + for keyname, key := range nodeInfo.Tags { + tstruct.Keys[keyname] = key.Get() + } + for keyname, key := range nodeInfo.Tags { + tstruct.Tags[keyname] = key.Get() + } + tstruct.AllNodes = allNodes + tstruct.Nfs = *controller.Nfs + tstruct.Dhcp = *controller.Dhcp + tstruct.Warewulf = *controller.Warewulf + tstruct.Ipaddr = controller.Ipaddr + tstruct.Ipaddr6 = controller.Ipaddr6 + tstruct.Netmask = controller.Netmask + tstruct.Network = controller.Network + netaddrStruct := net.IPNet{IP: net.ParseIP(controller.Network), Mask: net.IPMask(net.ParseIP(controller.Netmask))} + tstruct.NetworkCIDR = netaddrStruct.String() + if controller.Ipaddr6 != "" { + tstruct.Ipv6 = true + } else { + tstruct.Ipv6 = false + } + hostname, _ := os.Hostname() + tstruct.BuildHost = hostname + dt := time.Now() + tstruct.BuildTime = dt.Format("01-02-2006 15:04:05 MST") + tstruct.BuildTimeUnix = strconv.FormatInt(dt.Unix(), 10) + + return tstruct + +} diff --git a/internal/pkg/overlay/overlay.go b/internal/pkg/overlay/overlay.go index 2c246ed9..7953c2fb 100644 --- a/internal/pkg/overlay/overlay.go +++ b/internal/pkg/overlay/overlay.go @@ -6,19 +6,15 @@ import ( "fmt" "io/fs" "io/ioutil" - "net" "os" "path" "path/filepath" "regexp" - "strconv" "strings" "text/template" - "time" "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/util" - "github.com/hpcng/warewulf/internal/pkg/warewulfconf" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/pkg/errors" ) @@ -199,106 +195,17 @@ func BuildOverlayIndir(nodeInfo node.NodeInfo, overlayNames []string, outputDir if !util.IsDir(outputDir) { return errors.Errorf("output must a be a directory: %s", outputDir) } - controller, err := warewulfconf.New() - if err != nil { - wwlog.ErrorExc(err, "") - os.Exit(1) - } - nodeDB, err := node.New() - if err != nil { - wwlog.ErrorExc(err, "") - os.Exit(1) - } - allNodes, err := nodeDB.FindAllNodes() - if err != nil { - wwlog.ErrorExc(err, "") - os.Exit(1) - } if !util.ValidString(strings.Join(overlayNames, ""), "^[a-zA-Z0-9-._:]+$") { return errors.Errorf("overlay names contains illegal characters: %v", overlayNames) } - wwlog.Verbose("Processing node/overlay: %s/%s", nodeInfo.Id.Get(), strings.Join(overlayNames, "-")) - var tstruct TemplateStruct - tstruct.Kernel = new(node.KernelConf) - tstruct.Ipmi = new(node.IpmiConf) - tstruct.Id = nodeInfo.Id.Get() - tstruct.Hostname = nodeInfo.Id.Get() - tstruct.ClusterName = nodeInfo.ClusterName.Get() - tstruct.Container = nodeInfo.ContainerName.Get() - tstruct.Kernel.Version = nodeInfo.Kernel.Override.Get() - tstruct.Kernel.Override = nodeInfo.Kernel.Override.Get() - tstruct.Kernel.Args = nodeInfo.Kernel.Args.Get() - tstruct.Init = nodeInfo.Init.Get() - tstruct.Root = nodeInfo.Root.Get() - tstruct.Ipmi.Ipaddr = nodeInfo.Ipmi.Ipaddr.Get() - tstruct.Ipmi.Netmask = nodeInfo.Ipmi.Netmask.Get() - tstruct.Ipmi.Port = nodeInfo.Ipmi.Port.Get() - tstruct.Ipmi.Gateway = nodeInfo.Ipmi.Gateway.Get() - tstruct.Ipmi.UserName = nodeInfo.Ipmi.UserName.Get() - tstruct.Ipmi.Password = nodeInfo.Ipmi.Password.Get() - tstruct.Ipmi.Interface = nodeInfo.Ipmi.Interface.Get() - tstruct.Ipmi.Write = nodeInfo.Ipmi.Write.Get() - tstruct.RuntimeOverlay = nodeInfo.RuntimeOverlay.Print() - tstruct.SystemOverlay = nodeInfo.SystemOverlay.Print() - tstruct.NetDevs = make(map[string]*node.NetDevs) - tstruct.Keys = make(map[string]string) - tstruct.Tags = make(map[string]string) - for devname, netdev := range nodeInfo.NetDevs { - var nd node.NetDevs - tstruct.NetDevs[devname] = &nd - tstruct.NetDevs[devname].Device = netdev.Device.Get() - tstruct.NetDevs[devname].Hwaddr = netdev.Hwaddr.Get() - tstruct.NetDevs[devname].Ipaddr = netdev.Ipaddr.Get() - tstruct.NetDevs[devname].Netmask = netdev.Netmask.Get() - tstruct.NetDevs[devname].Gateway = netdev.Gateway.Get() - tstruct.NetDevs[devname].Type = netdev.Type.Get() - tstruct.NetDevs[devname].OnBoot = netdev.OnBoot.Get() - tstruct.NetDevs[devname].Primary = netdev.Primary.Get() - mask := net.IPMask(net.ParseIP(netdev.Netmask.Get()).To4()) - ipaddr := net.ParseIP(netdev.Ipaddr.Get()).To4() - netaddr := net.IPNet{IP: ipaddr, Mask: mask} - netPrefix, _ := net.IPMask(net.ParseIP(netdev.Netmask.Get()).To4()).Size() - tstruct.NetDevs[devname].Prefix = strconv.Itoa(netPrefix) - tstruct.NetDevs[devname].IpCIDR = netaddr.String() - tstruct.NetDevs[devname].Ipaddr6 = netdev.Ipaddr6.Get() - tstruct.NetDevs[devname].Tags = make(map[string]string) - for key, value := range netdev.Tags { - tstruct.NetDevs[devname].Tags[key] = value.Get() - } - } - // Backwards compatibility for templates using "Keys" - for keyname, key := range nodeInfo.Tags { - tstruct.Keys[keyname] = key.Get() - } - for keyname, key := range nodeInfo.Tags { - tstruct.Tags[keyname] = key.Get() - } - tstruct.AllNodes = allNodes - tstruct.Nfs = *controller.Nfs - tstruct.Dhcp = *controller.Dhcp - tstruct.Warewulf = *controller.Warewulf - tstruct.Ipaddr = controller.Ipaddr - tstruct.Ipaddr6 = controller.Ipaddr6 - tstruct.Netmask = controller.Netmask - tstruct.Network = controller.Network - netaddrStruct := net.IPNet{IP: net.ParseIP(controller.Network), Mask: net.IPMask(net.ParseIP(controller.Netmask))} - tstruct.NetworkCIDR = netaddrStruct.String() - if controller.Ipaddr6 != "" { - tstruct.Ipv6 = true - } else { - tstruct.Ipv6 = false - } - hostname, _ := os.Hostname() - tstruct.BuildHost = hostname - dt := time.Now() - tstruct.BuildTime = dt.Format("01-02-2006 15:04:05 MST") - tstruct.BuildTimeUnix = strconv.FormatInt(dt.Unix(), 10) + + wwlog.Printf(wwlog.VERBOSE, "Processing node/overlay: %s/%s\n", nodeInfo.Id.Get(), strings.Join(overlayNames, "-")) for _, overlayName := range overlayNames { wwlog.Verbose("Building overlay %s for node %s in %s", overlayName, nodeInfo.Id.Get(), outputDir) overlaySourceDir := OverlaySourceDir(overlayName) - wwlog.Debug("Starting to build overlay %s\nChanging directory to OverlayDir: %s", overlayName, overlaySourceDir) - err = os.Chdir(overlaySourceDir) + wwlog.Printf(wwlog.DEBUG, "Starting to build overlay %s\nChanging directory to OverlayDir: %s\n", overlayName, overlaySourceDir) + err := os.Chdir(overlaySourceDir) if err != nil { return errors.Wrap(err, "could not change directory to overlay dir") } @@ -330,48 +237,21 @@ func BuildOverlayIndir(nodeInfo node.NodeInfo, overlayNames []string, outputDir wwlog.Debug("Created directory in overlay: %s", location) } else if filepath.Ext(location) == ".ww" { + tstruct := InitStruct(nodeInfo) tstruct.BuildSource = path.Join(overlaySourceDir, location) wwlog.Verbose("Evaluating overlay template file: %s", location) destFile := strings.TrimSuffix(location, ".ww") - backupFile := true - writeFile := true - tmpl, err := template.New(path.Base(location)).Option("missingkey=default").Funcs(template.FuncMap{ - // TODO: Fix for missingkey=zero - "Include": templateFileInclude, - "IncludeFrom": templateContainerFileInclude, - "IncludeBlock": templateFileBlock, - "inc": func(i int) int { return i + 1 }, - "dec": func(i int) int { return i - 1 }, - "file": func(str string) string { return fmt.Sprintf("{{ /* file \"%s\" */ }}", str) }, - "abort": func() string { - wwlog.Debug("abort file called in %s", location) - writeFile = false - return "" - }, - "nobackup": func() string { - wwlog.Debug("not backup for %s", location) - backupFile = false - return "" - }, - "split": func(s string, d string) []string { - return strings.Split(s, d) - }, - // }).ParseGlob(path.Join(OverlayDir, destFile+".ww*")) - }).ParseGlob(location) + + buffer, backupFile, writeFile, err := RenderTemplateFile(location, tstruct) if err != nil { - return errors.Wrap(err, "could not parse template "+location) - } - var buffer bytes.Buffer - err = tmpl.Execute(&buffer, tstruct) - if err != nil { - return errors.Wrap(err, "could not execute template") + return errors.Wrap(err, fmt.Sprintf("Failed to render template %s", location)) } if writeFile { destFileName := destFile var fileBuffer bytes.Buffer // search for magic file name comment fileScanner := bufio.NewScanner(bytes.NewReader(buffer.Bytes())) - fileScanner.Split(scanLines) + fileScanner.Split(ScanLines) reg := regexp.MustCompile(`.*{{\s*/\*\s*file\s*["'](.*)["']\s*\*/\s*}}.*`) foundFileComment := false for fileScanner.Scan() { @@ -475,8 +355,55 @@ func carefulWriteBuffer(destFile string, buffer bytes.Buffer, backupFile bool, p return err } +/* +Parses the template with the given filename, variables must be in data. Returns the +parsed template as bytes.Buffer, and the bool variables for backupFile and writeFile. +If something goes wrong an error is returned. +*/ +func RenderTemplateFile(fileName string, data TemplateStruct) ( + buffer bytes.Buffer, + backupFile bool, + writeFile bool, + err error) { + backupFile = true + writeFile = true + tmpl, err := template.New(path.Base(fileName)).Option("missingkey=default").Funcs(template.FuncMap{ + // TODO: Fix for missingkey=zero + "Include": templateFileInclude, + "IncludeFrom": templateContainerFileInclude, + "IncludeBlock": templateFileBlock, + "inc": func(i int) int { return i + 1 }, + "dec": func(i int) int { return i - 1 }, + "file": func(str string) string { return fmt.Sprintf("{{ /* file \"%s\" */ }}", str) }, + "abort": func() string { + wwlog.Printf(wwlog.DEBUG, "abort file called in %s\n", fileName) + writeFile = false + return "" + }, + "nobackup": func() string { + wwlog.Printf(wwlog.DEBUG, "not backup for %s\n", fileName) + backupFile = false + return "" + }, + "split": func(s string, d string) []string { + return strings.Split(s, d) + }, + // }).ParseGlob(path.Join(OverlayDir, destFile+".ww*")) + }).ParseGlob(fileName) + if err != nil { + err = errors.Wrap(err, "could not parse template "+fileName) + return + } + err = tmpl.Execute(&buffer, data) + if err != nil { + err = errors.Wrap(err, "could not execute template") + return + } + return +} + // Simple version of ScanLines, but include the line break -func scanLines(data []byte, atEOF bool) (advance int, token []byte, err error) { +func ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error) { if atEOF && len(data) == 0 { return 0, nil, nil }