From fc8d3863d82778c1724a3dec5ee0cb4e8d04b3ac Mon Sep 17 00:00:00 2001 From: Carter Dodd Date: Sat, 4 Jun 2022 11:14:48 -0500 Subject: [PATCH] use wwctl to re-build provision overlays, update to pass overlaynames --- internal/app/wwctl/overlay/build/main.go | 62 ++++++++++++------------ internal/app/wwctl/overlay/build/root.go | 5 +- internal/app/wwctl/overlay/imprt/main.go | 2 +- internal/pkg/overlay/overlay.go | 8 +-- internal/pkg/util/util.go | 12 +++++ internal/pkg/warewulfd/provision.go | 20 +++++++- internal/pkg/warewulfd/util.go | 42 ++++++---------- 7 files changed, 83 insertions(+), 68 deletions(-) diff --git a/internal/app/wwctl/overlay/build/main.go b/internal/app/wwctl/overlay/build/main.go index 484d249e..4477e6ef 100644 --- a/internal/app/wwctl/overlay/build/main.go +++ b/internal/app/wwctl/overlay/build/main.go @@ -31,63 +31,61 @@ func CobraRunE(cmd *cobra.Command, args []string) error { wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err) os.Exit(1) } - if OverlayDir != "" { - if OverlayName == "" { - return errors.New("no overlay name given") + + if len(args) > 0 { + args = hostlist.Expand(args) + nodes = node.FilterByName(nodes, args) + + if len(nodes) < len(args) { + return errors.New("Failed to find nodes") } + } + + if OverlayDir != "" { + if len(OverlayNames) == 0 { + // TODO: should this behave the same as OverlayDir == "", and build default + // set to overlays? + return errors.New("Must specify overlay(s) to build") + } + if len(args) > 0 { - args = hostlist.Expand(args) + if len(nodes) != 1 { + return errors.New("Must specify one node to build overlay") + } + for _, node := range nodes { - if util.InSlice(node.RuntimeOverlay.GetSlice(), OverlayName) || - util.InSlice(node.SystemOverlay.GetSlice(), OverlayName) { - return overlay.BuildOverlayIndir(node, strings.Split(OverlayName, ","), OverlayDir) - } else { - return errors.New("no node uses the given overlay") - } + return overlay.BuildOverlayIndir(node, OverlayNames), OverlayDir) } } else { + // TODO this seems different than what is set in BuildHostOverlay var host node.NodeInfo var idEntry node.Entry hostname, _ := os.Hostname() - wwlog.Printf(wwlog.INFO, "Building overlay for %s: host\n", hostname) + wwlog.Info("Building overlay for host: %s", hostname) idEntry.Set(hostname) host.Id = idEntry - return overlay.BuildOverlayIndir(host, strings.Split(OverlayName, ","), OverlayDir) + return overlay.BuildOverlayIndir(host, OverlayNames, OverlayDir) } } + if BuildHost || (!BuildHost && !BuildNodes && len(args) == 0 && controller.Warewulf.EnableHostOverlay) { err := overlay.BuildHostOverlay() if err != nil { wwlog.Printf(wwlog.WARN, "host overlay could not be built: %s\n", err) } } - if BuildNodes || (!BuildHost && !BuildNodes) { - if len(args) > 0 { - args = hostlist.Expand(args) - if OverlayName != "" { - err = overlay.BuildSpecificOverlays(node.FilterByName(nodes, args), OverlayName) - } else { - err = overlay.BuildAllOverlays(node.FilterByName(nodes, args)) - } + if BuildNodes || (!BuildHost && !BuildNodes) { + if len(OverlayNames) > 0 { + err = overlay.BuildSpecificOverlays(nodes, OverlayNames) } else { - if OverlayName != "" { - for _, n := range nodes { - if util.InSlice(n.RuntimeOverlay.GetSlice(), OverlayName) || - util.InSlice(n.SystemOverlay.GetSlice(), OverlayName) { - err = overlay.BuildSpecificOverlays([]node.NodeInfo{n}, OverlayName) - } - } - } else { - err = overlay.BuildAllOverlays(nodes) - } + err = overlay.BuildAllOverlays(nodes) } if err != nil { - wwlog.Printf(wwlog.WARN, "Some system overlays failed to be generated: %s\n", err) - + wwlog.Printf(wwlog.WARN, "Some overlays failed to be generated: %s\n", err) } } return nil diff --git a/internal/app/wwctl/overlay/build/root.go b/internal/app/wwctl/overlay/build/root.go index 7437f52b..958a9c92 100644 --- a/internal/app/wwctl/overlay/build/root.go +++ b/internal/app/wwctl/overlay/build/root.go @@ -31,14 +31,15 @@ var ( } BuildHost bool BuildNodes bool - OverlayName string + OverlayNames []string OverlayDir string ) func init() { baseCmd.PersistentFlags().BoolVarP(&BuildHost, "host", "H", false, "Build overlays only for the host") baseCmd.PersistentFlags().BoolVarP(&BuildNodes, "nodes", "N", false, "Build overlays only for the nodes") - baseCmd.PersistentFlags().StringVarP(&OverlayName, "overlay", "O", "", "Build only specific overlay") + baseCmd.PersistentFlags().StringSliceVar(&OverlayNames, "overlay", "O", []string{}, "Build only specific overlay(s)") + if err := baseCmd.RegisterFlagCompletionFunc("overlay", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { list, _ := overlay.FindOverlays() return list, cobra.ShellCompDirectiveNoFileComp diff --git a/internal/app/wwctl/overlay/imprt/main.go b/internal/app/wwctl/overlay/imprt/main.go index 549a7c74..0c209087 100644 --- a/internal/app/wwctl/overlay/imprt/main.go +++ b/internal/app/wwctl/overlay/imprt/main.go @@ -70,7 +70,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } } - return overlay.BuildSpecificOverlays(updateNodes, overlayName) + return overlay.BuildSpecificOverlays(updateNodes, []string{overlayName}) } return nil diff --git a/internal/pkg/overlay/overlay.go b/internal/pkg/overlay/overlay.go index 634b5082..b877a29f 100644 --- a/internal/pkg/overlay/overlay.go +++ b/internal/pkg/overlay/overlay.go @@ -68,13 +68,13 @@ func BuildAllOverlays(nodes []node.NodeInfo) error { // TODO: Add an Overlay Delete for both sourcedir and image -func BuildSpecificOverlays(nodes []node.NodeInfo, overlayName string) error { +func BuildSpecificOverlays(nodes []node.NodeInfo, overlayNames []string) error { for _, n := range nodes { - wwlog.Info("Building overlay for %s: %s", n.Id.Get(), overlayName) - err := BuildOverlay(n, []string{overlayName}) + wwlog.Info("Building overlay for %s: %v", n.Id.Get(), overlayNames) + err := BuildOverlay(n, overlayNames) if err != nil { - return errors.Wrap(err, "could not build overlay "+n.Id.Get()+"/"+overlayName+".img") + return errors.Wrapf(err, "could not build overlay for node %s: %v", n.Id.Get(), overlayNames) } } diff --git a/internal/pkg/util/util.go b/internal/pkg/util/util.go index b0b27cc4..9b7aca45 100644 --- a/internal/pkg/util/util.go +++ b/internal/pkg/util/util.go @@ -654,3 +654,15 @@ func BuildFsImage( return nil } + +/******************************************************************************* + Runs wwctl command +*/ +func RunWWCTL(args ...string) (out string, err error) { + + proc := exec.Command("wwctl", args...) + + out, err := proc.CombinedOutput() + + return out, err +} diff --git a/internal/pkg/warewulfd/provision.go b/internal/pkg/warewulfd/provision.go index 1fd8270b..7cd2bfca 100644 --- a/internal/pkg/warewulfd/provision.go +++ b/internal/pkg/warewulfd/provision.go @@ -158,9 +158,25 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) { for _, overlayname := range stage_overlays { oneoverlaynewer = oneoverlaynewer || util.PathIsNewer(stage_file, overlay.OverlaySourceDir(overlayname)) } + if !util.IsFile(stage_file) || util.PathIsNewer(stage_file, nodepkg.ConfigFile) || oneoverlaynewer { wwlog.Serv("BUILD %15s, overlays %v", node.Id.Get(), stage_overlays) - _ = overlay.BuildOverlay(node, stage_overlays) + + args := []string{} + + for _, overlayname := range stage_overlays { + args = append(args, "-O", overlayname) + } + + args = append(args, node.Id.Get()) + + out, err := util.RunWWCTL("overlay", "build", args...) + + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + wwlog.ErrorExc(err, out) + return + } } } } @@ -219,7 +235,7 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) { w.WriteHeader(http.StatusNotFound) } - err = sendFile(w, stage_file, node.Id.Get()) + err = sendFile(w, req, stage_file, node.Id.Get()) if err != nil { wwlog.ErrorExc(err, "") return diff --git a/internal/pkg/warewulfd/util.go b/internal/pkg/warewulfd/util.go index 2cc609df..62ad7fa6 100644 --- a/internal/pkg/warewulfd/util.go +++ b/internal/pkg/warewulfd/util.go @@ -1,16 +1,18 @@ package warewulfd import ( - "io" "net/http" "os" - "strconv" "github.com/hpcng/warewulf/internal/pkg/wwlog" - "github.com/pkg/errors" ) -func sendFile(w http.ResponseWriter, filename string, sendto string) error { +func sendFile( + w http.ResponseWriter, + req *http.Request, + filename string, + sendto string) error { + fd, err := os.Open(filename) if err != nil { w.WriteHeader(http.StatusInternalServerError) @@ -18,34 +20,20 @@ func sendFile(w http.ResponseWriter, filename string, sendto string) error { } defer fd.Close() - FileHeader := make([]byte, 512) - _, err = fd.Read(FileHeader) + stat, err := fd.Stat() if err != nil { w.WriteHeader(http.StatusInternalServerError) - return errors.Wrap(err, "failed to read header") + return err } - FileContentType := http.DetectContentType(FileHeader) - FileStat, _ := fd.Stat() - FileSize := strconv.FormatInt(FileStat.Size(), 10) - - _, err = fd.Seek(0, 0) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return errors.Wrap(err, "failed to seek") - } - - w.Header().Set("Content-Disposition", "attachment; filename=kernel") - w.Header().Set("Content-Type", FileContentType) - w.Header().Set("Content-Length", FileSize) - - _, err = io.Copy(w, fd) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return errors.Wrap(err, "failed to copy") - } + http.ServeContent( + w, + req, + filename, + stat.ModTime(), + fd ) wwlog.Send("%15s: %s", sendto, filename) - return err + return nil }