Merge pull request #2 from gmkurtzer/vnfs_refactor

Vnfs refactor
This commit is contained in:
Gregory M. Kurtzer
2020-12-06 22:31:26 -08:00
committed by GitHub
66 changed files with 1215 additions and 559 deletions

14
.gitignore vendored
View File

@@ -1,10 +1,10 @@
# project data
.idea
.tools
vendor/
/.idea
/.tools
/vendor/
# binaries
warewulfd
wwbuild
wwclient
wwctl
/warewulfd
/wwbuild
/wwclient
/wwctl

View File

@@ -49,16 +49,16 @@ files: all
install -d -m 0755 /etc/warewulf/ipxe
install -d -m 0755 /var/lib/tftpboot/warewulf/ipxe/
cp -r etc/* /etc/warewulf/
cp -r tftpboot/* /var/lib/tftpboot/warewulf/ipxe/
restorecon -r /var/lib/tftpboot/warewulf
# cp -r tftpboot/* /var/lib/tftpboot/warewulf/ipxe/
# restorecon -r /var/lib/tftpboot/warewulf
cp -r overlays /var/warewulf/
chmod +x /var/warewulf/overlays/system/default/init
chmod +x /var/warewulf/overlays/system/default/init.ww
mkdir -p /var/warewulf/overlays/system/default/warewulf/bin/
cp wwclient /var/warewulf/overlays/system/default/warewulf/bin/
services: files
sudo systemctl enable tftp
sudo systemctl restart tftp
# sudo systemctl enable tftp
# sudo systemctl restart tftp
warewulfd:
cd cmd/warewulfd; go build -mod vendor -tags "$(WW_BUILD_GO_BUILD_TAGS)" -o ../../warewulfd

View File

@@ -17,7 +17,7 @@ To install these and compile Warewulf, do the following:
```
sudo yum install epel-release
sudo yum install golang tftp-server dhcp
sudo yum install --tolerant golang tftp-server dhcp dhcp-server
sudo systemctl stop firewalld
sudo systemctl disable firewalld
@@ -51,59 +51,71 @@ netmask: 255.255.255.0
warewulf:
port: 9873
secure: true
update interval: 60
dhcp:
enabled: true
range start: 192.168.1.150
range end: 192.168.1.200
template: default
systemd name: dhcpd
tftp:
enabled: true
tftproot: /var/lib/tftpboot
systemd name: tftp
```
Note: You may need to change the systemd service names for your distribution.
Once it has been configured, you can have Warewulf configure the services:
```
sudo ./wwctl service dhcp -c
# sudo ./wwctl service tftp -c
sudo ./wwctl service -a
```
#### Use the controller's kernel and default VNFS into your "default" node profile:
Next we are going to start configuring Warewulf. Use the following two commands to
set the kernel and VNFS for the "default" profile which all nodes will utilize, and
then configure node specific information as you add a new node to the configuration:
```
sudo ./wwctl profile set default -K $(uname -r) -V docker://warewulf/centos-8
sudo ./wwctl node add n0000.cluster --netdev eth0 -I 192.168.1.100 -M 255.255.255.0 -G 192.168.1.1 -H 00:0c:29:23:8b:48
```
#### Build the kernel, VNFS, and overlays:
#### Pull and build the VNFS container and kernel:
Once you have added the node, you can start building the needed bootable components.
There are three major groups of data to provision:
1. Kernel: This is the boot kernel and driver overlay pair. The `wwctl kernel build`
command will create these files. The `-a` option will scan your configuration looking
for all needed kernel images and then go through and build them all. The caveat is
that all these kernels must be installed to your host controller node.
command will create these files. The `-a` option will scan your configuration looking
for all needed kernel images and then go through and build them all. The caveat is
that all these kernels must be installed to your host controller node.
1. VNFS: The "VNFS" is the "Virtual Node File System", and that is the template that
nodes will be provisioned to boot into. Warewulf v4 can support standard "chroot"
style VNFS formats (e.g. same as Warewulf 3 and/or Singularity Sandboxes) as well as
OCI (Open Container Initiative) formats which include Docker containers and containers
in Docker Hub. As you can see in the above `wwctl profile set` command, we configured
the VNFS to be a container hosted in Docker Hub. This can also be a local path or a
container in a `docker-daemon`.
1. Container/VNFS: The "VNFS" is the "Virtual Node File System", and that is the template that
nodes will be provisioned to boot into. Warewulf v4 can support standard "chroot"
style VNFS formats (e.g. same as Warewulf 3 and/or Singularity Sandboxes) as well as
OCI (Open Container Initiative) formats which include Docker containers and containers
in Docker Hub. As you can see in the above `wwctl profile set` command, we configured
the VNFS to be a container hosted in Docker Hub. This can also be a local path or a
container in a `docker-daemon`.
1. Overlays: There are two types of overlays, "system" and "runtime". The difference is
that the system overlay is provisioned before `/sbin/init` is called and the runtime
overlay is provisioned after `/sbin/init` is called and is done from the booted operating
system at periodic intervals (the time of this writing, it is ever 30 seconds).
that the system overlay is provisioned before `/sbin/init` is called and the runtime
overlay is provisioned after `/sbin/init` is called and is done from the booted operating
system at periodic intervals (the time of this writing, it is ever 30 seconds).
```
sudo ./wwctl kernel build -a
sudo ./wwctl vnfs build -a
sudo ./wwctl overlay build -sa
sudo ./wwctl container pull docker://warewulf/centos-7 centos-7
sudo ./wwctl container build centos-7
sudo ./wwctl kernel build $(uname -r)
```
#### Set up the default node profile
```
sudo ./wwctl profile set default -K $(uname -r) -C centos-7
sudo ./wwctl profile set default --netdev eth0 -M 255.255.255.0 -G 192.168.1.1
sudo ./wwctl profile list
```
#### Add a node and build node specific overlays
```
sudo ./wwctl node add n0000.cluster --netdev eth0 -I 192.168.1.100 -H 00:0c:29:23:8b:48
sudo ./wwctl node list -a n0000
sudo ./wwctl overlay build -a
```
#### Start the Warewulf daemon:

View File

@@ -4,12 +4,15 @@ echo
echo ================================================================================
echo Warewulf v4 now booting: {{.Fqdn}}
echo
echo Container: {{.ContainerName}}
echo Kernel: {{.KernelVersion}}
echo KernelArgs: {{.KernelArgs}}
echo
set base http://{{.Ipaddr}}:{{.Port}}
kernel ${base}/kernel/{{.Hwaddr}} {{.Kernelargs}} || reboot
initrd ${base}/vnfs/{{.Hwaddr}} || reboot
kernel ${base}/kernel/{{.Hwaddr}} {{.KernelArgs}} || reboot
initrd ${base}/container/{{.Hwaddr}} || reboot
initrd ${base}/kmods/{{.Hwaddr}} || reboot
initrd ${base}/overlay-system/{{.Hwaddr}} || reboot
boot || reboot

View File

@@ -1,7 +1,7 @@
nodeprofiles:
default:
comment: "This profile is automatically included for each node"
vnfs: ""
container name: ""
kernel version: ""
kernel args: crashkernel=no quiet

View File

@@ -9,8 +9,8 @@ dhcp:
range start: 192.168.1.150
range end: 192.168.1.200
template: default
systemd name: dhcp-server
systemd name: dhcpd
tftp:
enabled: true
tftproot: /var/lib/tftpboot
systemd name: tftp-server
systemd name: tftp

View File

@@ -0,0 +1,34 @@
package response
import (
"github.com/hpcng/warewulf/internal/pkg/container"
"log"
"net/http"
)
func ContainerSend(w http.ResponseWriter, req *http.Request) {
node, err := getSanity(req)
if err != nil {
w.WriteHeader(404)
log.Panicln(err)
return
}
if node.ContainerName.Defined() == true {
containerImage := container.ImageFile(node.ContainerName.Get())
err = sendFile(w, containerImage, node.Id.Get())
if err != nil {
log.Printf("ERROR1: %s\n", err)
w.WriteHeader(503)
} else {
log.Printf("SEND: %15s: %s\n", node.Id.Get(), containerImage)
}
} else {
w.WriteHeader(503)
log.Printf("ERROR: No Container set for node %s\n", node.Id.Get())
}
return
}

View File

@@ -13,13 +13,14 @@ import (
)
type iPxeTemplate struct {
Hostname string
Fqdn string
Vnfs string
Hwaddr string
Ipaddr string
Port string
Kernelargs string
Hostname string
Fqdn string
ContainerName string
Hwaddr string
Ipaddr string
Port string
KernelArgs string
KernelVersion string
}
func IpxeSend(w http.ResponseWriter, req *http.Request) {
@@ -70,8 +71,9 @@ func IpxeSend(w http.ResponseWriter, req *http.Request) {
replace.Port = strconv.Itoa(conf.Warewulf.Port)
replace.Hostname = node.Id.Get()
replace.Hwaddr = url[2]
replace.Vnfs = node.Vnfs.Get()
replace.Kernelargs = node.KernelArgs.Get()
replace.ContainerName = node.ContainerName.Get()
replace.KernelArgs = node.KernelArgs.Get()
replace.KernelVersion = node.KernelVersion.Get()
err = tmpl.Execute(w, replace)
if err != nil {

View File

@@ -1,7 +1,7 @@
package response
import (
"github.com/hpcng/warewulf/internal/pkg/config"
"github.com/hpcng/warewulf/internal/pkg/kernel"
"log"
"net/http"
)
@@ -16,7 +16,7 @@ func KernelSend(w http.ResponseWriter, req *http.Request) {
}
if node.KernelVersion.Defined() == true {
fileName := config.KernelImage(node.KernelVersion.Get())
fileName := kernel.KernelImage(node.KernelVersion.Get())
err := sendFile(w, fileName, node.Id.Get())
if err != nil {

View File

@@ -1,7 +1,7 @@
package response
import (
"github.com/hpcng/warewulf/internal/pkg/config"
"github.com/hpcng/warewulf/internal/pkg/kernel"
"log"
"net/http"
)
@@ -16,7 +16,7 @@ func KmodsSend(w http.ResponseWriter, req *http.Request) {
}
if node.KernelVersion.Defined() == true {
fileName := config.KmodsImage(node.KernelVersion.Get())
fileName := kernel.KmodsImage(node.KernelVersion.Get())
err := sendFile(w, fileName, node.Id.Get())
if err != nil {

View File

@@ -1,39 +0,0 @@
package response
import (
"github.com/hpcng/warewulf/internal/pkg/vnfs"
"log"
"net/http"
)
func VnfsSend(w http.ResponseWriter, req *http.Request) {
node, err := getSanity(req)
if err != nil {
w.WriteHeader(404)
log.Panicln(err)
return
}
if node.Vnfs.Defined() == true {
v, err := vnfs.Load(node.Vnfs.Get())
if err != nil {
w.WriteHeader(503)
log.Printf("ERROR: Could not load VNFS: %s\n", node.Id.Get())
return
}
err = sendFile(w, v.Image, node.Id.Get())
if err != nil {
log.Printf("ERROR1: %s\n", err)
} else {
log.Printf("SEND: %15s: %s\n", node.Id.Get(), v.Image)
}
} else {
w.WriteHeader(503)
log.Printf("ERROR: No VNFS set for node %s\n", node.Id.Get())
}
return
}

View File

@@ -14,7 +14,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
http.HandleFunc("/ipxe/", response.IpxeSend)
http.HandleFunc("/kernel/", response.KernelSend)
http.HandleFunc("/kmods/", response.KmodsSend)
http.HandleFunc("/vnfs/", response.VnfsSend)
http.HandleFunc("/container/", response.ContainerSend)
http.HandleFunc("/overlay-system/", response.SystemOverlaySend)
http.HandleFunc("/overlay-runtime", response.RuntimeOverlaySend)

View File

@@ -1,9 +1,9 @@
package build
import (
"github.com/hpcng/warewulf/internal/pkg/container"
"github.com/hpcng/warewulf/internal/pkg/kernel"
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/hpcng/warewulf/internal/pkg/vnfs"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/spf13/cobra"
"os"
@@ -47,7 +47,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
set[node.Vnfs.Get()]++
}
for e := range set {
vnfs.Build(e, buildForce)
container.Build(e, buildForce)
}
}

View File

@@ -6,24 +6,24 @@ import (
var (
baseCmd = &cobra.Command{
Use: "build",
Short: "Warewulf build subcommand",
Long: "Warewulf build is used to build VNFS, kernel, and system-overlay objects for\n" +
"provisioning. The default usage will be to build and/or update anything\n" +
"that seems to be needed.",
RunE: CobraRunE,
Use: "build",
Short: "Warewulf build subcommand",
Long: "Warewulf build is used to build VNFS, kernel, and system-overlay objects for\n" +
"provisioning. The default usage will be to build and/or update anything\n" +
"that seems to be needed.",
RunE: CobraRunE,
}
buildVnfs bool
buildKernel bool
buildVnfs bool
buildKernel bool
buildRuntimeOverlay bool
buildSystemOverlay bool
buildAll bool
buildForce bool
buildSystemOverlay bool
buildAll bool
buildForce bool
)
func init() {
baseCmd.PersistentFlags().BoolVarP(&buildVnfs, "vnfs", "V", false, "Build and/or update VNFS images.")
baseCmd.PersistentFlags().BoolVarP(&buildVnfs, "container", "V", false, "Build and/or update VNFS images.")
baseCmd.PersistentFlags().BoolVarP(&buildKernel, "kernel", "K", false, "Build and/or update Kernel images.")
baseCmd.PersistentFlags().BoolVarP(&buildRuntimeOverlay, "runtime", "R", false, "Build and/or update runtime overlays")
baseCmd.PersistentFlags().BoolVarP(&buildSystemOverlay, "system", "S", false, "Build and/or update system overlays")

View File

@@ -0,0 +1,113 @@
package build
import (
"fmt"
"github.com/hpcng/warewulf/internal/pkg/container"
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/spf13/cobra"
"os"
)
func CobraRunE(cmd *cobra.Command, args []string) error {
var containers []string
if BuildAll == true {
containers, _ = container.ListSources()
} else {
containers = args
}
for _, c := range containers {
if container.ValidSource(c) == false {
wwlog.Printf(wwlog.ERROR, "VNFS name does not exist: %s\n", c)
os.Exit(1)
}
container.Build(c, BuildForce)
}
if SetDefault == true {
if len(containers) != 1 {
wwlog.Printf(wwlog.ERROR, "Can only set default for one container\n")
} else {
nodeDB, err := node.New()
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err)
os.Exit(1)
}
//TODO: Don't loop through profiles, instead have a nodeDB function that goes directly to the map
profiles, _ := nodeDB.FindAllProfiles()
for _, profile := range profiles {
wwlog.Printf(wwlog.DEBUG, "Looking for profile default: %s\n", profile.Id.Get())
if profile.Id.Get() == "default" {
wwlog.Printf(wwlog.DEBUG, "Found profile default, setting container name to: %s\n", containers[0])
profile.ContainerName.Set(containers[0])
nodeDB.ProfileUpdate(profile)
}
}
nodeDB.Persist()
fmt.Printf("Set default profile to container: %s\n", containers[0])
}
}
/*
var nodes []node.NodeInfo
set := make(map[string]int)
n, err := node.New()
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err)
os.Exit(1)
}
if len(args) == 1 && ByNode == true {
var err error
nodes, err = n.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 {
if node.Vnfs.Defined() == true {
set[node.Vnfs.Get()]++
}
}
} else if BuildAll == true {
var err error
nodes, err = n.FindAllNodes()
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not get list of nodes: %s\n", err)
os.Exit(1)
}
for _, node := range nodes {
if node.Vnfs.Defined() == true {
wwlog.Printf(wwlog.VERBOSE, "Adding VNFS to list: %s (%s)\n", node.Vnfs.Get(), node.Id.Get())
set[node.Vnfs.Get()]++
}
}
} 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 := container.Build(v, BuildForce)
if err != nil {
wwlog.Printf(wwlog.ERROR, "%s\n", err)
os.Exit(1)
}
}
*/
return nil
}

