Basic functionality of wwctl vnfs build worked out

This commit is contained in:
Gregory Kurtzer
2020-11-18 22:46:23 -08:00
parent 724e1de14c
commit e9132cf6f7
8 changed files with 288 additions and 10 deletions

View File

@@ -19,7 +19,7 @@ var (
func init() {
baseCmd.PersistentFlags().BoolVarP(&BuildAll, "all", "a", false, "Build all overlays (runtime and system)")
baseCmd.PersistentFlags().BoolVarP(&ByNode, "node", "n", false, "Build overlay for a particular node")
baseCmd.PersistentFlags().BoolVarP(&ByNode, "node", "n", false, "Build overlay for a particular node(s)")
}
// GetRootCommand returns the root cobra.Command for the application.

View File

@@ -0,0 +1,57 @@
package build
import (
"fmt"
"github.com/hpcng/warewulf/internal/pkg/assets"
"github.com/hpcng/warewulf/internal/pkg/vnfs"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/spf13/cobra"
"os"
)
func CobraRunE(cmd *cobra.Command, args []string) error {
var nodes []assets.NodeInfo
set := make(map[string]int)
if len(args) == 1 && ByNode == true {
var err error
nodes, err = assets.SearchByName(args[0])
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not find nodes for search term: %s\n", args[0])
os.Exit(1)
}
for _, node := range nodes {
set[node.Vnfs] ++
}
} else if BuildAll == true {
var err error
nodes, err = assets.FindAllNodes()
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not get list of nodes: %s\n", err)
os.Exit(1)
}
for _, node := range nodes {
set[node.Vnfs] ++
}
} else if len(args) == 1 {
set[args[0]] ++
} else {
cmd.Usage()
os.Exit(1)
}
for v := range set {
fmt.Printf("Building VNFS: %s\n", v)
err := vnfs.Build(v, BuildForce)
if err != nil {
wwlog.Printf(wwlog.ERROR, "%s\n", err)
os.Exit(1)
}
}
return nil
}

View File

@@ -0,0 +1,28 @@
package build
import "github.com/spf13/cobra"
var (
baseCmd = &cobra.Command{
Use: "build (vnfs location | node search pattern)",
Short: "VNFS Image Build",
Long: "VNFS kernel images",
RunE: CobraRunE,
Args: cobra.RangeArgs(0,1),
}
BuildForce bool
BuildAll bool
ByNode bool
)
func init() {
baseCmd.PersistentFlags().BoolVarP(&BuildAll, "all", "a", false, "(re)Build all VNFS images for all nodes")
baseCmd.PersistentFlags().BoolVarP(&BuildForce, "force", "f", false, "Force rebuild, even if it isn't necessary")
baseCmd.PersistentFlags().BoolVarP(&ByNode, "node", "n", false, "Build VNFS for a particular node(s)")
}
// GetRootCommand returns the root cobra.Command for the application.
func GetCommand() *cobra.Command {
return baseCmd
}

View File

@@ -1,7 +1,7 @@
package vnfs
import (
"fmt"
"github.com/hpcng/warewulf/internal/app/wwctl/vnfs/build"
"github.com/spf13/cobra"
)
@@ -10,13 +10,12 @@ var (
Use: "vnfs",
Short: "VNFS image management",
Long: "Virtual Node File System (VNFS) image management",
RunE: CobraRunE,
}
test bool
)
func init() {
baseCmd.PersistentFlags().BoolVarP(&test, "test", "t", false, "Testing.")
baseCmd.AddCommand(build.GetCommand())
}
@@ -25,7 +24,3 @@ func GetCommand() *cobra.Command {
return baseCmd
}
func CobraRunE(cmd *cobra.Command, args []string) error {
fmt.Printf("Vnfs: Hello World\n")
return nil
}

View File

@@ -0,0 +1,64 @@
package vnfs
import (
"fmt"
"github.com/hpcng/warewulf/internal/pkg/config"
"github.com/hpcng/warewulf/internal/pkg/util"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"os"
"path"
)
func BuildContainerdir(v VnfsObject, buildForce bool) {
config := config.New()
if _, err := os.Stat(v.Source()); err != nil {
wwlog.Printf(wwlog.INFO, "%-35s: Skipping (bad path)\n", v.Name())
return
}
wwlog.Printf(wwlog.DEBUG, "Checking if there have been any updates to the VNFS directory\n")
if util.PathIsNewer(v.Source(), config.VnfsImage(v.NameClean())) {
if buildForce == false {
wwlog.Printf(wwlog.INFO, "%-35s: Skipping, VNFS is current\n", v.Name())
return
}
}
wwlog.Printf(wwlog.DEBUG, "Making the directory: %s\n", path.Dir(config.VnfsImage(v.NameClean())))
err := os.MkdirAll(path.Dir(config.VnfsImage(v.NameClean())), 0755)
if err != nil {
fmt.Printf("ERROR: %s\n", err)
return
}
wwlog.Printf(wwlog.DEBUG, "Making the directory: %s\n", path.Dir(config.VnfsChroot(v.NameClean())))
err = os.MkdirAll(path.Dir(config.VnfsChroot(v.NameClean())), 0755)
if err != nil {
fmt.Printf("ERROR: %s\n", err)
return
}
wwlog.Printf(wwlog.DEBUG, "Building VNFS image: '%s' -> '%s'\n", v.Source(), config.VnfsImage(v.NameClean()))
err = buildVnfs(v.Source(), config.VnfsImage(v.NameClean()))
if err != nil {
fmt.Printf("ERROR: %s\n", err)
os.Exit(1)
}
// Setup links from OCI rootfs to chroot path
_ = os.Remove(config.VnfsChroot(v.NameClean()) + "-link")
err = os.Symlink(v.Source(), config.VnfsChroot(v.NameClean())+"-link")
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not create symlink for Chroot: %s\n", err)
os.Exit(1)
}
err = os.Rename(config.VnfsChroot(v.NameClean())+"-link", config.VnfsChroot(v.NameClean()))
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not rename link: %s\n", err)
os.Exit(1)
}
wwlog.Printf(wwlog.INFO, "%-35s: Done\n", v.Name())
}

