From 5494424c09281e3eb375a658c26265d331cfb993 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Sat, 8 Feb 2025 14:52:48 -0700 Subject: [PATCH] wwctl image completions and arguments Signed-off-by: Jonathon Anderson --- internal/app/wwctl/completions/completions.go | 12 ++++++--- internal/app/wwctl/image/copy/main.go | 5 ---- internal/app/wwctl/image/copy/root.go | 2 +- internal/app/wwctl/image/imprt/root.go | 2 +- internal/app/wwctl/image/kernels/main_test.go | 8 +++--- internal/app/wwctl/image/kernels/root.go | 2 +- internal/app/wwctl/image/list/main.go | 22 +++++++++++++--- internal/app/wwctl/image/list/root.go | 2 ++ internal/app/wwctl/image/rename/main.go | 4 --- internal/app/wwctl/image/rename/root.go | 12 +++------ internal/app/wwctl/image/shell/main.go | 25 +++++++++++-------- internal/app/wwctl/image/shell/root.go | 2 +- internal/app/wwctl/image/show/main.go | 1 - internal/app/wwctl/image/show/root.go | 15 +++-------- 14 files changed, 59 insertions(+), 55 deletions(-) diff --git a/internal/app/wwctl/completions/completions.go b/internal/app/wwctl/completions/completions.go index 19adb05f..367a3750 100644 --- a/internal/app/wwctl/completions/completions.go +++ b/internal/app/wwctl/completions/completions.go @@ -48,9 +48,15 @@ func ProfileKernelVersion(cmd *cobra.Command, args []string, toComplete string) return kernelVersions, cobra.ShellCompDirectiveNoFileComp } -func Images(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - sources, _ := image.ListSources() - return sources, cobra.ShellCompDirectiveNoFileComp +func Images(num int) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if num <= 0 || len(args) < num { + sources, _ := image.ListSources() + return sources, cobra.ShellCompDirectiveNoFileComp + } else { + return nil, cobra.ShellCompDirectiveNoFileComp + } + } } func Profiles(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { diff --git a/internal/app/wwctl/image/copy/main.go b/internal/app/wwctl/image/copy/main.go index 83bc2ff2..89564fe0 100644 --- a/internal/app/wwctl/image/copy/main.go +++ b/internal/app/wwctl/image/copy/main.go @@ -10,11 +10,6 @@ import ( ) func CobraRunE(cmd *cobra.Command, args []string) (err error) { - - if len(args) > 2 { - wwlog.Warn("copy only requires 2 arguments but you provided %d arguments. Hence, they will be ignored.", len(args)) - } - cdp := &wwapiv1.ImageCopyParameter{ ImageSource: args[0], ImageDestination: args[1], diff --git a/internal/app/wwctl/image/copy/root.go b/internal/app/wwctl/image/copy/root.go index 009c33d6..0982efaa 100644 --- a/internal/app/wwctl/image/copy/root.go +++ b/internal/app/wwctl/image/copy/root.go @@ -13,7 +13,7 @@ var ( Short: "Copy an existing image", Long: "This command will duplicate an imported image.", RunE: CobraRunE, - Args: cobra.MinimumNArgs(2), + Args: cobra.ExactArgs(2), ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) != 0 { return nil, cobra.ShellCompDirectiveNoFileComp diff --git a/internal/app/wwctl/image/imprt/root.go b/internal/app/wwctl/image/imprt/root.go index 3f7d0355..5aaf3a0f 100644 --- a/internal/app/wwctl/image/imprt/root.go +++ b/internal/app/wwctl/image/imprt/root.go @@ -22,7 +22,7 @@ are: Imported images are used to create bootable images.`, Example: "wwctl image import docker://ghcr.io/warewulf/warewulf-rockylinux:8 rockylinux-8", RunE: CobraRunE, - Args: cobra.MinimumNArgs(1), + Args: cobra.RangeArgs(1, 2), PreRun: func(cmd *cobra.Command, args []string) { if SetForce && SetUpdate { wwlog.Warn("Both --force and --update flags are set, will ignore --update flag") diff --git a/internal/app/wwctl/image/kernels/main_test.go b/internal/app/wwctl/image/kernels/main_test.go index 7d25c7c5..bddb6288 100644 --- a/internal/app/wwctl/image/kernels/main_test.go +++ b/internal/app/wwctl/image/kernels/main_test.go @@ -27,12 +27,12 @@ Image Kernel Version Default Nodes }, "list": { files: map[string][]string{ - "image1": []string{ + "image1": { "/boot/vmlinuz-5.14.0-427.18.1.el9_4.x86_64", "/boot/vmlinuz-5.14.0-427.24.1.el9_4.x86_64", "/boot/vmlinuz-4.14.0-427.18.1.el8_4.x86_64", }, - "image2": []string{ + "image2": { "/boot/vmlinuz-0-rescue-eb46964329b146e39518c625feab3ea0", "/boot/vmlinuz-5.14.0-362.24.1.el9_3.aarch64", "/boot/vmlinuz-5.14.0-427.31.1.el9_4.aarch64+debug", @@ -56,12 +56,12 @@ image2 /boot/vmlinuz-5.14.0-427.31.1.el9_4.aarch64+debug 5.14.0-427.31.1 }, "single image": { files: map[string][]string{ - "image1": []string{ + "image1": { "/boot/vmlinuz-5.14.0-427.18.1.el9_4.x86_64", "/boot/vmlinuz-5.14.0-427.24.1.el9_4.x86_64", "/boot/vmlinuz-4.14.0-427.18.1.el8_4.x86_64", }, - "image2": []string{ + "image2": { "/boot/vmlinuz-0-rescue-eb46964329b146e39518c625feab3ea0", "/boot/vmlinuz-5.14.0-362.24.1.el9_3.aarch64", "/boot/vmlinuz-5.14.0-427.31.1.el9_4.aarch64+debug", diff --git a/internal/app/wwctl/image/kernels/root.go b/internal/app/wwctl/image/kernels/root.go index 834c66a3..9d191918 100644 --- a/internal/app/wwctl/image/kernels/root.go +++ b/internal/app/wwctl/image/kernels/root.go @@ -14,7 +14,7 @@ var ( Long: "This command lists the kernels that are available in the imported images.", RunE: CobraRunE, Aliases: []string{"kernel"}, - ValidArgsFunction: completions.Images, + ValidArgsFunction: completions.Images(0), // no limit } ) diff --git a/internal/app/wwctl/image/list/main.go b/internal/app/wwctl/image/list/main.go index 379717f8..766defcf 100644 --- a/internal/app/wwctl/image/list/main.go +++ b/internal/app/wwctl/image/list/main.go @@ -24,9 +24,13 @@ func CobraRunE(vars *variables) func(cmd *cobra.Command, args []string) (err err if err != nil { return err } + if vars.full { t.AddHeader("IMAGE NAME", "NODES", "KERNEL VERSION", "CREATION TIME", "MODIFICATION TIME", "SIZE") for i := 0; i < len(imageInfo); i++ { + if len(args) > 0 && !util.InSlice(args, imageInfo[i].Name) { + continue + } createTime := time.Unix(int64(imageInfo[i].CreateDate), 0) modTime := time.Unix(int64(imageInfo[i].ModDate), 0) sz := util.ByteToString(int64(imageInfo[i].ImgSize)) @@ -53,6 +57,9 @@ func CobraRunE(vars *variables) func(cmd *cobra.Command, args []string) (err err } else if vars.kernel { t.AddHeader("IMAGE NAME", "NODES", "KERNEL VERSION") for i := 0; i < len(imageInfo); i++ { + if len(args) > 0 && !util.InSlice(args, imageInfo[i].Name) { + continue + } t.AddLine( imageInfo[i].Name, strconv.FormatUint(uint64(imageInfo[i].NodeCount), 10), @@ -62,6 +69,9 @@ func CobraRunE(vars *variables) func(cmd *cobra.Command, args []string) (err err } else if showSize { t.AddHeader("IMAGE NAME", "NODES", "SIZE") for i := 0; i < len(imageInfo); i++ { + if len(args) > 0 && !util.InSlice(args, imageInfo[i].Name) { + continue + } sz := util.ByteToString(int64(imageInfo[i].ImgSize)) if vars.compressed { sz = util.ByteToString(int64(imageInfo[i].ImgSizeComp)) @@ -84,9 +94,15 @@ func CobraRunE(vars *variables) func(cmd *cobra.Command, args []string) (err err } } else { t.AddHeader("IMAGE NAME") - list, _ := image.ListSources() - for _, cont := range list { - t.AddLine(cont) + list, err := image.ListSources() + if err != nil { + return err + } + for _, name := range list { + if len(args) > 0 && !util.InSlice(args, name) { + continue + } + t.AddLine(name) } } t.Print() diff --git a/internal/app/wwctl/image/list/root.go b/internal/app/wwctl/image/list/root.go index fac941c6..615f140d 100644 --- a/internal/app/wwctl/image/list/root.go +++ b/internal/app/wwctl/image/list/root.go @@ -2,6 +2,7 @@ package list import ( "github.com/spf13/cobra" + "github.com/warewulf/warewulf/internal/app/wwctl/completions" ) type variables struct { @@ -22,6 +23,7 @@ func GetCommand() *cobra.Command { Long: "This command will show you the images that are imported into Warewulf.", RunE: CobraRunE(&vars), Aliases: []string{"ls"}, + ValidArgsFunction: completions.Images(0), // no limit } baseCmd.PersistentFlags().BoolVarP(&vars.full, "long", "l", false, "show all") baseCmd.PersistentFlags().BoolVarP(&vars.kernel, "kernel", "k", false, "show kernel version") diff --git a/internal/app/wwctl/image/rename/main.go b/internal/app/wwctl/image/rename/main.go index 100fa749..e0198fc6 100644 --- a/internal/app/wwctl/image/rename/main.go +++ b/internal/app/wwctl/image/rename/main.go @@ -11,10 +11,6 @@ import ( ) func CobraRunE(cmd *cobra.Command, args []string) (err error) { - if len(args) != 2 { - return fmt.Errorf("rename requires 2 arguments: %d provided", len(args)) - } - crp := &wwapiv1.ImageRenameParameter{ ImageName: args[0], TargetName: args[1], diff --git a/internal/app/wwctl/image/rename/root.go b/internal/app/wwctl/image/rename/root.go index 055cc22a..1a09aba7 100644 --- a/internal/app/wwctl/image/rename/root.go +++ b/internal/app/wwctl/image/rename/root.go @@ -2,7 +2,7 @@ package rename import ( "github.com/spf13/cobra" - "github.com/warewulf/warewulf/internal/pkg/image" + "github.com/warewulf/warewulf/internal/app/wwctl/completions" ) var baseCmd = &cobra.Command{ @@ -12,14 +12,8 @@ var baseCmd = &cobra.Command{ Short: "Rename an existing image", Long: "This command will rename an existing image.", RunE: CobraRunE, - Args: cobra.MinimumNArgs(2), - ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - if len(args) != 0 { - return nil, cobra.ShellCompDirectiveNoFileComp - } - list, _ := image.ListSources() - return list, cobra.ShellCompDirectiveNoFileComp - }, + Args: cobra.ExactArgs(2), + ValidArgsFunction: completions.Images(1), } var SetBuild bool diff --git a/internal/app/wwctl/image/shell/main.go b/internal/app/wwctl/image/shell/main.go index 2f50c76b..29bfa886 100644 --- a/internal/app/wwctl/image/shell/main.go +++ b/internal/app/wwctl/image/shell/main.go @@ -11,36 +11,39 @@ import ( "github.com/spf13/cobra" cntexec "github.com/warewulf/warewulf/internal/app/wwctl/image/exec" "github.com/warewulf/warewulf/internal/pkg/image" + "github.com/warewulf/warewulf/internal/pkg/util" "github.com/warewulf/warewulf/internal/pkg/wwlog" ) func CobraRunE(cmd *cobra.Command, args []string) error { - imageName := args[0] - var allargs []string if !image.ValidSource(imageName) { return fmt.Errorf("unknown Warewulf image: %s", imageName) } - shellName := os.Getenv("SHELL") if !image.ValidSource(imageName) { return fmt.Errorf("unknown Warewulf image: %s", imageName) } + var shells []string - if shellName == "" { - shells = append(shells, "/bin/bash") - } else { - shells = append(shells, shellName, "/bin/bash") + if os.Getenv("SHELL") != "" { + shells = append(shells, os.Getenv("SHELL")) } + shells = append(shells, "/bin/bash", "/bin/sh") + + shellName := "" for _, s := range shells { - if _, err := os.Stat(path.Join(image.RootFsDir(imageName), s)); err == nil { + if util.IsFile(path.Join(image.RootFsDir(imageName), s)) { shellName = s break } } + if shellName == "" { + return fmt.Errorf("no shell found in image: %s", imageName) + } + args = append(args, shellName) - allargs = append(allargs, args...) - wwlog.Debug("Calling exec with args: %s", allargs) + wwlog.Debug("%s: exec with args: %v", imageName, args) cntexec.SetBinds(binds) cntexec.SetNode(nodeName) cntexec.SyncUser = syncUser @@ -48,5 +51,5 @@ func CobraRunE(cmd *cobra.Command, args []string) error { if cntexec.Build { wwlog.Info("Image build will be skipped if the shell ends with a non-zero exit code.") } - return cntexec.CobraRunE(cmd, allargs) + return cntexec.CobraRunE(cmd, args) } diff --git a/internal/app/wwctl/image/shell/root.go b/internal/app/wwctl/image/shell/root.go index 1f76537e..6874e02f 100644 --- a/internal/app/wwctl/image/shell/root.go +++ b/internal/app/wwctl/image/shell/root.go @@ -13,7 +13,7 @@ var ( Long: "Run a interactive shell inside of a warewulf IMAGE.\n", Aliases: []string{"chroot"}, RunE: CobraRunE, - Args: cobra.MinimumNArgs(1), + Args: cobra.ExactArgs(1), ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) != 0 { return nil, cobra.ShellCompDirectiveNoFileComp diff --git a/internal/app/wwctl/image/show/main.go b/internal/app/wwctl/image/show/main.go index 3678403d..04bc4e4f 100644 --- a/internal/app/wwctl/image/show/main.go +++ b/internal/app/wwctl/image/show/main.go @@ -10,7 +10,6 @@ import ( ) func CobraRunE(cmd *cobra.Command, args []string) (err error) { - csp := &wwapiv1.ImageShowParameter{ ImageName: args[0], } diff --git a/internal/app/wwctl/image/show/root.go b/internal/app/wwctl/image/show/root.go index de10fc30..26dfc2f0 100644 --- a/internal/app/wwctl/image/show/root.go +++ b/internal/app/wwctl/image/show/root.go @@ -2,7 +2,7 @@ package show import ( "github.com/spf13/cobra" - "github.com/warewulf/warewulf/internal/pkg/image" + "github.com/warewulf/warewulf/internal/app/wwctl/completions" ) var ( @@ -12,16 +12,9 @@ var ( Short: "Show root fs dir for image", Long: `Shows the base directory for the chroot of the given image. More information about the image can be shown with the '-a' option.`, - RunE: CobraRunE, - ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - if len(args) != 0 { - return nil, cobra.ShellCompDirectiveNoFileComp - } - list, _ := image.ListSources() - return list, cobra.ShellCompDirectiveNoFileComp - }, - - Args: cobra.MinimumNArgs(1), + RunE: CobraRunE, + ValidArgsFunction: completions.Images(0), // no limit + Args: cobra.ExactArgs(1), } ShowAll bool )