View File

@@ -4,25 +4,24 @@ 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),
Use: "build (container 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
BuildAll bool
SetDefault 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)")
baseCmd.PersistentFlags().BoolVar(&SetDefault, "setdefault", false, "Set this container for the default profile")
}
// GetRootCommand returns the root cobra.Command for the application.
func GetCommand() *cobra.Command {
return baseCmd
}
}

View File

@@ -0,0 +1,55 @@
// +build linux
package child
import (
"fmt"
"github.com/hpcng/warewulf/internal/pkg/container"
"github.com/hpcng/warewulf/internal/pkg/util"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/spf13/cobra"
"os"
"path"
"syscall"
)
func CobraRunE(cmd *cobra.Command, args []string) error {
if os.Getpid() != 1 {
wwlog.Printf(wwlog.ERROR, "PID is not 1: %d\n", os.Getpid())
os.Exit(1)
}
containerName := args[0]
if container.ValidSource(containerName) == false {
wwlog.Printf(wwlog.ERROR, "Unknown Warewulf container: %s\n", containerName)
os.Exit(1)
}
containerPath := container.RootFsDir(containerName)
syscall.Mount("", "/", "", syscall.MS_PRIVATE, "")
syscall.Mount("/dev", path.Join(containerPath, "/dev"), "", syscall.MS_BIND, "")
if util.IsFile(path.Join(containerPath, "/etc/resolv.conf")) == true {
syscall.Mount("/etc/resolv.conf", path.Join(containerPath, "/etc/resolv.conf"), "", syscall.MS_BIND, "")
}
syscall.Chroot(containerPath)
os.Chdir("/")
syscall.Mount("rootfs", "rootfs", "", syscall.MS_BIND, "")
syscall.Mount("/proc", "/proc", "proc", 0, "")
ps1string := fmt.Sprintf("[%s] Warewulf> ", containerName)
os.Setenv("PS1", ps1string)
err := syscall.Exec(args[1], args[1:], os.Environ())
if err != nil {
wwlog.Printf(wwlog.ERROR, "%s\n", err)
os.Exit(1)
}
return nil
}

View File

@@ -0,0 +1,14 @@
// +build !linux
package child
import (
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/spf13/cobra"
)
func CobraRunE(cmd *cobra.Command, args []string) error {
wwlog.Printf(wwlog.ERROR, "This command does not work on non-Linux hosts\n")
return nil
}

View File

@@ -0,0 +1,21 @@
package child
import "github.com/spf13/cobra"
var (
baseCmd = &cobra.Command{
Use: "__child",
Hidden: true,
RunE: CobraRunE,
Args: cobra.MinimumNArgs(1),
}
)
func init() {
}
// GetRootCommand returns the root cobra.Command for the application.
func GetCommand() *cobra.Command {
return baseCmd
}

View File

@@ -0,0 +1,40 @@
// +build linux
package exec
import (
"fmt"
"github.com/hpcng/warewulf/internal/pkg/container"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/spf13/cobra"
"os"
"os/exec"
"syscall"
)
func CobraRunE(cmd *cobra.Command, args []string) error {
containerName := args[0]
if container.ValidSource(containerName) == false {
wwlog.Printf(wwlog.ERROR, "Unknown Warewulf container: %s\n", containerName)
os.Exit(1)
}
c := exec.Command("/proc/self/exe", append([]string{"container", "exec", "__child"}, args...)...)
//c := exec.Command("/bin/sh")
c.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS,
}
c.Stdin = os.Stdin
c.Stdout = os.Stdout
c.Stderr = os.Stderr
if err := c.Run(); err != nil {
fmt.Println("ERROR", err)
os.Exit(1)
}
return nil
}

View File

@@ -0,0 +1,14 @@
// +build !linux
package exec
import (
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/spf13/cobra"
)
func CobraRunE(cmd *cobra.Command, args []string) error {
wwlog.Printf(wwlog.ERROR, "This command does not work on non-Linux hosts\n")
return nil
}

View File

@@ -0,0 +1,26 @@
package exec
import (
"github.com/hpcng/warewulf/internal/app/wwctl/container/exec/child"
"github.com/spf13/cobra"
)
var (
baseCmd = &cobra.Command{
Use: "exec",
Short: "Spawn any command inside a Warewulf container",
Long: "Run a command inside a Warewulf container ",
RunE: CobraRunE,
Args: cobra.MinimumNArgs(1),
}
)
func init() {
baseCmd.AddCommand(child.GetCommand())
}
// GetRootCommand returns the root cobra.Command for the application.
func GetCommand() *cobra.Command {
return baseCmd
}

View File

