From 9e526c23fca06ef5ea550ca0ef4db4fb37cd5d5b Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Wed, 18 Mar 2026 16:58:39 -0600 Subject: [PATCH] Audit and correct documentation, cobra help text, and log messages for accuracy Signed-off-by: Jonathon Anderson --- CHANGELOG.md | 2 +- internal/app/wwctl/configure/hostfile/root.go | 2 +- .../app/wwctl/genconf/warewulfconf/print/root.go | 2 +- internal/app/wwctl/image/imprt/root.go | 12 ++++++------ internal/app/wwctl/image/syncuser/main.go | 2 +- internal/app/wwctl/node/export/root.go | 2 +- internal/app/wwctl/node/root.go | 2 +- internal/app/wwctl/overlay/build/root.go | 2 +- internal/app/wwctl/profile/edit/root.go | 4 ++-- internal/pkg/api/node/set.go | 2 +- internal/pkg/api/profile/set.go | 6 +++--- internal/pkg/image/build.go | 2 +- internal/pkg/node/flags.go | 2 +- internal/pkg/warewulfd/api/overlay.go | 4 ++-- internal/pkg/warewulfd/daemon.go | 2 +- internal/pkg/warewulfd/efi.go | 9 +++++---- internal/pkg/warewulfd/server/server.go | 2 +- internal/pkg/wwlog/wwlog.go | 4 ++-- userdocs/getting-started/quick-reference.rst | 2 +- userdocs/images/selinux.rst | 6 +++--- userdocs/nodes/nodes.rst | 3 ++- userdocs/server/configuration.rst | 8 ++++---- userdocs/server/wwctl.rst | 11 ++++++++--- 23 files changed, 50 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ccba6d63..2104b996 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,7 +54,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - TLS with the command `wwctl configure tls` for key management. Keys can be created automtically or imported. The runtime overlay is if TLS is enabled is not distributed over plain http. - - Documented that booting a node twice fixes broken partition tables - TLS support for `warewulfd` and REST API. - New `wwctl configure tls` command to generate and configure TLS keys and @@ -74,6 +73,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Distinguish between OS images and overlay images in documentation - Updated `MAINTAINING.md` to document golang version policy - Clarified functionality of syncuser commands and overlay in documentation +- Audit and correct documentation, cobra help text, and log messages for accuracy ## v4.6.5, 2026-01-12 diff --git a/internal/app/wwctl/configure/hostfile/root.go b/internal/app/wwctl/configure/hostfile/root.go index 8160d19b..d222f022 100644 --- a/internal/app/wwctl/configure/hostfile/root.go +++ b/internal/app/wwctl/configure/hostfile/root.go @@ -8,7 +8,7 @@ import ( var ( baseCmd = &cobra.Command{ DisableFlagsInUseLine: true, - Use: "hostfile [OPTIONS]", + Use: "hostfile [OPTIONS]", Short: "update hostfile on master", Long: "Manage the hostfile on the master node\n", RunE: CobraRunE, diff --git a/internal/app/wwctl/genconf/warewulfconf/print/root.go b/internal/app/wwctl/genconf/warewulfconf/print/root.go index a1f7ce0c..1362fca0 100644 --- a/internal/app/wwctl/genconf/warewulfconf/print/root.go +++ b/internal/app/wwctl/genconf/warewulfconf/print/root.go @@ -8,7 +8,7 @@ import ( var ( baseCmd = &cobra.Command{ Use: "print", - Short: "print wareweulf.conf", + Short: "print warewulf.conf", Long: "This command prints the actual used warewulf.conf, can be used to create an empty valid warewulf.conf", RunE: CobraRunE, Args: cobra.NoArgs, diff --git a/internal/app/wwctl/image/imprt/root.go b/internal/app/wwctl/image/imprt/root.go index 5f882507..b452fcb7 100644 --- a/internal/app/wwctl/image/imprt/root.go +++ b/internal/app/wwctl/image/imprt/root.go @@ -44,13 +44,13 @@ func init() { baseCmd.PersistentFlags().BoolVarP(&SetUpdate, "update", "u", false, "Overwrite files in an existing image with the files of remote image") baseCmd.PersistentFlags().BoolVarP(&SetBuild, "build", "b", false, "Build image after pulling") baseCmd.PersistentFlags().BoolVar(&SyncUser, "syncuser", false, "Synchronize UIDs/GIDs from host to image") - baseCmd.PersistentFlags().BoolVar(&OciNoHttps, "nohttps", false, "Ignore wrong TLS certificates, superseedes env WAREWULF_OCI_NOHTTPS") - baseCmd.PersistentFlags().StringVar(&OciUsername, "username", "", "Set username for the access to the registry, superseedes env WAREWULF_OCI_USERNAME") - baseCmd.PersistentFlags().StringVar(&OciPassword, "password", "", "Set password for the access to the registry, superseedes env WAREWULF_OCI_PASSWORD") - baseCmd.PersistentFlags().StringVar(&OciPassword, "passwd", "", "Set password for the access to the registry, superseedes env WAREWULF_OCI_PASSWORD") + baseCmd.PersistentFlags().BoolVar(&OciNoHttps, "nohttps", false, "Ignore wrong TLS certificates, supersedes env WAREWULF_OCI_NOHTTPS") + baseCmd.PersistentFlags().StringVar(&OciUsername, "username", "", "Set username for the access to the registry, supersedes env WAREWULF_OCI_USERNAME") + baseCmd.PersistentFlags().StringVar(&OciPassword, "password", "", "Set password for the access to the registry, supersedes env WAREWULF_OCI_PASSWORD") + baseCmd.PersistentFlags().StringVar(&OciPassword, "passwd", "", "Set password for the access to the registry, supersedes env WAREWULF_OCI_PASSWORD") _ = baseCmd.PersistentFlags().MarkHidden("passwd") - baseCmd.PersistentFlags().StringVar(&Platform, "platform", "", "Set other hardware platform e.g. amd64 or arm64, superseedes env WAREWULF_OCI_PLATFORM") - baseCmd.PersistentFlags().StringVar(&Platform, "arch", "", "Set other hardware platform, superseedes env WAREWULF_OCI_PLATFORM") + baseCmd.PersistentFlags().StringVar(&Platform, "platform", "", "Set other hardware platform e.g. amd64 or arm64, supersedes env WAREWULF_OCI_PLATFORM") + baseCmd.PersistentFlags().StringVar(&Platform, "arch", "", "Set other hardware platform, supersedes env WAREWULF_OCI_PLATFORM") _ = baseCmd.PersistentFlags().MarkHidden("arch") } diff --git a/internal/app/wwctl/image/syncuser/main.go b/internal/app/wwctl/image/syncuser/main.go index 8be540b6..7ac3c0d3 100644 --- a/internal/app/wwctl/image/syncuser/main.go +++ b/internal/app/wwctl/image/syncuser/main.go @@ -22,7 +22,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { if write && !build { // when write = true and build = false, we will print a warnning, this is the default case - wwlog.Warn("Syncuser is completed. Rebuild image or add `--build` flag for automatic rebuild after syncuser.") + wwlog.Info("Syncuser is completed. Rebuild image or add `--build` flag for automatic rebuild after syncuser.") } else if write && build { // if write = true and build = true, then it'll trigger the image build after sync cbp := &wwapiv1.ImageBuildParameter{ diff --git a/internal/app/wwctl/node/export/root.go b/internal/app/wwctl/node/export/root.go index bc62d306..db44d9d1 100644 --- a/internal/app/wwctl/node/export/root.go +++ b/internal/app/wwctl/node/export/root.go @@ -8,7 +8,7 @@ import ( var ( baseCmd = &cobra.Command{ DisableFlagsInUseLine: true, - Use: "export NODENAME", + Use: "export NODENAME", Short: "Export nodes as yaml to stdout", Long: "This command exports the given nodes as yaml to stdout.", RunE: CobraRunE, diff --git a/internal/app/wwctl/node/root.go b/internal/app/wwctl/node/root.go index c71e1451..a62f9ba5 100644 --- a/internal/app/wwctl/node/root.go +++ b/internal/app/wwctl/node/root.go @@ -17,7 +17,7 @@ import ( var ( baseCmd = &cobra.Command{ DisableFlagsInUseLine: true, - Use: "node COMMAND [OPTONS]", + Use: "node COMMAND [OPTIONS]", Short: "Node management", Long: "Management of node settings. All node ranges can use brackets to identify\n" + "node ranges. For example: n00[00-4].cluster[0-1] will identify the first 5 nodes\n" + diff --git a/internal/app/wwctl/overlay/build/root.go b/internal/app/wwctl/overlay/build/root.go index 041da655..6cf93723 100644 --- a/internal/app/wwctl/overlay/build/root.go +++ b/internal/app/wwctl/overlay/build/root.go @@ -27,7 +27,7 @@ func init() { panic(err) } baseCmd.PersistentFlags().StringVarP(&OverlayDir, "output", "o", "", `Do not create an overlay image for distribution but write to - the given directory. An overlay must also be ge given to use this option.`) + the given directory. An overlay must also be given to use this option.`) baseCmd.PersistentFlags().IntVar(&Workers, "workers", 0, "The number of parallel workers building overlays (<=0 indicates 1 worker per CPU)") } diff --git a/internal/app/wwctl/profile/edit/root.go b/internal/app/wwctl/profile/edit/root.go index 4b4c323b..0c72ea66 100644 --- a/internal/app/wwctl/profile/edit/root.go +++ b/internal/app/wwctl/profile/edit/root.go @@ -8,8 +8,8 @@ import ( var ( baseCmd = &cobra.Command{ DisableFlagsInUseLine: true, - Use: "edit [OPTIONS] NODENAME", - Short: "Edit node(s) with editor", + Use: "edit [OPTIONS] PROFILE", + Short: "Edit profile(s) with editor", Long: "This command opens an editor for the given profiles.", RunE: CobraRunE, ValidArgsFunction: completions.Profiles, diff --git a/internal/pkg/api/node/set.go b/internal/pkg/api/node/set.go index c19ec97f..62e26209 100644 --- a/internal/pkg/api/node/set.go +++ b/internal/pkg/api/node/set.go @@ -88,7 +88,7 @@ func NodeSetParameterCheck(set *wwapiv1.ConfSetParameter) (nodeDB node.NodesYaml if set.PartitionDelete != "" { for diskname, disk := range nodePtr.Disks { if _, ok := disk.Partitions[set.PartitionDelete]; ok { - wwlog.Verbose("Node: %s, on disk %, deleting partition: %s", nId, diskname, set.PartitionDelete) + wwlog.Verbose("Node: %s, on disk %s, deleting partition: %s", nId, diskname, set.PartitionDelete) delete(disk.Partitions, set.PartitionDelete) } else { return nodeDB, count, fmt.Errorf("partition doesn't exist: %s", set.PartitionDelete) diff --git a/internal/pkg/api/profile/set.go b/internal/pkg/api/profile/set.go index c35b4ade..d726b331 100644 --- a/internal/pkg/api/profile/set.go +++ b/internal/pkg/api/profile/set.go @@ -89,7 +89,7 @@ func ProfileSetParameterCheck(set *wwapiv1.ConfSetParameter) (nodeDB node.NodesY if set.PartitionDelete != "" { for diskname, disk := range profilePtr.Disks { if _, ok := disk.Partitions[set.PartitionDelete]; ok { - wwlog.Verbose("Node: %s, on disk %, deleting partition: %s", profileId, diskname, set.PartitionDelete) + wwlog.Verbose("Profile: %s, on disk %s, deleting partition: %s", profileId, diskname, set.PartitionDelete) delete(disk.Partitions, set.PartitionDelete) } else { return nodeDB, count, fmt.Errorf("partition doesn't exist: %s", set.PartitionDelete) @@ -99,7 +99,7 @@ func ProfileSetParameterCheck(set *wwapiv1.ConfSetParameter) (nodeDB node.NodesY } if set.DiskDelete != "" { if _, ok := profilePtr.Disks[set.DiskDelete]; ok { - wwlog.Verbose("Node: %s, deleting disk: %s", profileId, set.DiskDelete) + wwlog.Verbose("Profile: %s, deleting disk: %s", profileId, set.DiskDelete) delete(profilePtr.Disks, set.DiskDelete) } else { return nodeDB, count, fmt.Errorf("disk doesn't exist: %s", set.DiskDelete) @@ -107,7 +107,7 @@ func ProfileSetParameterCheck(set *wwapiv1.ConfSetParameter) (nodeDB node.NodesY } if set.FilesystemDelete != "" { if _, ok := profilePtr.FileSystems[set.FilesystemDelete]; ok { - wwlog.Verbose("Node: %s, deleting filesystem: %s", profileId, set.FilesystemDelete) + wwlog.Verbose("Profile: %s, deleting filesystem: %s", profileId, set.FilesystemDelete) delete(profilePtr.FileSystems, set.FilesystemDelete) } else { return nodeDB, count, fmt.Errorf("disk doesn't exist: %s", set.FilesystemDelete) diff --git a/internal/pkg/image/build.go b/internal/pkg/image/build.go index a7b49731..116b6301 100644 --- a/internal/pkg/image/build.go +++ b/internal/pkg/image/build.go @@ -34,7 +34,7 @@ func Build(name string, buildForce bool) error { var err error ignore, err = util.ReadFile(excludes_file) if err != nil { - return fmt.Errorf("failed creating directory: %s: %w", imagePath, err) + return fmt.Errorf("failed reading excludes file: %s: %w", excludes_file, err) } } diff --git a/internal/pkg/node/flags.go b/internal/pkg/node/flags.go index a1326197..21eef10c 100644 --- a/internal/pkg/node/flags.go +++ b/internal/pkg/node/flags.go @@ -58,7 +58,7 @@ func (f *boolPtrFlag) Type() string { } type NodeConfDel struct { - TagsDel []string `lopt:"tagdel" comment:"add tags"` + TagsDel []string `lopt:"tagdel" comment:"delete tags"` IpmiTagsDel []string `lopt:"ipmitagdel" comment:"delete ipmi tags"` NetTagsDel []string `lopt:"nettagdel" comment:"delete network tags"` NetDel string `lopt:"netdel" comment:"network to delete"` diff --git a/internal/pkg/warewulfd/api/overlay.go b/internal/pkg/warewulfd/api/overlay.go index 1e09067e..656bba6d 100644 --- a/internal/pkg/warewulfd/api/overlay.go +++ b/internal/pkg/warewulfd/api/overlay.go @@ -101,13 +101,13 @@ func (of *OverlayFile) readContents() (string, error) { fullPath := of.FullPath() f, err := os.ReadFile(fullPath) if err != nil { - wwlog.Warn("os.ReadFile err %w", err) + wwlog.Warn("os.ReadFile err %v", err) return "", err } // Populate the permissions, uid, and gid. s, err := os.Stat(fullPath) if err != nil { - wwlog.Warn("os.Stat err %w", err) + wwlog.Warn("os.Stat err %v", err) return "", err } fileMode := s.Mode() diff --git a/internal/pkg/warewulfd/daemon.go b/internal/pkg/warewulfd/daemon.go index 65bfe4d7..5b4f5d49 100644 --- a/internal/pkg/warewulfd/daemon.go +++ b/internal/pkg/warewulfd/daemon.go @@ -82,7 +82,7 @@ func DaemonStatus() error { } else { err := process.Signal(syscall.Signal(0)) if err != nil { - return fmt.Errorf("failed to send process SIGCONT: %w", err) + return fmt.Errorf("failed to send signal 0 (process existence check): %w", err) } else { wwlog.Serv("Warewulf server is running at PID: %d", pid) } diff --git a/internal/pkg/warewulfd/efi.go b/internal/pkg/warewulfd/efi.go index b853d890..54edfe24 100644 --- a/internal/pkg/warewulfd/efi.go +++ b/internal/pkg/warewulfd/efi.go @@ -6,6 +6,7 @@ import ( "path" "github.com/warewulf/warewulf/internal/pkg/image" + "github.com/warewulf/warewulf/internal/pkg/util" "github.com/warewulf/warewulf/internal/pkg/wwlog" ) @@ -38,20 +39,20 @@ func HandleEfiBoot(w http.ResponseWriter, req *http.Request) { case "grub.efi", "grub-tpm.efi", "grubx64.efi", "grubia32.efi", "grubaa64.efi", "grubarm.efi": stageFile = image.GrubFind(imageName) if stageFile == "" { - wwlog.Error("could't find grub*.efi for %s", imageName) + wwlog.Error("couldn't find grub*.efi for %s", imageName) w.WriteHeader(http.StatusNotFound) return } case "grub.cfg": stageFile = path.Join(ctx.conf.Paths.Sysconfdir, "warewulf/grub/grub.cfg.ww") tmplData = buildTemplateVars(ctx.conf, ctx.rinfo, ctx.remoteNode) - if stageFile == "" { - wwlog.Error("could't find grub.cfg template for %s", imageName) + if !util.IsFile(stageFile) { + wwlog.Error("couldn't find grub.cfg template for %s", imageName) w.WriteHeader(http.StatusNotFound) return } default: - wwlog.ErrorExc(fmt.Errorf("could't find efiboot file: %s", ctx.rinfo.efifile), "") + wwlog.ErrorExc(fmt.Errorf("couldn't find efiboot file: %s", ctx.rinfo.efifile), "") w.WriteHeader(http.StatusNotFound) return } diff --git a/internal/pkg/warewulfd/server/server.go b/internal/pkg/warewulfd/server/server.go index 4b4f30e6..9560a72d 100644 --- a/internal/pkg/warewulfd/server/server.go +++ b/internal/pkg/warewulfd/server/server.go @@ -97,7 +97,7 @@ func RunServer() error { auth := warewulfconf.NewAuthentication() if util.IsFile(conf.Paths.AuthenticationConf()) { if err := auth.Read(conf.Paths.AuthenticationConf()); err != nil { - wwlog.Warn("%w\n", err) + wwlog.Warn("%v", err) } } diff --git a/internal/pkg/wwlog/wwlog.go b/internal/pkg/wwlog/wwlog.go index ddb0bf60..1471fe8d 100644 --- a/internal/pkg/wwlog/wwlog.go +++ b/internal/pkg/wwlog/wwlog.go @@ -167,10 +167,10 @@ func SetLogWriterInfo(newOut io.Writer) { } /* -Set the log ofr info only +Set the log writer for errors */ func SetLogWriterErr(newOut io.Writer) { - logOut = newOut + logErr = newOut } /* diff --git a/userdocs/getting-started/quick-reference.rst b/userdocs/getting-started/quick-reference.rst index 8df9dd06..d9450d8b 100644 --- a/userdocs/getting-started/quick-reference.rst +++ b/userdocs/getting-started/quick-reference.rst @@ -30,7 +30,7 @@ Server management .. code-block:: shell - # Configure all external services (DHCP, TFTP, NFS, SSH, hosts) + # Configure all external services (TLS, warewulfd, TFTP, DHCP, NFS, SSH, hosts) wwctl configure --all # Configure individual services diff --git a/userdocs/images/selinux.rst b/userdocs/images/selinux.rst index 43399a29..2f592f16 100644 --- a/userdocs/images/selinux.rst +++ b/userdocs/images/selinux.rst @@ -5,8 +5,8 @@ SELinux-enabled Images ====================== Warewulf supports booting SELinux-enabled images, though nodes using SELinux -must be configured to use tmpfs for their image file system. ("ramfs," often -used by default, does not support extended file attributes, which are required +must be configured to use tmpfs for their image file system. (The default +``initramfs`` root does not support extended file attributes, which are required for SELinux context labeling.) .. code-block:: bash @@ -26,4 +26,4 @@ in the warewulf-node-images repository. .. _An example: https://github.com/warewulf/warewulf-node-images/tree/main/examples/rockylinux-9-selinux SELinux requires extended attributes, which aren't supported on a default -``initrootfs``. Nodes using SELinux should specify ``--root=tmpfs``. \ No newline at end of file +``initramfs`` root. Nodes using SELinux should specify ``--root=tmpfs``. \ No newline at end of file diff --git a/userdocs/nodes/nodes.rst b/userdocs/nodes/nodes.rst index 4bd139c0..42e40f2a 100644 --- a/userdocs/nodes/nodes.rst +++ b/userdocs/nodes/nodes.rst @@ -113,7 +113,8 @@ To include an explicit comma in the value, enclose the value in inner-quotes. Un-setting Node Fields ---------------------- -To un-set a field value, set the value to ``UNDEF``. +To un-set a field value, set the value to ``UNDEF`` or ``UNSET`` (both are +accepted). .. code-block:: shell diff --git a/userdocs/server/configuration.rst b/userdocs/server/configuration.rst index 5a5b52ba..08d88e5b 100644 --- a/userdocs/server/configuration.rst +++ b/userdocs/server/configuration.rst @@ -124,7 +124,7 @@ warewulf applied to the Warewulf server during configuration. (The host overlay is used to configure external services.) -* ``warewulf::grubboot``: Controls whether iPXE (default) or GRUB is used as the +* ``warewulf:grubboot``: Controls whether iPXE (default) or GRUB is used as the network bootloader. dhcp @@ -270,10 +270,10 @@ to operate in the host environment prior to deployment. * ``image mounts:dest``: The path in the image to use for the mount. -* ``image mounts::readonly``: Whether the mount should be read-only (``true``) +* ``image mounts:readonly``: Whether the mount should be read-only (``true``) or allow writes into the server path (``false``). -* ``image mounts::copy``: When ``true``, copy files into the image rather than +* ``image mounts:copy``: When ``true``, copy files into the image rather than mount. This is useful for initializing files with a starting value from the Warewulf server that should then be maintained as part of the image. @@ -299,7 +299,7 @@ Override paths to images, overlays, and other Warewulf components. * ``paths:sysconfdir``: The parent directory for the ``warewulf`` configuration directory, which stores ``warewulf.conf`` and ``nodes.conf``. -* ``paths::cachedir``: The parent directory for the ``warewulf`` cache of OCI +* ``paths:cachedir``: The parent directory for the ``warewulf`` cache of OCI images during ``wwctl image import``. The cache is stored at ``$cachedir/warewulf`` and can be cleared with ``wwctl clean``. diff --git a/userdocs/server/wwctl.rst b/userdocs/server/wwctl.rst index 3512a45d..ad6d9cfe 100644 --- a/userdocs/server/wwctl.rst +++ b/userdocs/server/wwctl.rst @@ -8,10 +8,10 @@ functionality. * ``configure``: configures the Warewulf server and its external services * ``node``: manages nodes in the cluster -* ``profiles``: defines common sets of node configuration which can be applied +* ``profile``: defines common sets of node configuration which can be applied to multiple nodes * ``image``: configures (node) images -* ``overlays``: manages overlays +* ``overlay``: manages overlays * ``clean``: removes the OCI image cache and leftover overlay images from deleted nodes @@ -49,16 +49,21 @@ through the following command : ================================================================================ n1 RUNTIME_OVERLAY __RUNTIME__.img.gz 16 -For each node, there are 4 different stages: +For each node, there are 7 different stages: +* **EFI** * **IPXE** * **KERNEL** +* **IMAGE** +* **INITRAMFS** * **SYSTEM_OVERLAY** * **RUNTIME_OVERLAY** You can use the ``wwctl node status`` to check communication between the Warewulf server (``warewulfd``) and the Warewulf client (``wwclient``). +.. note:: A provisioning workflow might not use every stage. + Maintenance ===========