101
internal/pkg/vnfs/docker.go Normal file
View File

@@ -0,0 +1,101 @@
package vnfs
import (
"context"
"fmt"
"github.com/hpcng/warewulf/internal/pkg/config"
"github.com/hpcng/warewulf/internal/pkg/oci"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"os"
"path"
)
func BuildDocker(v VnfsObject, buildForce bool) {
wwlog.Printf(wwlog.VERBOSE, "Building OCI Container: %s\n", v.Source())
config := config.New()
OciCacheDir := config.LocalStateDir + "/oci"
VnfsHashDir := config.LocalStateDir + "/oci/vnfs"
c, err := oci.NewCache(oci.OptSetCachePath(OciCacheDir))
if err != nil {
fmt.Printf("ERROR: %s\n", err)
os.Exit(1)
}
wwlog.Printf(wwlog.VERBOSE, "Downloading OCI container layers\n")
sourcePath, err := c.Pull(context.Background(), v.Source(), nil)
if err != nil {
fmt.Printf("ERROR: %s\n", err)
os.Exit(1)
}
hashDestination := VnfsHashDir + path.Base(sourcePath)
name, err := os.Readlink(config.VnfsImage(v.NameClean()))
if err == nil {
if name == hashDestination && buildForce == false {
wwlog.Printf(wwlog.INFO, "%-35s: Skipping, VNFS is current\n", v.Name())
return
}
}
err = os.MkdirAll(VnfsHashDir, 0755)
if err != nil {
fmt.Printf("ERROR: %s\n", err)
return
}
err = os.MkdirAll(path.Dir(config.VnfsImage(v.NameClean())), 0755)
if err != nil {
fmt.Printf("ERROR: %s\n", err)
return
}
err = os.MkdirAll(path.Dir(config.VnfsChroot(v.NameClean())), 0755)
if err != nil {
fmt.Printf("ERROR: %s\n", err)
return
}
wwlog.Printf(wwlog.VERBOSE, "Building bootable VNFS image\n")
err = buildVnfs(sourcePath, hashDestination)
if err != nil {
fmt.Printf("ERROR: %s\n", err)
os.Exit(1)
}
wwlog.Printf(wwlog.VERBOSE, "Finalizing Build\n")
// Setup links from OCI image to provision path
_ = os.Remove(config.VnfsImage(v.NameClean()) + "-link")
err = os.Symlink(hashDestination, config.VnfsImage(v.NameClean())+"-link")
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not create symlink for Image: %s\n", err)
os.Exit(1)
}
err = os.Rename(config.VnfsImage(v.NameClean())+"-link", config.VnfsImage(v.NameClean()))
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not rename link: %s\n", err)
os.Exit(1)
}
// Setup links from OCI rootfs to chroot path
_ = os.Remove(config.VnfsChroot(v.NameClean()) + "-link")
err = os.Symlink(sourcePath, config.VnfsChroot(v.NameClean())+"-link")
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not create symlink for Chroot: %s\n", err)
os.Exit(1)
}
err = os.Rename(config.VnfsChroot(v.NameClean())+"-link", config.VnfsChroot(v.NameClean()))
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not rename link: %s\n", err)
os.Exit(1)
}
wwlog.Printf(wwlog.INFO, "%-35s: Done\n", v.Name())
return
}

14
internal/pkg/vnfs/util.go Normal file
View File

@@ -0,0 +1,14 @@
package vnfs
import (
"fmt"
"os/exec"
)
func buildVnfs(source string, dest string) error {
cmd := fmt.Sprintf("cd %s; find . | cpio --quiet -o -H newc | gzip -c > \"%s\"", source, dest)
err := exec.Command("/bin/sh", "-c", cmd).Run()
return err
}

View File

@@ -1,12 +1,13 @@
package vnfs
import (
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"path"
"strings"
)
type VnfsObject struct {
SourcePath string
SourcePath string
}
func New(s string) VnfsObject {
@@ -48,4 +49,22 @@ func (self *VnfsObject) Source() string {
}
return self.SourcePath
}
}
func Build(uri string, force bool) error {
v := New(uri)
wwlog.Printf(wwlog.VERBOSE, "Building VNFS: %s\n", uri)
if strings.HasPrefix(uri, "/") {
if strings.HasSuffix(uri, "tar.gz") {
//wwlog.Printf(wwlog.WARN, "Building VNFS from local tarball: %s\n", uri)
wwlog.Printf(wwlog.WARN, "Building VNFS from local tarball is not supported yet: %s\n", uri)
} else {
BuildContainerdir(v, force)
}
} else {
BuildDocker(v, force)
}
return nil
}