@@ -0,0 +1,89 @@
package list
import (
"fmt"
"github.com/hpcng/warewulf/internal/pkg/container"
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/hpcng/warewulf/internal/pkg/util"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/spf13/cobra"
"os"
)
func CobraRunE(cmd *cobra.Command, args []string) error {
sources, err := container.ListSources()
if err != nil {
wwlog.Printf(wwlog.ERROR, "%s\n", err)
os.Exit(1)
}
nconfig, _ := node.New()
nodes, _ := nconfig.FindAllNodes()
nodemap := make(map[string]int)
for _, n := range nodes {
nodemap[n.ContainerName.Get()]++
}
fmt.Printf("%-35s %-6s %-6s\n", "VNFS NAME", "BUILT", "NODES")
for _, source := range sources {
image := container.ImageFile(source)
if nodemap[source] == 0 {
nodemap[source] = 0
}
fmt.Printf("%-35s %-6t %-6d\n", source, util.IsFile(image), nodemap[source])
}
/*
nconfig, _ := node.New()
nodes, _ := nconfig.FindAllNodes()
nodemap := make(map[string]int)
for _, n := range nodes {
nodemap[n.Vnfs.Get()]++
}
images, _ := ioutil.ReadDir(config.VnfsImageParentDir())
fmt.Printf("%-38s %-16s %s\n", "VNFS Name", "VNFS SIZE(k)", "NODES")
fmt.Println(strings.Repeat("=", 80))
for _, file := range images {
v, err := container.Load(file.Name())
if err == nil {
var vnfs_size int64
if util.IsFile(config.VnfsImage(file.Name())) {
s, _ := os.Stat(config.VnfsImage(file.Name()))
vnfs_size = s.Size() / 1024
}
if nodemap[v.Source] > 0 {
fmt.Printf("%-38s %-16d %d\n", v.Source, vnfs_size, nodemap[v.Source])
} else {
fmt.Printf("%-38s %-16d %d\n", v.Source, vnfs_size, 0)
}
}
continue
if util.IsDir(path.Join(config.VnfsImageParentDir(), file.Name())) {
var vnfs_size int64
if util.IsFile(config.VnfsImage(file.Name())) {
s, _ := os.Stat(config.VnfsImage(file.Name()))
vnfs_size = s.Size() / 1024
}
if nodemap[file.Name()] > 0 {
fmt.Printf("%-38s %-16d %d\n", file.Name(), vnfs_size, nodemap[file.Name()])
} else {
fmt.Printf("%-38s %-16d %d\n", file.Name(), vnfs_size, 0)
}
}
}
*/
return nil
}

View File

@@ -4,13 +4,13 @@ import "github.com/spf13/cobra"
var (
baseCmd = &cobra.Command{
Use: "list",
Short: "List VNFS images",
Long: "List VNFS images ",
RunE: CobraRunE,
Use: "list",
Short: "List VNFS images",
Long: "List VNFS images ",
RunE: CobraRunE,
}
SystemOverlay bool
BuildAll bool
BuildAll bool
)
func init() {

View File

@@ -0,0 +1,59 @@
package pull
import (
"fmt"
"github.com/hpcng/warewulf/internal/pkg/container"
"github.com/hpcng/warewulf/internal/pkg/util"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/spf13/cobra"
"os"
"path"
)
func CobraRunE(cmd *cobra.Command, args []string) error {
var name string
uri := args[0]
if len(args) == 2 {
name = args[1]
} else {
name = path.Base(uri)
fmt.Printf("Setting VNFS name: %s\n", name)
}
if container.ValidName(name) == false {
wwlog.Printf(wwlog.ERROR, "VNFS name contains illegal characters: %s\n", name)
os.Exit(1)
}
fullPath := container.SourceDir(name)
if util.IsDir(fullPath) == true {
if SetForce == true {
wwlog.Printf(wwlog.WARN, "Overwriting existing VNFS\n")
err := os.RemoveAll(fullPath)
if err != nil {
wwlog.Printf(wwlog.ERROR, "%s\n", err)
os.Exit(1)
}
} else if SetUpdate == true {
wwlog.Printf(wwlog.WARN, "Updating existing VNFS\n")
} else {
wwlog.Printf(wwlog.ERROR, "VNFS Name exists, specify --force, --update, or choose a different name: %s\n", name)
os.Exit(1)
}
}
err := container.PullURI(uri, name)
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not pull image: %s\n", err)
os.Exit(1)
}
if SetBuild == true {
fmt.Printf("Building container: %s\n", name)
container.Build(name, false)
}
return nil
}

View File

@@ -0,0 +1,28 @@
package pull
import "github.com/spf13/cobra"
var (
baseCmd = &cobra.Command{
Use: "pull",
Short: "Pull Source OCI VNFS images",
Long: "Pull Source OCI VNFS images ",
RunE: CobraRunE,
Args: cobra.MinimumNArgs(1),
}
SetForce bool
SetUpdate bool
SetBuild bool
)
func init() {
baseCmd.PersistentFlags().BoolVarP(&SetForce, "force", "f", false, "Force overwrite of an existing container")
baseCmd.PersistentFlags().BoolVarP(&SetUpdate, "update", "u", false, "Update and overwrite an existing container")
baseCmd.PersistentFlags().BoolVarP(&SetBuild, "build", "b", false, "Build container when after pulling")
}
// GetRootCommand returns the root cobra.Command for the application.
func GetCommand() *cobra.Command {
return baseCmd
}

View File

@@ -0,0 +1,31 @@
package container
import (
"github.com/hpcng/warewulf/internal/app/wwctl/container/build"
"github.com/hpcng/warewulf/internal/app/wwctl/container/exec"
"github.com/hpcng/warewulf/internal/app/wwctl/container/list"
"github.com/hpcng/warewulf/internal/app/wwctl/container/pull"
"github.com/spf13/cobra"
)
var (
baseCmd = &cobra.Command{
Use: "container",
Short: "Container / VNFS image management",
Long: "Virtual Node File System (VNFS) image management",
}
test bool
)
func init() {
baseCmd.AddCommand(build.GetCommand())
baseCmd.AddCommand(list.GetCommand())
baseCmd.AddCommand(pull.GetCommand())
baseCmd.AddCommand(exec.GetCommand())
}
// GetRootCommand returns the root cobra.Command for the application.
func GetCommand() *cobra.Command {
return baseCmd
}

View File

@@ -1,6 +1,7 @@
package build
import (
"fmt"
"github.com/hpcng/warewulf/internal/pkg/kernel"
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
@@ -9,59 +10,96 @@ import (
)
func CobraRunE(cmd *cobra.Command, args []string) error {
var nodes []node.NodeInfo
set := make(map[string]int)
n, err := node.New()
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err)
os.Exit(1)
for _, arg := range args {
err := kernel.Build(arg)
if err != nil {
wwlog.Printf(wwlog.ERROR, "Failed building kernel: %s\n", err)
os.Exit(1)
}
}
if len(args) == 1 && ByNode == true {
var err error
nodes, err = n.SearchByName(args[0])
if SetDefault == true {
if len(args) != 1 {
wwlog.Printf(wwlog.ERROR, "Can only set default for one kernel version\n")
} else {
nodeDB, err := node.New()
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err)
os.Exit(1)
}
//TODO: Don't loop through profiles, instead have a nodeDB function that goes directly to the map
profiles, _ := nodeDB.FindAllProfiles()
for _, profile := range profiles {
wwlog.Printf(wwlog.DEBUG, "Looking for profile default: %s\n", profile.Id.Get())
if profile.Id.Get() == "default" {
wwlog.Printf(wwlog.DEBUG, "Found profile default, setting kernel version to: %s\n", args[0])
profile.KernelVersion.Set(args[0])
nodeDB.ProfileUpdate(profile)
}
}
nodeDB.Persist()
fmt.Printf("Set default kernel version to: %s\n", args[0])
}
}
/*
var nodes []node.NodeInfo
set := make(map[string]int)
n, err := node.New()
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not find nodes for search term: %s\n", args[0])
wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err)
os.Exit(1)
}
for _, node := range nodes {
if node.KernelVersion.Defined() == true {
set[node.KernelVersion.Get()]++
if len(args) == 1 && ByNode == true {
var err error
nodes, err = n.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 {
if node.KernelVersion.Defined() == true {
set[node.KernelVersion.Get()]++
}
}
} else if BuildAll == true {
var err error
nodes, err = n.FindAllNodes()
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not get list of nodes: %s\n", err)
os.Exit(1)
}
for _, node := range nodes {
wwlog.Printf(wwlog.DEBUG, "evaluating node/kernel: %s/%s\n", node.Id.Get(), node.KernelVersion.Get())
if node.KernelVersion.Defined() == true {
set[node.KernelVersion.Get()]++
}
}
} else if len(args) == 1 {
set[args[0]]++
} else {
cmd.Usage()
os.Exit(1)
}
for k := range set {
wwlog.Printf(wwlog.INFO, "Building kernel: %s\n", k)
err := kernel.Build(k)
if err != nil {
wwlog.Printf(wwlog.ERROR, "%s\n", err)
os.Exit(1)
}
}
} else if BuildAll == true {
var err error
nodes, err = n.FindAllNodes()
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not get list of nodes: %s\n", err)
os.Exit(1)
}
for _, node := range nodes {
wwlog.Printf(wwlog.DEBUG, "evaluating node/kernel: %s/%s\n", node.Id.Get(), node.KernelVersion.Get())
if node.KernelVersion.Defined() == true {
set[node.KernelVersion.Get()]++
}
}
} else if len(args) == 1 {
set[args[0]]++
} else {
cmd.Usage()
os.Exit(1)
}
for k := range set {
wwlog.Printf(wwlog.INFO, "Building kernel: %s\n", k)
err := kernel.Build(k)
if err != nil {
wwlog.Printf(wwlog.ERROR, "%s\n", err)
os.Exit(1)
}
}
*/
return nil
}

View File

@@ -1,28 +1,29 @@
package build
import (
"github.com/spf13/cobra"
"github.com/spf13/cobra"
)
var (
baseCmd = &cobra.Command{
Use: "build (kernel version | node search pattern)",
Short: "Kernel Image Build",
Long: "Build kernel images",
RunE: CobraRunE,
Args: cobra.RangeArgs(0,1),
Use: "build (kernel version | node search pattern)",
Short: "Kernel Image Build",
Long: "Build kernel images",
RunE: CobraRunE,
Args: cobra.MinimumNArgs(1),
}
BuildAll bool
ByNode bool
BuildAll bool
ByNode bool
SetDefault bool
)
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(s)")
baseCmd.PersistentFlags().BoolVar(&SetDefault, "setdefault", false, "Set this kernel for the default profile")
}
// GetRootCommand returns the root cobra.Command for the application.
func GetCommand() *cobra.Command {
return baseCmd
}
}

View File

