From 1b02c89ca7ad87139227f305cb0cdb7026c4fee7 Mon Sep 17 00:00:00 2001 From: Christian Goll Date: Tue, 24 May 2022 19:41:31 +0200 Subject: [PATCH 1/9] moved overlay parsing to own function --- internal/pkg/overlay/overlay.go | 78 +++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 33 deletions(-) diff --git a/internal/pkg/overlay/overlay.go b/internal/pkg/overlay/overlay.go index 634b5082..8037c2b6 100644 --- a/internal/pkg/overlay/overlay.go +++ b/internal/pkg/overlay/overlay.go @@ -333,39 +333,8 @@ func BuildOverlayIndir(nodeInfo node.NodeInfo, overlayNames []string, outputDir 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) - 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") - } + + buffer, backupFile, writeFile, err := RenderTemplateFile(location, tstruct) if writeFile { destFileName := destFile var fileBuffer bytes.Buffer @@ -464,6 +433,49 @@ 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) { if atEOF && len(data) == 0 { From dfe3f907b92223da6e5a904d31d8d7a1940e0e17 Mon Sep 17 00:00:00 2001 From: Christian Goll Date: Tue, 24 May 2022 20:01:29 +0200 Subject: [PATCH 2/9] moved TemplateStruct init to own function --- internal/pkg/overlay/datastructure.go | 108 ++++++++++++++++++++++++++ internal/pkg/overlay/overlay.go | 102 ++---------------------- 2 files changed, 113 insertions(+), 97 deletions(-) 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 8037c2b6..6a8a15b7 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,6 +237,7 @@ 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") From 9e5b2d1aa3c203d9b4055dfd97ec2c1446169d63 Mon Sep 17 00:00:00 2001 From: Christian Goll Date: Wed, 25 May 2022 11:41:33 +0200 Subject: [PATCH 3/9] added the wwctl overlay parse command The `wwctl overlay parse -n NODE FILE` will interpret the given overlay file and print it stdout, via wwlog.PRINTF. The overlay code had to be refactored for this, but hopefully this makes the code a bit more readable. Also the tstruct has not its own initilization code. --- internal/app/wwctl/overlay/parse/main.go | 83 ++++++++++++++++++++++++ internal/app/wwctl/overlay/parse/root.go | 41 ++++++++++++ internal/app/wwctl/overlay/root.go | 9 ++- internal/pkg/overlay/overlay.go | 13 +++- 4 files changed, 140 insertions(+), 6 deletions(-) create mode 100644 internal/app/wwctl/overlay/parse/main.go create mode 100644 internal/app/wwctl/overlay/parse/root.go diff --git a/internal/app/wwctl/overlay/parse/main.go b/internal/app/wwctl/overlay/parse/main.go new file mode 100644 index 00000000..7d7384b7 --- /dev/null +++ b/internal/app/wwctl/overlay/parse/main.go @@ -0,0 +1,83 @@ +package parse + +import ( + "bufio" + "bytes" + "os" + "path/filepath" + "regexp" + + "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" + "github.com/spf13/cobra" +) + +func CobraRunE(cmd *cobra.Command, args []string) error { + var host node.NodeInfo + if NodeName == "" { + host.Kernel = new(node.KernelEntry) + host.Ipmi = new(node.IpmiEntry) + var idEntry node.Entry + hostname, _ := os.Hostname() + idEntry.Set(hostname) + host.Id = idEntry + } else { + 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) + buffer, backupFile, writeFile, err := overlay.RenderTemplateFile(args[0], 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]) + } + wwlog.Printf(wwlog.INFO, "backupFile: %v\nwriteFile: %v\n", backupFile, writeFile) + 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 := args[0] + 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 { + wwlog.Printf(wwlog.INFO, "%s", outBuffer.String()) + outBuffer.Reset() + } + destFileName = filenameFromTemplate[0][1] + wwlog.Printf(wwlog.INFO, "Filename: %s\n\n", destFileName) + wwlog.Printf(wwlog.INFO, "%s", outBuffer.String()) + foundFileComment = true + } else { + _, _ = outBuffer.WriteString(line) + } + } + wwlog.Printf(wwlog.INFO, "Filename: %s\n\n", destFileName) + wwlog.Printf(wwlog.INFO, "%s", outBuffer.String()) + return nil +} diff --git a/internal/app/wwctl/overlay/parse/root.go b/internal/app/wwctl/overlay/parse/root.go new file mode 100644 index 00000000..e4db0f81 --- /dev/null +++ b/internal/app/wwctl/overlay/parse/root.go @@ -0,0 +1,41 @@ +package parse + +import ( + "log" + + "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/spf13/cobra" +) + +var ( + baseCmd = &cobra.Command{ + DisableFlagsInUseLine: true, + Use: "parse [OPTIONS] FILE_NAME", + Short: "parses interprets the given file as warewulf template", + Long: "This command tries to parse a given file as warewulf template, it needs not to be in overlay folder.", + RunE: CobraRunE, + Aliases: []string{"parse"}, + Args: cobra.ExactArgs(1), + } + NodeName string +) + +func init() { + baseCmd.PersistentFlags().StringVarP(&NodeName, "node", "n", "", "node used for the variables in the template") + if err := baseCmd.RegisterFlagCompletionFunc("node", 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) + } +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/overlay/root.go b/internal/app/wwctl/overlay/root.go index 4bb1cd95..00d931c0 100644 --- a/internal/app/wwctl/overlay/root.go +++ b/internal/app/wwctl/overlay/root.go @@ -10,6 +10,7 @@ import ( "github.com/hpcng/warewulf/internal/app/wwctl/overlay/imprt" "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/parse" "github.com/hpcng/warewulf/internal/app/wwctl/overlay/show" "github.com/spf13/cobra" ) @@ -17,9 +18,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 +35,8 @@ func init() { baseCmd.AddCommand(imprt.GetCommand()) baseCmd.AddCommand(chmod.GetCommand()) baseCmd.AddCommand(chown.GetCommand()) + baseCmd.AddCommand(parse.GetCommand()) + } // GetRootCommand returns the root cobra.Command for the application. diff --git a/internal/pkg/overlay/overlay.go b/internal/pkg/overlay/overlay.go index 6a8a15b7..0f55563b 100644 --- a/internal/pkg/overlay/overlay.go +++ b/internal/pkg/overlay/overlay.go @@ -243,12 +243,15 @@ func BuildOverlayIndir(nodeInfo node.NodeInfo, overlayNames []string, outputDir destFile := strings.TrimSuffix(location, ".ww") buffer, backupFile, writeFile, err := RenderTemplateFile(location, tstruct) + if err != nil { + 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() { @@ -346,7 +349,11 @@ Parses the template with the given filename, variables must be in data. Returns 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) { +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{ @@ -385,7 +392,7 @@ func RenderTemplateFile(fileName string, data TemplateStruct) (buffer bytes.Buff } // 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 } From 98e085c6f2509ab91c19ca95f49225d7fdc6ac6a Mon Sep 17 00:00:00 2001 From: Christian Goll Date: Wed, 25 May 2022 12:24:18 +0200 Subject: [PATCH 4/9] Trim 'ww' suffix on output --- internal/app/wwctl/overlay/parse/main.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/internal/app/wwctl/overlay/parse/main.go b/internal/app/wwctl/overlay/parse/main.go index 7d7384b7..0090ca3e 100644 --- a/internal/app/wwctl/overlay/parse/main.go +++ b/internal/app/wwctl/overlay/parse/main.go @@ -6,6 +6,7 @@ import ( "os" "path/filepath" "regexp" + "strings" "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/overlay" @@ -52,31 +53,31 @@ func CobraRunE(cmd *cobra.Command, args []string) error { 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]) } - wwlog.Printf(wwlog.INFO, "backupFile: %v\nwriteFile: %v\n", backupFile, writeFile) 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 := args[0] + 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 { + 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] - wwlog.Printf(wwlog.INFO, "Filename: %s\n\n", destFileName) - wwlog.Printf(wwlog.INFO, "%s", outBuffer.String()) foundFileComment = true } else { _, _ = outBuffer.WriteString(line) } } + 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()) return nil From 312596276eddab1c163af3d9bb1729d2b94535d3 Mon Sep 17 00:00:00 2001 From: Christian Goll Date: Wed, 25 May 2022 15:52:33 +0200 Subject: [PATCH 5/9] Add source for parse --- internal/app/wwctl/overlay/parse/main.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/app/wwctl/overlay/parse/main.go b/internal/app/wwctl/overlay/parse/main.go index 0090ca3e..35e24f7c 100644 --- a/internal/app/wwctl/overlay/parse/main.go +++ b/internal/app/wwctl/overlay/parse/main.go @@ -46,6 +46,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { 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(args[0], tstruct) if err != nil { return err From 2f4757600db6601c6debd683511b7dc69583408a Mon Sep 17 00:00:00 2001 From: Christian Goll Date: Wed, 25 May 2022 20:58:52 +0200 Subject: [PATCH 6/9] added quiet option --- internal/app/wwctl/overlay/parse/main.go | 12 ++++++++---- internal/app/wwctl/overlay/parse/root.go | 2 ++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/internal/app/wwctl/overlay/parse/main.go b/internal/app/wwctl/overlay/parse/main.go index 35e24f7c..ee6add2e 100644 --- a/internal/app/wwctl/overlay/parse/main.go +++ b/internal/app/wwctl/overlay/parse/main.go @@ -67,8 +67,10 @@ func CobraRunE(cmd *cobra.Command, args []string) error { if len(filenameFromTemplate) != 0 { wwlog.Printf(wwlog.DEBUG, "Found multifile comment, new filename %s\n", filenameFromTemplate[0][1]) if foundFileComment { - wwlog.Printf(wwlog.INFO, "backupFile: %v\nwriteFile: %v\n", backupFile, writeFile) - wwlog.Printf(wwlog.INFO, "Filename: %s\n\n", destFileName) + 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() } @@ -78,8 +80,10 @@ func CobraRunE(cmd *cobra.Command, args []string) error { _, _ = outBuffer.WriteString(line) } } - wwlog.Printf(wwlog.INFO, "backupFile: %v\nwriteFile: %v\n", backupFile, writeFile) - wwlog.Printf(wwlog.INFO, "Filename: %s\n\n", destFileName) + 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()) return nil } diff --git a/internal/app/wwctl/overlay/parse/root.go b/internal/app/wwctl/overlay/parse/root.go index e4db0f81..730a6210 100644 --- a/internal/app/wwctl/overlay/parse/root.go +++ b/internal/app/wwctl/overlay/parse/root.go @@ -18,6 +18,7 @@ var ( Args: cobra.ExactArgs(1), } NodeName string + Quiet bool ) func init() { @@ -33,6 +34,7 @@ func init() { }); 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. From 53667157c5e49f20168f3f55176fa52f07825514 Mon Sep 17 00:00:00 2001 From: Christian Goll Date: Wed, 8 Jun 2022 15:36:20 +0200 Subject: [PATCH 7/9] parse not own command but show --render --- internal/app/wwctl/overlay/parse/main.go | 89 ------------------ internal/app/wwctl/overlay/parse/root.go | 43 --------- internal/app/wwctl/overlay/root.go | 2 - internal/app/wwctl/overlay/show/main.go | 109 ++++++++++++++++++----- internal/app/wwctl/overlay/show/root.go | 18 ++++ 5 files changed, 107 insertions(+), 154 deletions(-) delete mode 100644 internal/app/wwctl/overlay/parse/main.go delete mode 100644 internal/app/wwctl/overlay/parse/root.go diff --git a/internal/app/wwctl/overlay/parse/main.go b/internal/app/wwctl/overlay/parse/main.go deleted file mode 100644 index ee6add2e..00000000 --- a/internal/app/wwctl/overlay/parse/main.go +++ /dev/null @@ -1,89 +0,0 @@ -package parse - -import ( - "bufio" - "bytes" - "os" - "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" - "github.com/spf13/cobra" -) - -func CobraRunE(cmd *cobra.Command, args []string) error { - var host node.NodeInfo - if NodeName == "" { - host.Kernel = new(node.KernelEntry) - host.Ipmi = new(node.IpmiEntry) - var idEntry node.Entry - hostname, _ := os.Hostname() - idEntry.Set(hostname) - host.Id = idEntry - } else { - 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(args[0], 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()) - return nil -} diff --git a/internal/app/wwctl/overlay/parse/root.go b/internal/app/wwctl/overlay/parse/root.go deleted file mode 100644 index 730a6210..00000000 --- a/internal/app/wwctl/overlay/parse/root.go +++ /dev/null @@ -1,43 +0,0 @@ -package parse - -import ( - "log" - - "github.com/hpcng/warewulf/internal/pkg/node" - "github.com/spf13/cobra" -) - -var ( - baseCmd = &cobra.Command{ - DisableFlagsInUseLine: true, - Use: "parse [OPTIONS] FILE_NAME", - Short: "parses interprets the given file as warewulf template", - Long: "This command tries to parse a given file as warewulf template, it needs not to be in overlay folder.", - RunE: CobraRunE, - Aliases: []string{"parse"}, - Args: cobra.ExactArgs(1), - } - NodeName string - Quiet bool -) - -func init() { - baseCmd.PersistentFlags().StringVarP(&NodeName, "node", "n", "", "node used for the variables in the template") - if err := baseCmd.RegisterFlagCompletionFunc("node", 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. -func GetCommand() *cobra.Command { - return baseCmd -} diff --git a/internal/app/wwctl/overlay/root.go b/internal/app/wwctl/overlay/root.go index 00d931c0..b3713a7c 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/imprt" "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/parse" "github.com/hpcng/warewulf/internal/app/wwctl/overlay/show" "github.com/spf13/cobra" ) @@ -35,7 +34,6 @@ func init() { baseCmd.AddCommand(imprt.GetCommand()) baseCmd.AddCommand(chmod.GetCommand()) baseCmd.AddCommand(chown.GetCommand()) - baseCmd.AddCommand(parse.GetCommand()) } diff --git a/internal/app/wwctl/overlay/show/main.go b/internal/app/wwctl/overlay/show/main.go index dac7c150..8e5e0824 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,28 +23,91 @@ func CobraRunE(cmd *cobra.Command, args []string) error { overlayName := args[0] fileName := args[1] + if NodeName == "" { + overlaySourceDir = overlay.OverlaySourceDir(overlayName) - overlaySourceDir = overlay.OverlaySourceDir(overlayName) + if !util.IsDir(overlaySourceDir) { + wwlog.Printf(wwlog.ERROR, "Overlay does not exist: %s\n", overlayName) + os.Exit(1) + } + + overlayFile := path.Join(overlaySourceDir, fileName) + + if !util.IsFile(overlayFile) { + wwlog.Printf(wwlog.ERROR, "File does not exist within overlay: %s:%s\n", overlayName, fileName) + 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) + } + + 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(args[0], 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()) - if !util.IsDir(overlaySourceDir) { - wwlog.Printf(wwlog.ERROR, "Overlay does not exist: %s\n", overlayName) - os.Exit(1) } - - overlayFile := path.Join(overlaySourceDir, fileName) - - if !util.IsFile(overlayFile) { - wwlog.Printf(wwlog.ERROR, "File does not exist within overlay: %s:%s\n", overlayName, fileName) - 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) - } - - 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..aaa3961b 100644 --- a/internal/app/wwctl/overlay/show/root.go +++ b/internal/app/wwctl/overlay/show/root.go @@ -1,6 +1,9 @@ package show import ( + "log" + + "github.com/hpcng/warewulf/internal/pkg/node" "github.com/spf13/cobra" ) @@ -14,9 +17,24 @@ var ( Aliases: []string{"cat"}, Args: cobra.ExactArgs(2), } + NodeName string + Quiet bool ) func init() { + baseCmd.PersistentFlags().StringVarP(&NodeName, "name", "n", "", "node used for the variables in the template") + if err := baseCmd.RegisterFlagCompletionFunc("name", 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. From 69c058f1060d042e6c420c41865e1cb002216e48 Mon Sep 17 00:00:00 2001 From: Christian Goll Date: Wed, 8 Jun 2022 15:49:55 +0200 Subject: [PATCH 8/9] added bash completion for overlay commands --- internal/app/wwctl/overlay/chmod/root.go | 8 ++++++++ internal/app/wwctl/overlay/chown/root.go | 12 +++++++++++- internal/app/wwctl/overlay/delete/root.go | 8 ++++++++ internal/app/wwctl/overlay/edit/root.go | 8 ++++++++ internal/app/wwctl/overlay/imprt/root.go | 12 +++++++++++- internal/app/wwctl/overlay/list/root.go | 8 ++++++++ internal/app/wwctl/overlay/show/root.go | 12 ++++++++++-- 7 files changed, 64 insertions(+), 4 deletions(-) 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/show/root.go b/internal/app/wwctl/overlay/show/root.go index aaa3961b..2dae0e77 100644 --- a/internal/app/wwctl/overlay/show/root.go +++ b/internal/app/wwctl/overlay/show/root.go @@ -4,6 +4,7 @@ import ( "log" "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/overlay" "github.com/spf13/cobra" ) @@ -16,14 +17,21 @@ 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, "name", "n", "", "node used for the variables in the template") - if err := baseCmd.RegisterFlagCompletionFunc("name", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + 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 From 95e03b3df4f1b94b3ca7215a639a972de4e1b96c Mon Sep 17 00:00:00 2001 From: Christian Goll Date: Wed, 8 Jun 2022 15:56:10 +0200 Subject: [PATCH 9/9] get arguments for show --render right --- internal/app/wwctl/overlay/show/main.go | 30 ++++++++++++------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/internal/app/wwctl/overlay/show/main.go b/internal/app/wwctl/overlay/show/main.go index 8e5e0824..42775c29 100644 --- a/internal/app/wwctl/overlay/show/main.go +++ b/internal/app/wwctl/overlay/show/main.go @@ -23,21 +23,21 @@ func CobraRunE(cmd *cobra.Command, args []string) error { overlayName := args[0] fileName := args[1] + overlaySourceDir = overlay.OverlaySourceDir(overlayName) + + if !util.IsDir(overlaySourceDir) { + wwlog.Printf(wwlog.ERROR, "Overlay does not exist: %s\n", overlayName) + os.Exit(1) + } + + overlayFile := path.Join(overlaySourceDir, fileName) + + if !util.IsFile(overlayFile) { + wwlog.Printf(wwlog.ERROR, "File does not exist within overlay: %s:%s\n", overlayName, fileName) + os.Exit(1) + } + if NodeName == "" { - overlaySourceDir = overlay.OverlaySourceDir(overlayName) - - if !util.IsDir(overlaySourceDir) { - wwlog.Printf(wwlog.ERROR, "Overlay does not exist: %s\n", overlayName) - os.Exit(1) - } - - overlayFile := path.Join(overlaySourceDir, fileName) - - if !util.IsFile(overlayFile) { - wwlog.Printf(wwlog.ERROR, "File does not exist within overlay: %s:%s\n", overlayName, fileName) - os.Exit(1) - } - f, err := ioutil.ReadFile(overlayFile) if err != nil { wwlog.Printf(wwlog.ERROR, "Could not read file: %s\n", err) @@ -69,7 +69,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } tstruct := overlay.InitStruct(host) tstruct.BuildSource = args[0] - buffer, backupFile, writeFile, err := overlay.RenderTemplateFile(args[0], tstruct) + buffer, backupFile, writeFile, err := overlay.RenderTemplateFile(overlayFile, tstruct) if err != nil { return err }