@@ -2,17 +2,22 @@ package list
import (
"fmt"
"github.com/hpcng/warewulf/internal/pkg/config"
"github.com/hpcng/warewulf/internal/pkg/kernel"
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/hpcng/warewulf/internal/pkg/util"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/spf13/cobra"
"io/ioutil"
"os"
"path"
"strings"
)
func CobraRunE(cmd *cobra.Command, args []string) error {
kernels, err := kernel.ListKernels()
if err != nil {
wwlog.Printf(wwlog.ERROR, "%s\n", err)
os.Exit(1)
}
nconfig, _ := node.New()
nodes, _ := nconfig.FindAllNodes()
nodemap := make(map[string]int)
@@ -21,31 +26,53 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
nodemap[n.KernelVersion.Get()]++
}
images, _ := ioutil.ReadDir(config.KernelParentDir())
fmt.Printf("%-35s %-6s %-6s\n", "VNFS NAME", "BUILT", "NODES")
for _, k := range kernels {
image := kernel.KernelImage(k)
fmt.Printf("%-38s %-16s %-16s %s\n", "KERNEL VERSION", "KERNEL SIZE(k)", "KMODS SIZE(k)", "NODES")
fmt.Println(strings.Repeat("=", 80))
if nodemap[k] == 0 {
nodemap[k] = 0
}
fmt.Printf("%-35s %-6t %-6d\n", k, util.IsFile(image), nodemap[k])
for _, file := range images {
if util.IsDir(path.Join(config.KernelParentDir(), file.Name())) {
var kernel_size int64
var kmods_size int64
if util.IsFile(config.KernelImage(file.Name())) {
s, _ := os.Stat(config.KernelImage(file.Name()))
kernel_size = s.Size() / 1024
}
if util.IsFile(config.KmodsImage(file.Name())) {
s, _ := os.Stat(config.KmodsImage(file.Name()))
kmods_size = s.Size() / 1024
}
}
if nodemap[file.Name()] > 0 {
fmt.Printf("%-38s %-16d %-16d %d\n", file.Name(), kernel_size, kmods_size, nodemap[file.Name()])
} else {
fmt.Printf("%-38s %-16d %-16d %d\n", file.Name(), kernel_size, kmods_size, 0)
/*
nconfig, _ := node.New()
nodes, _ := nconfig.FindAllNodes()
nodemap := make(map[string]int)
for _, n := range nodes {
nodemap[n.KernelVersion.Get()]++
}
images, _ := ioutil.ReadDir(config.KernelParentDir())
fmt.Printf("%-38s %-16s %-16s %s\n", "KERNEL VERSION", "KERNEL SIZE(k)", "KMODS SIZE(k)", "NODES")
fmt.Println(strings.Repeat("=", 80))
for _, file := range images {
if util.IsDir(path.Join(config.KernelParentDir(), file.Name())) {
var kernel_size int64
var kmods_size int64
if util.IsFile(config.KernelImage(file.Name())) {
s, _ := os.Stat(config.KernelImage(file.Name()))
kernel_size = s.Size() / 1024
}
if util.IsFile(config.KmodsImage(file.Name())) {
s, _ := os.Stat(config.KmodsImage(file.Name()))
kmods_size = s.Size() / 1024
}
if nodemap[file.Name()] > 0 {
fmt.Printf("%-38s %-16d %-16d %d\n", file.Name(), kernel_size, kmods_size, nodemap[file.Name()])
} else {
fmt.Printf("%-38s %-16d %-16d %d\n", file.Name(), kernel_size, kmods_size, 0)
}
}
}
}
*/
return nil
}

View File

@@ -22,7 +22,7 @@ var (
func init() {
baseCmd.PersistentFlags().StringVarP(&SetGroup, "group", "g", "default", "Group to add nodes to")
baseCmd.PersistentFlags().StringVarP(&SetController, "controller", "c", "localhost", "Controller to add nodes to")
baseCmd.PersistentFlags().StringVarP(&SetNetDev, "netdev", "n", "eth0", "Define the network device to configure")
baseCmd.PersistentFlags().StringVarP(&SetNetDev, "netdev", "N", "eth0", "Define the network device to configure")
baseCmd.PersistentFlags().StringVarP(&SetIpaddr, "ipaddr", "I", "", "Set the node's network device IP address")
baseCmd.PersistentFlags().StringVarP(&SetNetmask, "netmask", "M", "", "Set the node's network device netmask")
baseCmd.PersistentFlags().StringVarP(&SetGateway, "gateway", "G", "", "Set the node's network device gateway")

View File

@@ -50,12 +50,13 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "ClusterName", node.ClusterName.Source(), node.ClusterName.Print())
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "Profiles", "--", strings.Join(node.Profiles, ","))
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "Vnfs", node.Vnfs.Source(), node.Vnfs.Print())
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "ContainerName", node.ContainerName.Source(), node.ContainerName.Print())
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "KernelVersion", node.KernelVersion.Source(), node.KernelVersion.Print())
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "KernelArgs", node.KernelArgs.Source(), node.KernelArgs.Print())
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "RuntimeOverlay", node.RuntimeOverlay.Source(), node.RuntimeOverlay.Print())
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "SystemOverlay", node.SystemOverlay.Source(), node.SystemOverlay.Print())
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "Ipxe", node.Ipxe.Source(), node.Ipxe.Print())
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "Init", node.Init.Source(), node.Init.Print())
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "IpmiIpaddr", node.IpmiIpaddr.Source(), node.IpmiIpaddr.Print())
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "IpmiNetmask", node.IpmiNetmask.Source(), node.IpmiNetmask.Print())
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "IpmiUserName", node.IpmiUserName.Source(), node.IpmiUserName.Print())
@@ -99,11 +100,11 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
}
} else if ShowLong == true {
fmt.Printf("%-22s %-26s %-35s %s\n", "NODE NAME", "KERNEL VERSION", "VNFS IMAGE", "OVERLAYS (S/R)")
fmt.Printf("%-22s %-26s %-35s %s\n", "NODE NAME", "KERNEL VERSION", "CONTAINER", "OVERLAYS (S/R)")
fmt.Println(strings.Repeat("=", 120))
for _, node := range nodes {
fmt.Printf("%-22s %-26s %-35s %s\n", node.Id.Get(), node.KernelVersion.Print(), node.Vnfs.Print(), node.SystemOverlay.Print()+"/"+node.RuntimeOverlay.Print())
fmt.Printf("%-22s %-26s %-35s %s\n", node.Id.Get(), node.KernelVersion.Print(), node.ContainerName.Print(), node.SystemOverlay.Print()+"/"+node.RuntimeOverlay.Print())
}
} else {

View File

@@ -2,6 +2,7 @@ package set
import (
"fmt"
"github.com/hpcng/warewulf/internal/pkg/container"
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/hpcng/warewulf/internal/pkg/util"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
@@ -43,6 +44,23 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
os.Exit(1)
}
if SetContainer != "" {
if container.ValidSource(SetContainer) == true {
imageFile := container.ImageFile(SetContainer)
if util.IsFile(imageFile) == false {
wwlog.Printf(wwlog.ERROR, "Container has not been built: %s\n", SetContainer)
if SetForce == false {
os.Exit(1)
}
}
} else {
wwlog.Printf(wwlog.ERROR, "Container does not exist: %s\n", SetContainer)
if SetForce == false {
os.Exit(1)
}
}
}
for _, n := range nodes {
wwlog.Printf(wwlog.VERBOSE, "Evaluating node: %s\n", n.Id.Get())
@@ -56,10 +74,20 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
os.Exit(1)
}
}
if SetVnfs != "" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting vnfs to: %s\n", n.Id.Get(), SetVnfs)
if SetContainer != "" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting container name to: %s\n", n.Id.Get(), SetContainer)
n.Vnfs.Set(SetVnfs)
n.ContainerName.Set(SetContainer)
err := nodeDB.NodeUpdate(n)
if err != nil {
wwlog.Printf(wwlog.ERROR, "%s\n", err)
os.Exit(1)
}
}
if SetInit != "" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting init command to: %s\n", n.Id.Get(), SetInit)
n.Init.Set(SetInit)
err := nodeDB.NodeUpdate(n)
if err != nil {
wwlog.Printf(wwlog.ERROR, "%s\n", err)

View File

@@ -10,7 +10,7 @@ var (
RunE: CobraRunE,
}
SetComment string
SetVnfs string
SetContainer string
SetKernel string
SetNetDev string
SetIpaddr string
@@ -30,14 +30,17 @@ var (
SetYes bool
SetAddProfile []string
SetDelProfile []string
SetForce bool
SetInit string
)
func init() {
baseCmd.PersistentFlags().StringVar(&SetComment, "comment", "", "Set a comment for this node")
baseCmd.PersistentFlags().StringVarP(&SetVnfs, "vnfs", "V", "", "Set node Virtual Node File System (VNFS)")
baseCmd.PersistentFlags().StringVarP(&SetContainer, "container", "C", "", "Set the container (VNFS) for this node")
baseCmd.PersistentFlags().StringVarP(&SetKernel, "kernel", "K", "", "Set Kernel version for nodes")
baseCmd.PersistentFlags().StringVarP(&SetClusterName, "cluster", "C", "", "Set the node's cluster name")
baseCmd.PersistentFlags().StringVarP(&SetClusterName, "cluster", "c", "", "Set the node's cluster group")
baseCmd.PersistentFlags().StringVarP(&SetIpxe, "ipxe", "P", "", "Set the node's iPXE template name")
baseCmd.PersistentFlags().StringVarP(&SetInit, "init", "i", "", "Define the init process to boot the container")
baseCmd.PersistentFlags().StringVarP(&SetRuntimeOverlay, "runtime", "R", "", "Set the node's runtime overlay")
baseCmd.PersistentFlags().StringVarP(&SetSystemOverlay, "system", "S", "", "Set the node's system overlay")
baseCmd.PersistentFlags().StringVar(&SetIpmiIpaddr, "ipmi", "", "Set the node's IPMI IP address")
@@ -48,7 +51,7 @@ func init() {
baseCmd.PersistentFlags().StringSliceVarP(&SetAddProfile, "addprofile", "p", []string{}, "Add Profile(s) to node")
baseCmd.PersistentFlags().StringSliceVarP(&SetDelProfile, "delprofile", "r", []string{}, "Remove Profile(s) to node")
baseCmd.PersistentFlags().StringVarP(&SetNetDev, "netdev", "n", "", "Define the network device to configure")
baseCmd.PersistentFlags().StringVarP(&SetNetDev, "netdev", "N", "", "Define the network device to configure")
baseCmd.PersistentFlags().StringVarP(&SetIpaddr, "ipaddr", "I", "", "Set the node's network device IP address")
baseCmd.PersistentFlags().StringVarP(&SetNetmask, "netmask", "M", "", "Set the node's network device netmask")
baseCmd.PersistentFlags().StringVarP(&SetGateway, "gateway", "G", "", "Set the node's network device gateway")
@@ -57,6 +60,7 @@ func init() {
baseCmd.PersistentFlags().BoolVarP(&SetNodeAll, "all", "a", false, "Set all nodes")
baseCmd.PersistentFlags().BoolVarP(&SetYes, "yes", "y", false, "Set 'yes' to all questions asked")
baseCmd.PersistentFlags().BoolVarP(&SetForce, "force", "f", false, "Force configuration (even on error)")
}

View File

@@ -37,9 +37,11 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "Comment", profile.Comment.Print())
fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "ClusterName", profile.ClusterName.Print())
fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "Vnfs", profile.Vnfs.Print())
fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "ContainerName", profile.ContainerName.Print())
fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "KernelVersion", profile.KernelVersion.Print())
fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "KernelArgs", profile.KernelArgs.Print())
fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "Init", profile.Init.Print())
fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "RuntimeOverlay", profile.RuntimeOverlay.Print())
fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "SystemOverlay", profile.SystemOverlay.Print())
fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "Ipxe", profile.Ipxe.Print())

View File

@@ -2,7 +2,9 @@ package set
import (
"fmt"
"github.com/hpcng/warewulf/internal/pkg/container"
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/hpcng/warewulf/internal/pkg/util"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
@@ -46,6 +48,23 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
}
}
if SetContainer != "" {
if container.ValidSource(SetContainer) == true {
imageFile := container.ImageFile(SetContainer)
if util.IsFile(imageFile) == false {
wwlog.Printf(wwlog.ERROR, "Container has not been built: %s\n", SetContainer)
if SetForce == false {
os.Exit(1)
}
}
} else {
wwlog.Printf(wwlog.ERROR, "Container name does not exist: %s\n", SetContainer)
if SetForce == false {
os.Exit(1)
}
}
}
for _, p := range profiles {
wwlog.Printf(wwlog.VERBOSE, "Modifying profile: %s\n", p.Id.Get())
@@ -69,16 +88,27 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
os.Exit(1)
}
}
if SetVnfs != "" {
wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting VNFS to: %s\n", p.Id, SetVnfs)
if SetContainer != "" {
wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting Container name to: %s\n", p.Id, SetContainer)
p.Vnfs.Set(SetVnfs)
p.ContainerName.Set(SetContainer)
err := nodeDB.ProfileUpdate(p)
if err != nil {
wwlog.Printf(wwlog.ERROR, "%s\n", err)
os.Exit(1)
}
}
if SetInit != "" {
wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting init command to: %s\n", p.Id, SetInit)
p.Init.Set(SetInit)
err := nodeDB.ProfileUpdate(p)
if err != nil {
wwlog.Printf(wwlog.ERROR, "%s\n", err)
os.Exit(1)
}
}
if SetKernel != "" {
wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting Kernel version to: %s\n", p.Id, SetKernel)

View File

@@ -10,8 +10,9 @@ var (
RunE: CobraRunE,
}
SetAll bool
SetForce bool
SetComment string
SetVnfs string
SetContainer string
SetKernel string
SetClusterName string
SetIpxe string
@@ -26,21 +27,24 @@ var (
SetGateway string
SetHwaddr string
SetNetDevDel bool
SetInit string
)
func init() {
baseCmd.PersistentFlags().StringVar(&SetComment, "comment", "", "Set a comment for this node")
baseCmd.PersistentFlags().StringVarP(&SetVnfs, "vnfs", "V", "", "Set node Virtual Node File System (VNFS)")
baseCmd.PersistentFlags().StringVarP(&SetContainer, "container", "C", "", "Set the container (VNFS) for this node")
baseCmd.PersistentFlags().StringVarP(&SetKernel, "kernel", "K", "", "Set Kernel version for nodes")
baseCmd.PersistentFlags().StringVarP(&SetClusterName, "cluster", "C", "", "Set the node's cluster name")
baseCmd.PersistentFlags().StringVarP(&SetClusterName, "cluster", "c", "", "Set the node's cluster group")
baseCmd.PersistentFlags().StringVarP(&SetIpxe, "ipxe", "P", "", "Set the node's iPXE template name")
baseCmd.PersistentFlags().StringVarP(&SetInit, "init", "i", "", "Define the init process to boot the container")
baseCmd.PersistentFlags().StringVarP(&SetRuntimeOverlay, "runtime", "R", "", "Set the node's runtime overlay")
baseCmd.PersistentFlags().StringVarP(&SetSystemOverlay, "system", "S", "", "Set the node's system overlay")
baseCmd.PersistentFlags().StringVar(&SetIpmiNetmask, "ipminetmask", "", "Set the node's IPMI netmask")
baseCmd.PersistentFlags().StringVar(&SetIpmiUsername, "ipmiuser", "", "Set the node's IPMI username")
baseCmd.PersistentFlags().StringVar(&SetIpmiPassword, "ipmipass", "", "Set the node's IPMI password")
baseCmd.PersistentFlags().StringVarP(&SetNetDev, "netdev", "n", "", "Define the network device to configure")
baseCmd.PersistentFlags().StringVarP(&SetNetDev, "netdev", "N", "", "Define the network device to configure")
baseCmd.PersistentFlags().StringVarP(&SetIpaddr, "ipaddr", "I", "", "Set the node's network device IP address")
baseCmd.PersistentFlags().StringVarP(&SetNetmask, "netmask", "M", "", "Set the node's network device netmask")
baseCmd.PersistentFlags().StringVarP(&SetGateway, "gateway", "G", "", "Set the node's network device gateway")
@@ -48,6 +52,7 @@ func init() {
baseCmd.PersistentFlags().BoolVar(&SetNetDevDel, "netdel", false, "Delete the node's network device")
baseCmd.PersistentFlags().BoolVarP(&SetAll, "all", "a", false, "Set all profiles")
baseCmd.PersistentFlags().BoolVarP(&SetForce, "force", "f", false, "Force configuration (even on error)")
}
// GetRootCommand returns the root cobra.Command for the application.

View File

@@ -3,9 +3,10 @@ package ready
import (
"fmt"
"github.com/hpcng/warewulf/internal/pkg/config"
"github.com/hpcng/warewulf/internal/pkg/container"
"github.com/hpcng/warewulf/internal/pkg/kernel"
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/hpcng/warewulf/internal/pkg/util"
"github.com/hpcng/warewulf/internal/pkg/vnfs"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/spf13/cobra"
"os"
@@ -35,13 +36,14 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
var runtimeo_good bool
status := true
if node.Vnfs.Get() != "" {
v, _ := vnfs.Load(node.Vnfs.Get())
if util.IsFile(v.Image) == true {
if node.ContainerName.Get() != "" {
vnfsImage := container.ImageFile(node.ContainerName.Get())
if util.IsFile(vnfsImage) == true {
vnfs_good = true
} else {
status = false
wwlog.Printf(wwlog.VERBOSE, "VNFS not found: %s, %s\n", node.Id.Get(), v.Source)
wwlog.Printf(wwlog.VERBOSE, "VNFS not found: %s, %s\n", node.Id.Get(), vnfsImage)
}
} else {
status = false
@@ -49,13 +51,13 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
}
if node.KernelVersion.Get() != "" {
if util.IsFile(config.KernelImage(node.KernelVersion.Get())) == true {
if util.IsFile(kernel.KernelImage(node.KernelVersion.Get())) == true {
kernel_good = true
} else {
status = false
wwlog.Printf(wwlog.VERBOSE, "Node Kernel not found: %s, %s\n", node.Id.Get(), node.KernelVersion.Get())
}
if util.IsFile(config.KmodsImage(node.KernelVersion.Get())) == true {
if util.IsFile(kernel.KmodsImage(node.KernelVersion.Get())) == true {
kmods_good = true
} else {
status = false

View File

@@ -1,13 +1,13 @@
package wwctl
import (
"github.com/hpcng/warewulf/internal/app/wwctl/container"
"github.com/hpcng/warewulf/internal/app/wwctl/kernel"
"github.com/hpcng/warewulf/internal/app/wwctl/node"
"github.com/hpcng/warewulf/internal/app/wwctl/overlay"
"github.com/hpcng/warewulf/internal/app/wwctl/profile"
"github.com/hpcng/warewulf/internal/app/wwctl/ready"
"github.com/hpcng/warewulf/internal/app/wwctl/service"
"github.com/hpcng/warewulf/internal/app/wwctl/vnfs"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/spf13/cobra"
@@ -32,7 +32,7 @@ func init() {
rootCmd.AddCommand(overlay.GetCommand())
// rootCmd.AddCommand(controller.GetCommand())
rootCmd.AddCommand(vnfs.GetCommand())
rootCmd.AddCommand(container.GetCommand())
rootCmd.AddCommand(node.GetCommand())
rootCmd.AddCommand(kernel.GetCommand())
// rootCmd.AddCommand(group.GetCommand())

View File

@@ -1,68 +0,0 @@
package build
import (
"fmt"
"github.com/hpcng/warewulf/internal/pkg/node"
"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 []node.NodeInfo
set := make(map[string]int)
n, err := node.New()
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err)
os.Exit(1)
}
if len(args) == 1 && ByNode == true {
var err error
nodes, err = n.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 {
if node.Vnfs.Defined() == true {
set[node.Vnfs.Get()]++
}
}
} else if BuildAll == true {
var err error
nodes, err = n.FindAllNodes()
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not get list of nodes: %s\n", err)
os.Exit(1)
}
for _, node := range nodes {
if node.Vnfs.Defined() == true {
wwlog.Printf(wwlog.VERBOSE, "Adding VNFS to list: %s (%s)\n", node.Vnfs.Get(), node.Id.Get())
set[node.Vnfs.Get()]++
}
}
} 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

@@ -1,63 +0,0 @@
package list
import (
"fmt"
"github.com/hpcng/warewulf/internal/pkg/config"
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/hpcng/warewulf/internal/pkg/util"
"github.com/hpcng/warewulf/internal/pkg/vnfs"
"github.com/spf13/cobra"
"io/ioutil"
"os"
"path"
"strings"
)
func CobraRunE(cmd *cobra.Command, args []string) error {
nconfig, _ := node.New()
nodes, _ := nconfig.FindAllNodes()
nodemap := make(map[string]int)
for _, n := range nodes {
nodemap[n.Vnfs.Get()]++
}
images, _ := ioutil.ReadDir(config.VnfsImageParentDir())
fmt.Printf("%-38s %-16s %s\n", "VNFS Name", "VNFS SIZE(k)", "NODES")
fmt.Println(strings.Repeat("=", 80))
for _, file := range images {
v, err := vnfs.Load(file.Name())
if err == nil {
var vnfs_size int64
if util.IsFile(config.VnfsImage(file.Name())) {
s, _ := os.Stat(config.VnfsImage(file.Name()))
vnfs_size = s.Size() / 1024
}
if nodemap[v.Source] > 0 {
fmt.Printf("%-38s %-16d %d\n", v.Source, vnfs_size, nodemap[v.Source])
} else {
fmt.Printf("%-38s %-16d %d\n", v.Source, vnfs_size, 0)
}
}
continue
if util.IsDir(path.Join(config.VnfsImageParentDir(), file.Name())) {
var vnfs_size int64
if util.IsFile(config.VnfsImage(file.Name())) {
s, _ := os.Stat(config.VnfsImage(file.Name()))
vnfs_size = s.Size() / 1024
}
if nodemap[file.Name()] > 0 {
fmt.Printf("%-38s %-16d %d\n", file.Name(), vnfs_size, nodemap[file.Name()])
} else {
fmt.Printf("%-38s %-16d %d\n", file.Name(), vnfs_size, 0)
}
}
}
return nil
}

View File

@@ -1,27 +0,0 @@
package vnfs
import (
"github.com/hpcng/warewulf/internal/app/wwctl/vnfs/build"
"github.com/hpcng/warewulf/internal/app/wwctl/vnfs/list"
"github.com/spf13/cobra"
)
var (
baseCmd = &cobra.Command{
Use: "vnfs",
Short: "VNFS image management",
Long: "Virtual Node File System (VNFS) image management",
}
test bool
)
func init() {
baseCmd.AddCommand(build.GetCommand())
baseCmd.AddCommand(list.GetCommand())
}
// GetRootCommand returns the root cobra.Command for the application.
func GetCommand() *cobra.Command {
return baseCmd
}

View File

@@ -11,10 +11,6 @@ const (
LocalStateDir = "/var/warewulf"
)
func NodeConfig() string {
return fmt.Sprintf("%s/nodes.conf", LocalStateDir)
}
func OverlayDir() string {
return fmt.Sprintf("%s/overlays/", LocalStateDir)
}
@@ -27,25 +23,13 @@ func RuntimeOverlayDir() string {
return path.Join(OverlayDir(), "/runtime")
}
func VnfsImageParentDir() string {
return fmt.Sprintf("%s/provision/vnfs/", LocalStateDir)
}
func VnfsChrootParentDir() string {
return fmt.Sprintf("%s/chroot/", LocalStateDir)
}
func KernelParentDir() string {
return fmt.Sprintf("%s/provision/kernel/", LocalStateDir)
}
func SystemOverlaySource(overlayName string) string {
if overlayName == "" {
wwlog.Printf(wwlog.ERROR, "System overlay name is not defined\n")
return ""
}
if util.TaintCheck(overlayName, "^[a-zA-Z0-9-._]+$") == false {
if util.ValidString(overlayName, "^[a-zA-Z0-9-._]+$") == false {
wwlog.Printf(wwlog.ERROR, "System overlay name contains illegal characters: %s\n", overlayName)
return ""
}
@@ -59,7 +43,7 @@ func RuntimeOverlaySource(overlayName string) string {
return ""
}
if util.TaintCheck(overlayName, "^[a-zA-Z0-9-._]+$") == false {
if util.ValidString(overlayName, "^[a-zA-Z0-9-._]+$") == false {
wwlog.Printf(wwlog.ERROR, "Runtime overlay name contains illegal characters: %s\n", overlayName)
return ""
}
@@ -67,41 +51,13 @@ func RuntimeOverlaySource(overlayName string) string {
return path.Join(RuntimeOverlayDir(), overlayName)
}
func KernelImage(kernelVersion string) string {
if kernelVersion == "" {
wwlog.Printf(wwlog.ERROR, "Kernel Version is not defined\n")
return ""
}
if util.TaintCheck(kernelVersion, "^[a-zA-Z0-9-._]+$") == false {
wwlog.Printf(wwlog.ERROR, "Runtime overlay name contains illegal characters: %s\n", kernelVersion)
return ""
}
return path.Join(KernelParentDir(), kernelVersion, "vmlinuz")
}
func KmodsImage(kernelVersion string) string {
if kernelVersion == "" {
wwlog.Printf(wwlog.ERROR, "Kernel Version is not defined\n")
return ""
}
if util.TaintCheck(kernelVersion, "^[a-zA-Z0-9-._]+$") == false {
wwlog.Printf(wwlog.ERROR, "Runtime overlay name contains illegal characters: %s\n", kernelVersion)
return ""
}
return path.Join(KernelParentDir(), kernelVersion, "kmods.img")
}
func SystemOverlayImage(nodeName string) string {
if nodeName == "" {
wwlog.Printf(wwlog.ERROR, "Node name is not defined\n")
return ""
}
if util.TaintCheck(nodeName, "^[a-zA-Z0-9-._:]+$") == false {
if util.ValidString(nodeName, "^[a-zA-Z0-9-._:]+$") == false {
wwlog.Printf(wwlog.ERROR, "System overlay name contains illegal characters: %s\n", nodeName)
return ""
}
@@ -115,42 +71,10 @@ func RuntimeOverlayImage(nodeName string) string {
return ""
}
if util.TaintCheck(nodeName, "^[a-zA-Z0-9-._:]+$") == false {
if util.ValidString(nodeName, "^[a-zA-Z0-9-._:]+$") == false {
wwlog.Printf(wwlog.ERROR, "System overlay name contains illegal characters: %s\n", nodeName)
return ""
}
return fmt.Sprintf("%s/provision/overlays/runtime/%s.img", LocalStateDir, nodeName)
}
func VnfsImageDir(uri string) string {
if uri == "" {
wwlog.Printf(wwlog.ERROR, "VNFS URI is not defined\n")
return ""
}
if util.TaintCheck(uri, "^[a-zA-Z0-9-._:]+$") == false {
wwlog.Printf(wwlog.ERROR, "VNFS name contains illegal characters: %s\n", uri)
return ""
}
return path.Join(VnfsImageParentDir(), uri)
}
func VnfsImage(uri string) string {
return path.Join(VnfsImageDir(uri), "image")
}
func VnfsChroot(uri string) string {
if uri == "" {
wwlog.Printf(wwlog.ERROR, "VNFS name is not defined\n")
return ""
}
if util.TaintCheck(uri, "^[a-zA-Z0-9-._:]+$") == false {
wwlog.Printf(wwlog.ERROR, "VNFS name contains illegal characters: %s\n", uri)
return ""
}
return path.Join(VnfsChrootParentDir(), uri)
}

View File

@@ -0,0 +1,54 @@
package container
import (
"fmt"
"github.com/hpcng/warewulf/internal/pkg/util"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"os"
"os/exec"
"path"
)
func Build(name string, buildForce bool) {
rootfsPath := RootFsDir(name)
imagePath := ImageFile(name)
if ValidSource(name) == false {
wwlog.Printf(wwlog.INFO, "%-35s: Skipping (bad path)\n", name)
return
}
if buildForce == false {
wwlog.Printf(wwlog.DEBUG, "Checking if there have been any updates to the VNFS directory\n")
if util.PathIsNewer(rootfsPath, imagePath) {
wwlog.Printf(wwlog.INFO, "%-35s: Skipping, VNFS is current\n", name)
return
}
}
wwlog.Printf(wwlog.DEBUG, "Making parent directory for: %s\n", name)
err := os.MkdirAll(path.Dir(imagePath), 0755)
if err != nil {
fmt.Printf("ERROR: %s\n", err)
return
}
wwlog.Printf(wwlog.DEBUG, "Making parent directory for: %s\n", rootfsPath)
err = os.MkdirAll(path.Dir(rootfsPath), 0755)
if err != nil {
fmt.Printf("ERROR: %s\n", err)
return
}
wwlog.Printf(wwlog.DEBUG, "Building VNFS image: '%s' -> '%s'\n", rootfsPath, imagePath)
cmd := fmt.Sprintf("cd %s; find . | cpio --quiet -o -H newc | gzip -c > \"%s\"", rootfsPath, imagePath)
err = exec.Command("/bin/sh", "-c", cmd).Run()
if err != nil {
wwlog.Printf(wwlog.ERROR, "Failed building VNFS: %s\n", err)
return
}
wwlog.Printf(wwlog.INFO, "%-35s: Done\n", name)
}

View File

@@ -0,0 +1,45 @@
package container
import (
"context"
"github.com/hpcng/warewulf/internal/pkg/config"
"github.com/hpcng/warewulf/internal/pkg/errors"
"github.com/hpcng/warewulf/internal/pkg/oci"
"os"
)
func PullURI(uri string, name string) error {
OciBlobCacheDir := config.LocalStateDir + "/oci/blobs"
err := os.MkdirAll(OciBlobCacheDir, 0755)
if err != nil {
return err
}
if ValidName(name) == false {
return errors.New("VNFS name contains illegal characters: " + name)
}
fullPath := RootFsDir(name)
err = os.MkdirAll(fullPath, 0755)
if err != nil {
return err
}
p, err := oci.NewPuller(
oci.OptSetBlobCachePath(OciBlobCacheDir),
oci.OptSetSystemContext(nil),
)
if err != nil {
return err
}
p.GenerateID(context.Background(), uri)
if err := p.Pull(context.Background(), uri, fullPath); err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,85 @@
package container
import (
"github.com/hpcng/warewulf/internal/pkg/config"
"github.com/hpcng/warewulf/internal/pkg/errors"
"github.com/hpcng/warewulf/internal/pkg/util"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"io/ioutil"
"os"
"path"
)
func ValidName(name string) bool {
if util.ValidString(name, "^[a-zA-Z0-9.:-]+$") == false {
wwlog.Printf(wwlog.WARN, "VNFS name has illegal characters: %s\n", name)
return false
}
return true
}
func SourceParentDir() string {
return path.Join(config.LocalStateDir, "chroots")
}
func SourceDir(name string) string {
return path.Join(SourceParentDir(), name)
}
func RootFsDir(name string) string {
return path.Join(SourceDir(name), "rootfs")
}
func ImageParentDir() string {
return path.Join(config.LocalStateDir, "provision/container/")
}
func ImageFile(name string) string {
return path.Join(ImageParentDir(), name+".img.gz")
}
func ListSources() ([]string, error) {
var ret []string
err := os.MkdirAll(SourceParentDir(), 0755)
if err != nil {
return ret, errors.New("Could not create VNFS source parent directory: " + SourceParentDir())
}
wwlog.Printf(wwlog.DEBUG, "Searching for VNFS Rootfs directories: %s\n", SourceParentDir())
sources, err := ioutil.ReadDir(SourceParentDir())
if err != nil {
return ret, err
}
for _, source := range sources {
wwlog.Printf(wwlog.VERBOSE, "Found VNFS source: %s\n", source.Name())
if ValidName(source.Name()) == false {
continue
}
if ValidSource(source.Name()) == false {
continue
}
ret = append(ret, source.Name())
}
return ret, nil
}
func ValidSource(name string) bool {
fullPath := RootFsDir(name)
if ValidName(name) == false {
return false
}
if util.IsDir(fullPath) == false {
wwlog.Printf(wwlog.WARN, "Location is not a VNFS source directory: %s\n", name)
return false
}
return true
}

View File

@@ -6,17 +6,75 @@ import (
"github.com/hpcng/warewulf/internal/pkg/errors"
"github.com/hpcng/warewulf/internal/pkg/util"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"io/ioutil"
"os"
"os/exec"
"path"
)
func ParentDir() string {
return path.Join(config.LocalStateDir, "provision/kernel")
}
func KernelImage(kernelVersion string) string {
if kernelVersion == "" {
wwlog.Printf(wwlog.ERROR, "Kernel Version is not defined\n")
return ""
}
if util.ValidString(kernelVersion, "^[a-zA-Z0-9-._]+$") == false {
wwlog.Printf(wwlog.ERROR, "Runtime overlay name contains illegal characters: %s\n", kernelVersion)
return ""
}
return path.Join(ParentDir(), kernelVersion, "vmlinuz")
}
func KmodsImage(kernelVersion string) string {
if kernelVersion == "" {
wwlog.Printf(wwlog.ERROR, "Kernel Version is not defined\n")
return ""
}
if util.ValidString(kernelVersion, "^[a-zA-Z0-9-._]+$") == false {
wwlog.Printf(wwlog.ERROR, "Runtime overlay name contains illegal characters: %s\n", kernelVersion)
return ""
}
return path.Join(ParentDir(), kernelVersion, "kmods.img")
}
func ListKernels() ([]string, error) {
var ret []string
err := os.MkdirAll(ParentDir(), 0755)
if err != nil {
return ret, errors.New("Could not create Kernel parent directory: " + ParentDir())
}
wwlog.Printf(wwlog.DEBUG, "Searching for Kernel image directories: %s\n", ParentDir())
kernels, err := ioutil.ReadDir(ParentDir())
if err != nil {
return ret, err
}
for _, kernel := range kernels {
wwlog.Printf(wwlog.VERBOSE, "Found Kernel: %s\n", kernel.Name())
ret = append(ret, kernel.Name())
}
return ret, nil
}
func Build(kernelVersion string) error {
kernelImage := "/boot/vmlinuz-" + kernelVersion
kernelDrivers := "/lib/modules/" + kernelVersion
kernelDestination := config.KernelImage(kernelVersion)
driversDestination := config.KmodsImage(kernelVersion)
kernelDestination := KernelImage(kernelVersion)
driversDestination := KmodsImage(kernelVersion)
// Create the destination paths just in case it doesn't exist
os.MkdirAll(path.Dir(kernelDestination), 0755)
@@ -30,6 +88,7 @@ func Build(kernelVersion string) error {
return errors.New("Could not locate kernel drivers: " + kernelDrivers)
}
wwlog.Printf(wwlog.VERBOSE, "Setting up Kernel\n")
if _, err := os.Stat(kernelImage); err == nil {
err := util.CopyFile(kernelImage, kernelDestination)
if err != nil {
@@ -38,6 +97,7 @@ func Build(kernelVersion string) error {
wwlog.Printf(wwlog.INFO, "%-45s: Done\n", "vmlinuz-"+kernelVersion)
}
wwlog.Printf(wwlog.VERBOSE, "Building Kernel driver image\n")
if _, err := os.Stat(kernelDrivers); err == nil {
cmd := fmt.Sprintf("cd /; find .%s | cpio --quiet -o -H newc -F \"%s\"", kernelDrivers, driversDestination)
err := exec.Command("/bin/sh", "-c", cmd).Run()

View File

@@ -45,6 +45,7 @@ func (self *nodeYaml) FindAllNodes() ([]NodeInfo, error) {
n.SystemOverlay.SetDefault("default")
n.RuntimeOverlay.SetDefault("default")
n.Ipxe.SetDefault("default")
n.Init.SetDefault("/sbin/init")
fullname := strings.SplitN(nodename, ".", 2)
if len(fullname) > 1 {
@@ -59,11 +60,12 @@ func (self *nodeYaml) FindAllNodes() ([]NodeInfo, error) {
n.Id.Set(nodename)
n.Comment.Set(node.Comment)
n.Vnfs.Set(node.Vnfs)
n.ContainerName.Set(node.ContainerName)
n.KernelVersion.Set(node.KernelVersion)
n.KernelArgs.Set(node.KernelArgs)
n.ClusterName.Set(node.ClusterName)
n.Ipxe.Set(node.Ipxe)
n.Init.Set(node.Init)
n.IpmiIpaddr.Set(node.IpmiIpaddr)
n.IpmiNetmask.Set(node.IpmiNetmask)
n.IpmiUserName.Set(node.IpmiUserName)
@@ -97,10 +99,11 @@ func (self *nodeYaml) FindAllNodes() ([]NodeInfo, error) {
n.Comment.SetAlt(self.NodeProfiles[p].Comment, pstring)
n.ClusterName.SetAlt(self.NodeProfiles[p].ClusterName, pstring)
n.Vnfs.SetAlt(self.NodeProfiles[p].Vnfs, pstring)
n.ContainerName.SetAlt(self.NodeProfiles[p].ContainerName, pstring)
n.KernelVersion.SetAlt(self.NodeProfiles[p].KernelVersion, pstring)
n.KernelArgs.SetAlt(self.NodeProfiles[p].KernelArgs, pstring)
n.Ipxe.SetAlt(self.NodeProfiles[p].Ipxe, pstring)
n.Init.SetAlt(self.NodeProfiles[p].Init, pstring)
n.IpmiIpaddr.SetAlt(self.NodeProfiles[p].IpmiIpaddr, pstring)
n.IpmiNetmask.SetAlt(self.NodeProfiles[p].IpmiNetmask, pstring)
n.IpmiUserName.SetAlt(self.NodeProfiles[p].IpmiUserName, pstring)
@@ -140,8 +143,9 @@ func (self *nodeYaml) FindAllProfiles() ([]NodeInfo, error) {
p.Id.Set(name)
p.Comment.Set(profile.Comment)
p.Vnfs.Set(profile.Vnfs)
p.ContainerName.Set(profile.ContainerName)
p.Ipxe.Set(profile.Ipxe)
p.Init.Set(profile.Init)
p.KernelVersion.Set(profile.KernelVersion)
p.KernelArgs.Set(profile.KernelArgs)
p.IpmiNetmask.Set(profile.IpmiNetmask)

View File

@@ -19,7 +19,7 @@ type NodeConf struct {
Comment string `yaml:"comment,omitempty"`
Disabled bool `yaml:"disabled,omitempty"`
ClusterName string `yaml:"cluster name,omitempty"`
Vnfs string `yaml:"vnfs,omitempty"`
ContainerName string `yaml:"container name,omitempty"`
Ipxe string `yaml:"ipxe template,omitempty"`
KernelVersion string `yaml:"kernel version,omitempty"`
KernelArgs string `yaml:"kernel args,omitempty"`
@@ -29,6 +29,7 @@ type NodeConf struct {
IpmiNetmask string `yaml:"ipmi netmask,omitempty"`
RuntimeOverlay string `yaml:"runtime overlay files,omitempty"`
SystemOverlay string `yaml:"system overlay files,omitempty"`
Init string `yaml:"init,omitempty"`
Profiles []string `yaml:"profiles,omitempty"`
NetDevs map[string]*NetDevs `yaml:"network devices,omitempty"`
}
@@ -60,7 +61,7 @@ type NodeInfo struct {
Cid Entry
Comment Entry
ClusterName Entry
Vnfs Entry
ContainerName Entry
Ipxe Entry
KernelVersion Entry
KernelArgs Entry
@@ -70,6 +71,7 @@ type NodeInfo struct {
IpmiPassword Entry
RuntimeOverlay Entry
SystemOverlay Entry
Init Entry //TODO: Finish adding this...
Profiles []string
GroupProfiles []string
NetDevs map[string]*NetDevEntry

View File

@@ -54,9 +54,10 @@ func (self *nodeYaml) NodeUpdate(node NodeInfo) error {
}
self.Nodes[nodeID].Comment = node.Comment.GetReal()
self.Nodes[nodeID].Vnfs = node.Vnfs.GetReal()
self.Nodes[nodeID].ContainerName = node.ContainerName.GetReal()
self.Nodes[nodeID].ClusterName = node.ClusterName.GetReal()
self.Nodes[nodeID].Ipxe = node.Ipxe.GetReal()
self.Nodes[nodeID].Init = node.Init.GetReal()
self.Nodes[nodeID].KernelVersion = node.KernelVersion.GetReal()
self.Nodes[nodeID].KernelArgs = node.KernelArgs.GetReal()
self.Nodes[nodeID].IpmiIpaddr = node.IpmiIpaddr.GetReal()
@@ -125,8 +126,9 @@ func (self *nodeYaml) ProfileUpdate(profile NodeInfo) error {
return errors.New("Profile name does not exist: " + profileID)
}
self.NodeProfiles[profileID].Comment = profile.Comment.GetReal()
self.NodeProfiles[profileID].Vnfs = profile.Vnfs.GetReal()
self.NodeProfiles[profileID].ContainerName = profile.ContainerName.GetReal()
self.NodeProfiles[profileID].Ipxe = profile.Ipxe.GetReal()
self.NodeProfiles[profileID].Init = profile.Init.GetReal()
self.NodeProfiles[profileID].ClusterName = profile.ClusterName.GetReal()
self.NodeProfiles[profileID].KernelVersion = profile.KernelVersion.GetReal()
self.NodeProfiles[profileID].KernelArgs = profile.KernelArgs.GetReal()

View File

@@ -10,7 +10,7 @@ import (
)
const (
defaultCachePath = "/var/warewulf/vnfs-cache/oci/"
defaultCachePath = "/var/warewulf/container-cache/oci/"
blobPrefix = "blobs"
rootfsPrefix = "rootfs"
)
@@ -79,15 +79,15 @@ func NewCache(opts ...CacheOpt) (*Cache, error) {
}
func (c *Cache) Pull(ctx context.Context, uri string, sysCtx *types.SystemContext) (string, error) {
p, err := newPuller(
optSetBlobCachePath(c.blobDir()),
optSetSystemContext(sysCtx),
p, err := NewPuller(
OptSetBlobCachePath(c.blobDir()),
OptSetSystemContext(sysCtx),
)
if err != nil {
return "", err
}
id, err := p.generateID(ctx, uri)
id, err := p.GenerateID(ctx, uri)
if err != nil {
return "", err
}
@@ -107,7 +107,7 @@ func (c *Cache) Pull(ctx context.Context, uri string, sysCtx *types.SystemContex
}
// populate entry
if err := p.pull(ctx, uri, path); err != nil {
if err := p.Pull(ctx, uri, path); err != nil {
// clean up entry on error
os.RemoveAll(path)
return "", err

View File

@@ -23,21 +23,21 @@ import (
type pullerOpt func(*puller) error
func optSetBlobCachePath(path string) pullerOpt {
func OptSetBlobCachePath(path string) pullerOpt {
return func(p *puller) error {
p.blobCachePath = path
return nil
}
}
func optSetTmpDirPath(path string) pullerOpt {
func OptSetTmpDirPath(path string) pullerOpt {
return func(p *puller) error {
p.tmpDirPath = path
return nil
}
}
func optSetSystemContext(s *types.SystemContext) pullerOpt {
func OptSetSystemContext(s *types.SystemContext) pullerOpt {
return func(p *puller) error {
p.sysCtx = s
return nil
@@ -51,7 +51,7 @@ type puller struct {
sysCtx *types.SystemContext
}
func newPuller(opts ...pullerOpt) (*puller, error) {
func NewPuller(opts ...pullerOpt) (*puller, error) {
p := &puller{
// default to a sensible value, but caller should set this with opts
blobCachePath: filepath.Join(defaultCachePath, blobPrefix),
@@ -93,8 +93,8 @@ func getReference(uri string) (types.ImageReference, error) {
}
}
// generateID stores and returns a unique identifier derived from the sha256sum of the image manifest
func (p *puller) generateID(ctx context.Context, uri string) (string, error) {
// GenerateID stores and returns a unique identifier derived from the sha256sum of the image manifest
func (p *puller) GenerateID(ctx context.Context, uri string) (string, error) {
ref, err := getReference(uri)
if err != nil {
return "", fmt.Errorf("unable to parse uri: %v", err)
@@ -114,7 +114,7 @@ func (p *puller) generateID(ctx context.Context, uri string) (string, error) {
return p.id, nil
}
func (p *puller) pull(ctx context.Context, uri, dst string) (err error) {
func (p *puller) Pull(ctx context.Context, uri, dst string) (err error) {
srcRef, err := getReference(uri)
if err != nil {
return fmt.Errorf("unable to parse uri: %v", err)
@@ -135,7 +135,7 @@ func (p *puller) pull(ctx context.Context, uri, dst string) (err error) {
// copy to cache location
_, err = copy.Image(ctx, policyCtx, cacheRef, srcRef, &copy.Options{
ReportWriter: os.Stdout,
SourceCtx: p.sysCtx,
SourceCtx: p.sysCtx,
})
if err != nil {
return err

View File

@@ -1,8 +1,7 @@
package overlay
import (
"github.com/hpcng/warewulf/internal/pkg/util"
"github.com/hpcng/warewulf/internal/pkg/vnfs"
"github.com/hpcng/warewulf/internal/pkg/container"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"io/ioutil"
"path"
@@ -18,24 +17,24 @@ func templateFileInclude(path string) string {
return strings.TrimSuffix(string(content), "\n")
}
func templateVnfsFileInclude(vnfsname string, filepath string) string {
wwlog.Printf(wwlog.DEBUG, "Including VNFS file into template: %s: %s\n", vnfsname, filepath)
func templateContainerFileInclude(containername string, filepath string) string {
wwlog.Printf(wwlog.DEBUG, "Including VNFS file into template: %s: %s\n", containername, filepath)
if vnfsname == "" {
wwlog.Printf(wwlog.WARN, "VNFS not set for template import request: %s: %s\n", vnfsname, filepath)
if containername == "" {
wwlog.Printf(wwlog.WARN, "VNFS not set for template import request: %s: %s\n", containername, filepath)
return ""
}
v, _ := vnfs.Load(vnfsname)
vnfsDir := v.Chroot
if util.IsDir(vnfsDir) == false {
wwlog.Printf(wwlog.WARN, "Template requires VNFS (%s) to be imported: %s\n", vnfsname, filepath)
if container.ValidSource(containername) == false {
wwlog.Printf(wwlog.WARN, "Template required VNFS does not exist: %s\n", containername)
return ""
}
wwlog.Printf(wwlog.DEBUG, "IncludeVnfs file from: %s/%s\n", vnfsDir, filepath)
content, err := ioutil.ReadFile(path.Join(vnfsDir, filepath))
containerDir := container.RootFsDir(containername)
wwlog.Printf(wwlog.DEBUG, "Including file from container: %s:%s\n", containerDir, filepath)
content, err := ioutil.ReadFile(path.Join(containerDir, filepath))
if err != nil {
wwlog.Printf(wwlog.ERROR, "Template include: %s\n", err)

View File

@@ -18,18 +18,17 @@ import (
)
type TemplateStruct struct {
Self struct {
Id string
Hostname string
GroupName string
Vnfs string
IpmiIpaddr string
IpmiNetmask string
IpmiUserName string
IpmiPassword string
NetDevs map[string]*node.NetDevs
}
AllNodes []node.NodeInfo
Id string
Hostname string
GroupName string
Container string
Init string
IpmiIpaddr string
IpmiNetmask string
IpmiUserName string
IpmiPassword string
NetDevs map[string]*node.NetDevs
AllNodes []node.NodeInfo
}
func BuildSystemOverlay(nodeList []node.NodeInfo) error {
@@ -131,22 +130,23 @@ func buildOverlay(nodeList []node.NodeInfo, overlayType string) error {
wwlog.Printf(wwlog.DEBUG, "Processing overlay for node: %s\n", n.Id.Get())
t.Self.Id = n.Id.Get()
t.Self.Hostname = n.Id.Get()
t.Self.Vnfs = n.Vnfs.Get()
t.Self.IpmiIpaddr = n.IpmiIpaddr.Get()
t.Self.IpmiNetmask = n.IpmiNetmask.Get()
t.Self.IpmiUserName = n.IpmiUserName.Get()
t.Self.IpmiPassword = n.IpmiPassword.Get()
t.Self.NetDevs = make(map[string]*node.NetDevs)
t.Id = n.Id.Get()
t.Hostname = n.Id.Get()
t.Container = n.ContainerName.Get()
t.Init = n.Init.Get()
t.IpmiIpaddr = n.IpmiIpaddr.Get()
t.IpmiNetmask = n.IpmiNetmask.Get()
t.IpmiUserName = n.IpmiUserName.Get()
t.IpmiPassword = n.IpmiPassword.Get()
t.NetDevs = make(map[string]*node.NetDevs)
for devname, netdev := range n.NetDevs {
var nd node.NetDevs
t.Self.NetDevs[devname] = &nd
t.Self.NetDevs[devname].Hwaddr = netdev.Hwaddr.Get()
t.Self.NetDevs[devname].Ipaddr = netdev.Ipaddr.Get()
t.Self.NetDevs[devname].Netmask = netdev.Netmask.Get()
t.Self.NetDevs[devname].Gateway = netdev.Gateway.Get()
t.Self.NetDevs[devname].Type = netdev.Type.Get()
t.NetDevs[devname] = &nd
t.NetDevs[devname].Hwaddr = netdev.Hwaddr.Get()
t.NetDevs[devname].Ipaddr = netdev.Ipaddr.Get()
t.NetDevs[devname].Netmask = netdev.Netmask.Get()
t.NetDevs[devname].Gateway = netdev.Gateway.Get()
t.NetDevs[devname].Type = netdev.Type.Get()
}
t.AllNodes = allNodes
@@ -203,8 +203,8 @@ func buildOverlay(nodeList []node.NodeInfo, overlayType string) error {
destFile := strings.TrimSuffix(location, ".ww")
tmpl, err := template.New(path.Base(location)).Funcs(template.FuncMap{
"Include": templateFileInclude,
"IncludeFromVnfs": templateVnfsFileInclude,
"Include": templateFileInclude,
"IncludeFrom": templateContainerFileInclude,
}).ParseGlob(path.Join(OverlayDir, destFile+".ww*"))
if err != nil {
wwlog.Printf(wwlog.ERROR, "%s\n", err)

View File

@@ -114,7 +114,7 @@ func IsFile(path string) bool {
return false
}
func TaintCheck(pattern string, expr string) bool {
func ValidString(pattern string, expr string) bool {
if b, _ := regexp.MatchString(expr, pattern); b == true {
return true
}
@@ -122,7 +122,7 @@ func TaintCheck(pattern string, expr string) bool {
}
func ValidateOrDie(message string, pattern string, expr string) {
if TaintCheck(pattern, expr) == false {
if ValidString(pattern, expr) == false {
wwlog.Printf(wwlog.ERROR, "%s does not validate: '%s'\n", message, pattern)
os.Exit(1)
}

View File

@@ -14,7 +14,7 @@ func BuildDocker(vnfs VnfsObject, buildForce bool) {
wwlog.Printf(wwlog.VERBOSE, "Building OCI Container: %s\n", vnfs.Source)
OciCacheDir := config.LocalStateDir + "/oci"
VnfsHashDir := config.LocalStateDir + "/oci/vnfs"
VnfsHashDir := config.LocalStateDir + "/oci/container"
c, err := oci.NewCache(oci.OptSetCachePath(OciCacheDir))
if err != nil {

View File

@@ -24,8 +24,8 @@ func Load(name string) (VnfsObject, error) {
var ret VnfsObject
if name == "" {
wwlog.Printf(wwlog.DEBUG, "Called vnfs.Load() without a name, returning error\n")
return ret, errors.New("Called vnfs.Load() without a VNFS name")
wwlog.Printf(wwlog.DEBUG, "Called container.Load() without a name, returning error\n")
return ret, errors.New("Called container.Load() without a VNFS name")
}
pathFriendlyName := CleanName(name)
@@ -69,8 +69,8 @@ func New(source string) (VnfsObject, error) {
var ret VnfsObject
if source == "" {
wwlog.Printf(wwlog.DEBUG, "Called vnfs.Load() without a name, returning error\n")
return ret, errors.New("Called vnfs.Load() without a VNFS name")
wwlog.Printf(wwlog.DEBUG, "Called container.Load() without a name, returning error\n")
return ret, errors.New("Called container.Load() without a VNFS name")
}
if util.IsFile(ret.Config) {

View File

@@ -1,2 +1,2 @@
{{IncludeFromVnfs $.Self.Vnfs "/etc/group"}}
{{IncludeFrom $.Container "/etc/group"}}
{{Include "/etc/group"}}

View File

@@ -1,3 +1,3 @@
root::0:0:root:/root:/bin/bash
{{IncludeFromVnfs $.Self.Vnfs "/etc/passwd"}}
{{IncludeFrom $.Container "/etc/passwd"}}
{{Include "/etc/passwd"}}

View File

@@ -1 +1 @@
{{$.Self.Id}}
{{$.Id}}

View File

@@ -1,8 +1,8 @@
DEVICE=eth0
NAME=eth0
IPADDR={{$.Self.NetDevs.eth0.Ipaddr}}
NETMASK={{$.Self.NetDevs.eth0.Netmask}}
GATEWAY={{$.Self.NetDevs.eth0.Gateway}}
HWADDR={{$.Self.NetDevs.eth0.Hwaddr}}
IPADDR={{$.NetDevs.eth0.Ipaddr}}
NETMASK={{$.NetDevs.eth0.Netmask}}
GATEWAY={{$.NetDevs.eth0.Gateway}}
HWADDR={{$.NetDevs.eth0.Hwaddr}}
BOOTPROTO=static
ONBOOT=yes

View File

@@ -1,2 +1,2 @@
NETWORKING=yes
HOSTNAME={{$.Self.Id}}
HOSTNAME={{$.Id}}

View File

@@ -33,8 +33,8 @@ mount -t devtmpfs devtmpfs /dev
nohup /warewulf/bin/wwclient >/var/log/wwclient.log 2>&1 </dev/null &
echo "Calling /sbin/init..."
echo "Calling {{$.Init}}..."
echo
sleep 2
exec /sbin/init
exec {{$.Init}}

View File

@@ -8,10 +8,10 @@ if [ ! -e /dev/ipmi0 ]; then
ls -la /dev/ipmi0
fi
IP="{{$.Self.IpmiIpaddr}}"
NETMASK="{{$.Self.IpmiNetmask}}"
USER="{{$.Self.IpmiUserName}}"
PASS="{{$.Self.IpmiPassword}}"
IP="{{$.IpmiIpaddr}}"
NETMASK="{{$.IpmiNetmask}}"
USER="{{$.IpmiUserName}}"
PASS="{{$.IpmiPassword}}"
echo IP is $IP
echo NETMASK is $NETMASK