Format entire source code using make fmt
Signed-off-by: Jonathon Anderson <janderson@ciq.com>
This commit is contained in:
@@ -4,7 +4,7 @@ package vers42
|
|||||||
* YAML data representations
|
* YAML data representations
|
||||||
******/
|
******/
|
||||||
|
|
||||||
//type nodeYaml struct {
|
// type nodeYaml struct {
|
||||||
type NodeYaml struct { // <-Needs to be exported
|
type NodeYaml struct { // <-Needs to be exported
|
||||||
NodeProfiles map[string]*NodeConf
|
NodeProfiles map[string]*NodeConf
|
||||||
Nodes map[string]*NodeConf
|
Nodes map[string]*NodeConf
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ package vers43
|
|||||||
* YAML data representations
|
* YAML data representations
|
||||||
******/
|
******/
|
||||||
|
|
||||||
//type nodeYaml struct {
|
// type nodeYaml struct {
|
||||||
type NodeYaml struct { // <- needs to be exported
|
type NodeYaml struct { // <- needs to be exported
|
||||||
WWInternal int `yaml:"WW_INTERNAL"`
|
WWInternal int `yaml:"WW_INTERNAL"`
|
||||||
NodeProfiles map[string]*NodeConf
|
NodeProfiles map[string]*NodeConf
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ import (
|
|||||||
var (
|
var (
|
||||||
baseCmd = &cobra.Command{
|
baseCmd = &cobra.Command{
|
||||||
DisableFlagsInUseLine: true,
|
DisableFlagsInUseLine: true,
|
||||||
Use: "build [OPTIONS] CONTAINER [...]",
|
Use: "build [OPTIONS] CONTAINER [...]",
|
||||||
Short: "(Re)build a bootable VNFS image",
|
Short: "(Re)build a bootable VNFS image",
|
||||||
Long: "This command will build a bootable VNFS image from imported CONTAINER image(s).",
|
Long: "This command will build a bootable VNFS image from imported CONTAINER image(s).",
|
||||||
RunE: CobraRunE,
|
RunE: CobraRunE,
|
||||||
Args: cobra.ArbitraryArgs,
|
Args: cobra.ArbitraryArgs,
|
||||||
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||||
if len(args) != 0 {
|
if len(args) != 0 {
|
||||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ var (
|
|||||||
baseCmd = &cobra.Command{
|
baseCmd = &cobra.Command{
|
||||||
DisableFlagsInUseLine: true,
|
DisableFlagsInUseLine: true,
|
||||||
Use: "copy CONTAINER NEW_NAME",
|
Use: "copy CONTAINER NEW_NAME",
|
||||||
Aliases: []string{"cp"},
|
Aliases: []string{"cp"},
|
||||||
Short: "Copy an existing container",
|
Short: "Copy an existing container",
|
||||||
Long: "This command will duplicate an imported container image.",
|
Long: "This command will duplicate an imported container image.",
|
||||||
RunE: CobraRunE,
|
RunE: CobraRunE,
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/container"
|
"github.com/hpcng/warewulf/internal/pkg/container"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/overlay"
|
"github.com/hpcng/warewulf/internal/pkg/overlay"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||||
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
|
"github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
|
||||||
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/warewulfd"
|
"github.com/hpcng/warewulf/internal/pkg/warewulfd"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import (
|
|||||||
var (
|
var (
|
||||||
powerCmd = &cobra.Command{
|
powerCmd = &cobra.Command{
|
||||||
DisableFlagsInUseLine: true,
|
DisableFlagsInUseLine: true,
|
||||||
Use: "console [OPTIONS] NODENAME",
|
Use: "console [OPTIONS] NODENAME",
|
||||||
Short: "Connect to IPMI console",
|
Short: "Connect to IPMI console",
|
||||||
Long: "Start a new IPMI console for NODENAME.",
|
Long: "Start a new IPMI console for NODENAME.",
|
||||||
Args: cobra.MinimumNArgs(1),
|
Args: cobra.MinimumNArgs(1),
|
||||||
RunE: CobraRunE,
|
RunE: CobraRunE,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ var (
|
|||||||
Long: "Management of node settings. All node ranges can use brackets to identify\n" +
|
Long: "Management of node settings. All node ranges can use brackets to identify\n" +
|
||||||
"node ranges. For example: n00[00-4].cluster[0-1] will identify the first 5 nodes\n" +
|
"node ranges. For example: n00[00-4].cluster[0-1] will identify the first 5 nodes\n" +
|
||||||
"in cluster0 and cluster1.",
|
"in cluster0 and cluster1.",
|
||||||
Aliases: []string{"nodes"},
|
Aliases: []string{"nodes"},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ import (
|
|||||||
var (
|
var (
|
||||||
powerCmd = &cobra.Command{
|
powerCmd = &cobra.Command{
|
||||||
DisableFlagsInUseLine: true,
|
DisableFlagsInUseLine: true,
|
||||||
Use: "sensors [OPTIONS] PATTERN",
|
Use: "sensors [OPTIONS] PATTERN",
|
||||||
Short: "Show node IPMI sensor information",
|
Short: "Show node IPMI sensor information",
|
||||||
Long: "Show IPMI sensor information for nodes matching PATTERN.",
|
Long: "Show IPMI sensor information for nodes matching PATTERN.",
|
||||||
Args: cobra.MinimumNArgs(1),
|
Args: cobra.MinimumNArgs(1),
|
||||||
RunE: CobraRunE,
|
RunE: CobraRunE,
|
||||||
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||||
if len(args) != 0 {
|
if len(args) != 0 {
|
||||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/warewulfd"
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/testenv"
|
"github.com/hpcng/warewulf/internal/pkg/testenv"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/warewulfd"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/overlay"
|
"github.com/hpcng/warewulf/internal/pkg/overlay"
|
||||||
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||||
"github.com/hpcng/warewulf/pkg/hostlist"
|
"github.com/hpcng/warewulf/pkg/hostlist"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|||||||
@@ -29,10 +29,10 @@ var (
|
|||||||
return node_names, cobra.ShellCompDirectiveNoFileComp
|
return node_names, cobra.ShellCompDirectiveNoFileComp
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
BuildHost bool
|
BuildHost bool
|
||||||
BuildNodes bool
|
BuildNodes bool
|
||||||
OverlayNames []string
|
OverlayNames []string
|
||||||
OverlayDir string
|
OverlayDir string
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
const initialTemplate = `# This is a Warewulf Template file.
|
const initialTemplate = `# This is a Warewulf Template file.
|
||||||
#
|
#
|
||||||
# This file (suffix '.ww') will be automatically rewritten without the suffix
|
# This file (suffix '.ww') will be automatically rewritten without the suffix
|
||||||
@@ -35,7 +34,6 @@ const initialTemplate = `# This is a Warewulf Template file.
|
|||||||
# Source: {{.BuildSource}}
|
# Source: {{.BuildSource}}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
||||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||||
overlayName := args[0]
|
overlayName := args[0]
|
||||||
fileName := args[1]
|
fileName := args[1]
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import (
|
|||||||
var (
|
var (
|
||||||
powerCmd = &cobra.Command{
|
powerCmd = &cobra.Command{
|
||||||
DisableFlagsInUseLine: true,
|
DisableFlagsInUseLine: true,
|
||||||
Use: "cycle [OPTIONS] [PATTERN ...]",
|
Use: "cycle [OPTIONS] [PATTERN ...]",
|
||||||
Short: "Power cycle the given node(s)",
|
Short: "Power cycle the given node(s)",
|
||||||
Long: "This command cycles power for a set of nodes specified by PATTERN.",
|
Long: "This command cycles power for a set of nodes specified by PATTERN.",
|
||||||
RunE: CobraRunE,
|
RunE: CobraRunE,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import (
|
|||||||
var (
|
var (
|
||||||
powerCmd = &cobra.Command{
|
powerCmd = &cobra.Command{
|
||||||
DisableFlagsInUseLine: true,
|
DisableFlagsInUseLine: true,
|
||||||
Use: "off [OPTIONS] [PATTERN ...]",
|
Use: "off [OPTIONS] [PATTERN ...]",
|
||||||
Short: "Power off the given node(s)",
|
Short: "Power off the given node(s)",
|
||||||
Long: "This command will shutdown power to a set of nodes specified by PATTERN.",
|
Long: "This command will shutdown power to a set of nodes specified by PATTERN.",
|
||||||
RunE: CobraRunE,
|
RunE: CobraRunE,
|
||||||
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||||
if len(args) != 0 {
|
if len(args) != 0 {
|
||||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import (
|
|||||||
var (
|
var (
|
||||||
powerCmd = &cobra.Command{
|
powerCmd = &cobra.Command{
|
||||||
DisableFlagsInUseLine: true,
|
DisableFlagsInUseLine: true,
|
||||||
Use: "reset [OPTIONS] [PATTERN ...]",
|
Use: "reset [OPTIONS] [PATTERN ...]",
|
||||||
Short: "Issue a reset to node(s)",
|
Short: "Issue a reset to node(s)",
|
||||||
Long: "This command will issue a reset to a set of nodes specified by PATTERN.",
|
Long: "This command will issue a reset to a set of nodes specified by PATTERN.",
|
||||||
RunE: CobraRunE,
|
RunE: CobraRunE,
|
||||||
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||||
if len(args) != 0 {
|
if len(args) != 0 {
|
||||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ import (
|
|||||||
var (
|
var (
|
||||||
baseCmd = &cobra.Command{
|
baseCmd = &cobra.Command{
|
||||||
DisableFlagsInUseLine: true,
|
DisableFlagsInUseLine: true,
|
||||||
Use: "power COMMAND [OPTIONS]",
|
Use: "power COMMAND [OPTIONS]",
|
||||||
Short: "Warewulf node power management",
|
Short: "Warewulf node power management",
|
||||||
Long: "This command controls the power state of nodes.",
|
Long: "This command controls the power state of nodes.",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import (
|
|||||||
var (
|
var (
|
||||||
powerCmd = &cobra.Command{
|
powerCmd = &cobra.Command{
|
||||||
DisableFlagsInUseLine: true,
|
DisableFlagsInUseLine: true,
|
||||||
Use: "soft",
|
Use: "soft",
|
||||||
Short: "Gracefully shuts down the given node(s)",
|
Short: "Gracefully shuts down the given node(s)",
|
||||||
Long: "This command uses the operationg system to shut down the set of nodes specified by PATTERN.",
|
Long: "This command uses the operationg system to shut down the set of nodes specified by PATTERN.",
|
||||||
RunE: CobraRunE,
|
RunE: CobraRunE,
|
||||||
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||||
if len(args) != 0 {
|
if len(args) != 0 {
|
||||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import (
|
|||||||
var (
|
var (
|
||||||
powerCmd = &cobra.Command{
|
powerCmd = &cobra.Command{
|
||||||
DisableFlagsInUseLine: true,
|
DisableFlagsInUseLine: true,
|
||||||
Use: "status [OPTIONS] [PATTERN ...]",
|
Use: "status [OPTIONS] [PATTERN ...]",
|
||||||
Short: "Show power status for the given node(s)",
|
Short: "Show power status for the given node(s)",
|
||||||
Long: "This command displays the power status of a set of nodes specified by PATTERN.",
|
Long: "This command displays the power status of a set of nodes specified by PATTERN.",
|
||||||
RunE: CobraRunE,
|
RunE: CobraRunE,
|
||||||
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||||
if len(args) != 0 {
|
if len(args) != 0 {
|
||||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
|
||||||
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/warewulfd"
|
"github.com/hpcng/warewulf/internal/pkg/warewulfd"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ import (
|
|||||||
"github.com/hpcng/warewulf/internal/app/wwctl/server"
|
"github.com/hpcng/warewulf/internal/app/wwctl/server"
|
||||||
"github.com/hpcng/warewulf/internal/app/wwctl/ssh"
|
"github.com/hpcng/warewulf/internal/app/wwctl/ssh"
|
||||||
"github.com/hpcng/warewulf/internal/app/wwctl/version"
|
"github.com/hpcng/warewulf/internal/app/wwctl/version"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/help"
|
|
||||||
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/help"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import "github.com/spf13/cobra"
|
|||||||
var (
|
var (
|
||||||
baseCmd = &cobra.Command{
|
baseCmd = &cobra.Command{
|
||||||
DisableFlagsInUseLine: true,
|
DisableFlagsInUseLine: true,
|
||||||
Use: "reload [OPTIONS]",
|
Use: "reload [OPTIONS]",
|
||||||
Short: "Reload the Warewulf server configuration",
|
Short: "Reload the Warewulf server configuration",
|
||||||
RunE: CobraRunE,
|
RunE: CobraRunE,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import "github.com/spf13/cobra"
|
|||||||
var (
|
var (
|
||||||
baseCmd = &cobra.Command{
|
baseCmd = &cobra.Command{
|
||||||
DisableFlagsInUseLine: true,
|
DisableFlagsInUseLine: true,
|
||||||
Use: "restart [OPTIONS]",
|
Use: "restart [OPTIONS]",
|
||||||
Short: "Restart the Warewulf server",
|
Short: "Restart the Warewulf server",
|
||||||
RunE: CobraRunE,
|
RunE: CobraRunE,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ import (
|
|||||||
var (
|
var (
|
||||||
baseCmd = &cobra.Command{
|
baseCmd = &cobra.Command{
|
||||||
DisableFlagsInUseLine: true,
|
DisableFlagsInUseLine: true,
|
||||||
Use: "server COMMAND [OPTIONS]",
|
Use: "server COMMAND [OPTIONS]",
|
||||||
Short: "Warewulf server process commands",
|
Short: "Warewulf server process commands",
|
||||||
Long: "This command will allow you to control the Warewulf daemon process.",
|
Long: "This command will allow you to control the Warewulf daemon process.",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import "github.com/spf13/cobra"
|
|||||||
var (
|
var (
|
||||||
baseCmd = &cobra.Command{
|
baseCmd = &cobra.Command{
|
||||||
DisableFlagsInUseLine: true,
|
DisableFlagsInUseLine: true,
|
||||||
Use: "start [OPTIONS]",
|
Use: "start [OPTIONS]",
|
||||||
Short: "Start Warewulf server",
|
Short: "Start Warewulf server",
|
||||||
RunE: CobraRunE,
|
RunE: CobraRunE,
|
||||||
}
|
}
|
||||||
SetForeground bool
|
SetForeground bool
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import "github.com/spf13/cobra"
|
|||||||
var (
|
var (
|
||||||
baseCmd = &cobra.Command{
|
baseCmd = &cobra.Command{
|
||||||
DisableFlagsInUseLine: true,
|
DisableFlagsInUseLine: true,
|
||||||
Use: "status [OPTIONS]",
|
Use: "status [OPTIONS]",
|
||||||
Short: "Warewulf server status",
|
Short: "Warewulf server status",
|
||||||
RunE: CobraRunE,
|
RunE: CobraRunE,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import "github.com/spf13/cobra"
|
|||||||
var (
|
var (
|
||||||
baseCmd = &cobra.Command{
|
baseCmd = &cobra.Command{
|
||||||
DisableFlagsInUseLine: true,
|
DisableFlagsInUseLine: true,
|
||||||
Use: "stop [OPTIONS]",
|
Use: "stop [OPTIONS]",
|
||||||
Short: "Stop Warewulf server",
|
Short: "Stop Warewulf server",
|
||||||
RunE: CobraRunE,
|
RunE: CobraRunE,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -17,4 +17,4 @@ type TlsConfig struct {
|
|||||||
// should be the concatenation of the server's certificate, any
|
// should be the concatenation of the server's certificate, any
|
||||||
// intermediates, and the CA's certificate
|
// intermediates, and the CA's certificate
|
||||||
ConcatCert string `yaml:"concatcert,omitempty"`
|
ConcatCert string `yaml:"concatcert,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
|
|
||||||
// DHCPConf represents the configuration for the DHCP service that
|
// DHCPConf represents the configuration for the DHCP service that
|
||||||
// Warewulf will configure.
|
// Warewulf will configure.
|
||||||
type DHCPConf struct {
|
type DHCPConf struct {
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/creasty/defaults"
|
"github.com/creasty/defaults"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
// NFSConf represents the NFS configuration that will be used by
|
// NFSConf represents the NFS configuration that will be used by
|
||||||
// Warewulf to generate exports on the server and mounts on compute
|
// Warewulf to generate exports on the server and mounts on compute
|
||||||
// nodes.
|
// nodes.
|
||||||
@@ -15,7 +13,6 @@ type NFSConf struct {
|
|||||||
SystemdName string `yaml:"systemd name" default:"nfsd"`
|
SystemdName string `yaml:"systemd name" default:"nfsd"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// An NFSExportConf reprents a single NFS export / mount.
|
// An NFSExportConf reprents a single NFS export / mount.
|
||||||
type NFSExportConf struct {
|
type NFSExportConf struct {
|
||||||
Path string `yaml:"path" default:"/dev/null"`
|
Path string `yaml:"path" default:"/dev/null"`
|
||||||
@@ -24,7 +21,6 @@ type NFSExportConf struct {
|
|||||||
Mount bool `default:"true" yaml:"mount"`
|
Mount bool `default:"true" yaml:"mount"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Implements the Unmarshal interface for NFSConf to set default
|
// Implements the Unmarshal interface for NFSConf to set default
|
||||||
// values.
|
// values.
|
||||||
func (conf *NFSConf) Unmarshal(unmarshal func(interface{}) error) error {
|
func (conf *NFSConf) Unmarshal(unmarshal func(interface{}) error) error {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
func TestDefaultRootConf(t *testing.T) {
|
func TestDefaultRootConf(t *testing.T) {
|
||||||
conf := New()
|
conf := New()
|
||||||
|
|
||||||
@@ -58,7 +57,6 @@ func TestDefaultRootConf(t *testing.T) {
|
|||||||
assert.NotEmpty(t, conf.Paths.WWClientdir)
|
assert.NotEmpty(t, conf.Paths.WWClientdir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func TestInitializedFromFile(t *testing.T) {
|
func TestInitializedFromFile(t *testing.T) {
|
||||||
example_warewulf_conf := "WW_INTERNAL: 43"
|
example_warewulf_conf := "WW_INTERNAL: 43"
|
||||||
tempWarewulfConf, warewulfConfErr := os.CreateTemp("", "warewulf.conf-")
|
tempWarewulfConf, warewulfConfErr := os.CreateTemp("", "warewulf.conf-")
|
||||||
@@ -74,7 +72,6 @@ func TestInitializedFromFile(t *testing.T) {
|
|||||||
assert.True(t, conf.InitializedFromFile())
|
assert.True(t, conf.InitializedFromFile())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func TestExampleRootConf(t *testing.T) {
|
func TestExampleRootConf(t *testing.T) {
|
||||||
example_warewulf_conf := `WW_INTERNAL: 43
|
example_warewulf_conf := `WW_INTERNAL: 43
|
||||||
ipaddr: 192.168.200.1
|
ipaddr: 192.168.200.1
|
||||||
@@ -157,7 +154,6 @@ container mounts:
|
|||||||
assert.True(t, conf.MountsContainer[0].ReadOnly)
|
assert.True(t, conf.MountsContainer[0].ReadOnly)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func TestCache(t *testing.T) {
|
func TestCache(t *testing.T) {
|
||||||
confOrig := New()
|
confOrig := New()
|
||||||
confCached := Get()
|
confCached := Get()
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
|
|
||||||
// TFTPConf represents that configuration for the TFTP service that
|
// TFTPConf represents that configuration for the TFTP service that
|
||||||
// Warewulf will configure.
|
// Warewulf will configure.
|
||||||
type TFTPConf struct {
|
type TFTPConf struct {
|
||||||
Enabled bool `yaml:"enabled" default:"true"`
|
Enabled bool `yaml:"enabled" default:"true"`
|
||||||
TftpRoot string `yaml:"tftproot" default:"/var/lib/tftpboot"`
|
TftpRoot string `yaml:"tftproot" default:"/var/lib/tftpboot"`
|
||||||
SystemdName string `yaml:"systemd name" default:"tftp"`
|
SystemdName string `yaml:"systemd name" default:"tftp"`
|
||||||
|
|
||||||
// Path is relative to buildconfig.DATADIR()
|
// Path is relative to buildconfig.DATADIR()
|
||||||
IpxeBinaries map[string]string `yaml:"ipxe" default:"{\"00:09\": \"ipxe/ipxe-snponly-x86_64.efi\",\"00:00\": \"ipxe/undionly.kpxe\",\"00:0B\": \"ipxe/arm64-efi/snponly.efi\",\"00:07\": \"ipxe/ipxe-snponly-x86_64.efi\"}"`
|
IpxeBinaries map[string]string `yaml:"ipxe" default:"{\"00:09\": \"ipxe/ipxe-snponly-x86_64.efi\",\"00:00\": \"ipxe/undionly.kpxe\",\"00:0B\": \"ipxe/arm64-efi/snponly.efi\",\"00:07\": \"ipxe/ipxe-snponly-x86_64.efi\"}"`
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
|
|
||||||
// WarewulfConf adds additional Warewulf-specific configuration to
|
// WarewulfConf adds additional Warewulf-specific configuration to
|
||||||
// BaseConf.
|
// BaseConf.
|
||||||
type WarewulfConf struct {
|
type WarewulfConf struct {
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/overlay"
|
"github.com/hpcng/warewulf/internal/pkg/overlay"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||||
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package configure
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/overlay"
|
"github.com/hpcng/warewulf/internal/pkg/overlay"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||||
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
|
||||||
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
|
||||||
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -16,11 +16,9 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
const passwdPath = "/etc/passwd"
|
const passwdPath = "/etc/passwd"
|
||||||
const groupPath = "/etc/group"
|
const groupPath = "/etc/group"
|
||||||
|
|
||||||
|
|
||||||
// SyncUids updates the /etc/passwd and /etc/group files in the
|
// SyncUids updates the /etc/passwd and /etc/group files in the
|
||||||
// container identified by containerName by installing the equivalent
|
// container identified by containerName by installing the equivalent
|
||||||
// files from the host and appending names only in the
|
// files from the host and appending names only in the
|
||||||
@@ -41,16 +39,32 @@ func SyncUids(containerName string, showOnly bool) error {
|
|||||||
containerGroupPath := path.Join(containerPath, groupPath)
|
containerGroupPath := path.Join(containerPath, groupPath)
|
||||||
|
|
||||||
passwdSync := make(syncDB)
|
passwdSync := make(syncDB)
|
||||||
if err := passwdSync.readFromHost(passwdPath); err != nil { return err }
|
if err := passwdSync.readFromHost(passwdPath); err != nil {
|
||||||
if err := passwdSync.readFromContainer(containerPasswdPath); err != nil { return err }
|
return err
|
||||||
if err := passwdSync.checkConflicts(); err != nil { return err }
|
}
|
||||||
if err := passwdSync.findUserFiles(containerPath); err != nil { return err }
|
if err := passwdSync.readFromContainer(containerPasswdPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := passwdSync.checkConflicts(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := passwdSync.findUserFiles(containerPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
groupSync := make(syncDB)
|
groupSync := make(syncDB)
|
||||||
if err := groupSync.readFromHost(groupPath); err != nil { return err }
|
if err := groupSync.readFromHost(groupPath); err != nil {
|
||||||
if err := groupSync.readFromContainer(containerGroupPath); err != nil { return err }
|
return err
|
||||||
if err := groupSync.checkConflicts(); err != nil { return err }
|
}
|
||||||
if err := groupSync.findGroupFiles(containerPath); err != nil { return err }
|
if err := groupSync.readFromContainer(containerGroupPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := groupSync.checkConflicts(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := groupSync.findGroupFiles(containerPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
passwdSync.log("passwd")
|
passwdSync.log("passwd")
|
||||||
groupSync.log("group")
|
groupSync.log("group")
|
||||||
@@ -62,31 +76,37 @@ func SyncUids(containerName string, showOnly bool) error {
|
|||||||
wwlog.Info("uid/gid already synced")
|
wwlog.Info("uid/gid already synced")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err := passwdSync.chownUserFiles(); err != nil { return err }
|
if err := passwdSync.chownUserFiles(); err != nil {
|
||||||
if err := groupSync.chownGroupFiles(); err != nil { return err }
|
return err
|
||||||
|
}
|
||||||
|
if err := groupSync.chownGroupFiles(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if err := passwdSync.update(containerPasswdPath, passwdPath); err != nil { return err }
|
if err := passwdSync.update(containerPasswdPath, passwdPath); err != nil {
|
||||||
if err := groupSync.update(containerGroupPath, groupPath); err != nil { return err }
|
return err
|
||||||
|
}
|
||||||
|
if err := groupSync.update(containerGroupPath, groupPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
wwlog.Info("uid/gid synced for container %s", containerName)
|
wwlog.Info("uid/gid synced for container %s", containerName)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// A syncDB maps user or group names to syncInfo instances, which
|
// A syncDB maps user or group names to syncInfo instances, which
|
||||||
// correlate IDs between host and container and track affected
|
// correlate IDs between host and container and track affected
|
||||||
// files. This can be used for either /etc/passwd or /etc/group IDs.
|
// files. This can be used for either /etc/passwd or /etc/group IDs.
|
||||||
type syncDB map[string]syncInfo
|
type syncDB map[string]syncInfo
|
||||||
|
|
||||||
|
|
||||||
// checkConflicts inspects a syncDB map for irreconcilable
|
// checkConflicts inspects a syncDB map for irreconcilable
|
||||||
// conflicts. A conflict arises if the container has an entry with the
|
// conflicts. A conflict arises if the container has an entry with the
|
||||||
// same id as an entry in the host and the host does not have an entry
|
// same id as an entry in the host and the host does not have an entry
|
||||||
// with the same name.
|
// with the same name.
|
||||||
func (db syncDB) checkConflicts() error {
|
func (db syncDB) checkConflicts() error {
|
||||||
for nameInContainer, containerIds := range db {
|
for nameInContainer, containerIds := range db {
|
||||||
if (!containerIds.inContainer() || containerIds.inHost()) {
|
if !containerIds.inContainer() || containerIds.inHost() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +122,6 @@ func (db syncDB) checkConflicts() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// log generates debug and verbose logs inspecting a syncDB map.
|
// log generates debug and verbose logs inspecting a syncDB map.
|
||||||
//
|
//
|
||||||
// The provided prefix is prepended to log entries to provide context
|
// The provided prefix is prepended to log entries to provide context
|
||||||
@@ -112,10 +131,18 @@ func (db syncDB) log(prefix string) {
|
|||||||
var onlyContainer, onlyHost, match, differ []string
|
var onlyContainer, onlyHost, match, differ []string
|
||||||
for name, ids := range db {
|
for name, ids := range db {
|
||||||
wwlog.Debug("%s: %s: host(%v) container(%v) files: %v", prefix, name, ids.HostID, ids.ContainerID, ids.ContainerFiles)
|
wwlog.Debug("%s: %s: host(%v) container(%v) files: %v", prefix, name, ids.HostID, ids.ContainerID, ids.ContainerFiles)
|
||||||
if ids.onlyContainer() { onlyContainer = append(onlyContainer, name) }
|
if ids.onlyContainer() {
|
||||||
if ids.onlyHost() { onlyHost = append(onlyHost, name) }
|
onlyContainer = append(onlyContainer, name)
|
||||||
if ids.match() { match = append(match, name) }
|
}
|
||||||
if ids.differ() { differ = append(differ, name) }
|
if ids.onlyHost() {
|
||||||
|
onlyHost = append(onlyHost, name)
|
||||||
|
}
|
||||||
|
if ids.match() {
|
||||||
|
match = append(match, name)
|
||||||
|
}
|
||||||
|
if ids.differ() {
|
||||||
|
differ = append(differ, name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wwlog.Verbose("%s: container only: %v", prefix, onlyContainer)
|
wwlog.Verbose("%s: container only: %v", prefix, onlyContainer)
|
||||||
@@ -124,7 +151,6 @@ func (db syncDB) log(prefix string) {
|
|||||||
wwlog.Verbose("%s: differ: %v", prefix, differ)
|
wwlog.Verbose("%s: differ: %v", prefix, differ)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// read reads fileName (an /etc/passwd or /etc/group file) into a
|
// read reads fileName (an /etc/passwd or /etc/group file) into a
|
||||||
// syncDB map. Since the name and numerical id for both files are
|
// syncDB map. Since the name and numerical id for both files are
|
||||||
// stored at fields 0 and 2, the same function can read both files.
|
// stored at fields 0 and 2, the same function can read both files.
|
||||||
@@ -180,19 +206,16 @@ func (db syncDB) read(fileName string, fromContainer bool) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// readFromHost reads fileName into a syncDB map.
|
// readFromHost reads fileName into a syncDB map.
|
||||||
//
|
//
|
||||||
// Equivalent to read(fileName, false)
|
// Equivalent to read(fileName, false)
|
||||||
func (db syncDB) readFromHost(fileName string) error { return db.read(fileName, false) }
|
func (db syncDB) readFromHost(fileName string) error { return db.read(fileName, false) }
|
||||||
|
|
||||||
|
|
||||||
// readFromContainer reads fileName into a syncDB map.
|
// readFromContainer reads fileName into a syncDB map.
|
||||||
//
|
//
|
||||||
// Equivalent to read(fileName, true)
|
// Equivalent to read(fileName, true)
|
||||||
func (db syncDB) readFromContainer(fileName string) error { return db.read(fileName, true) }
|
func (db syncDB) readFromContainer(fileName string) error { return db.read(fileName, true) }
|
||||||
|
|
||||||
|
|
||||||
// findFiles finds files under containerPath that are owned by each
|
// findFiles finds files under containerPath that are owned by each
|
||||||
// tracked container ID.
|
// tracked container ID.
|
||||||
//
|
//
|
||||||
@@ -200,7 +223,9 @@ func (db syncDB) readFromContainer(fileName string) error { return db.read(fileN
|
|||||||
// recorded. Otherwise, files with a matching uid are recorded.
|
// recorded. Otherwise, files with a matching uid are recorded.
|
||||||
func (db syncDB) findFiles(containerPath string, byGid bool) error {
|
func (db syncDB) findFiles(containerPath string, byGid bool) error {
|
||||||
for name, ids := range db {
|
for name, ids := range db {
|
||||||
if err := ids.findFiles(containerPath, byGid); err != nil { return err }
|
if err := ids.findFiles(containerPath, byGid); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if len(ids.ContainerFiles) > 0 {
|
if len(ids.ContainerFiles) > 0 {
|
||||||
wwlog.Debug("files for %s (%v -> %v, gid: %v): %v", name, ids.ContainerID, ids.HostID, byGid, ids.ContainerFiles)
|
wwlog.Debug("files for %s (%v -> %v, gid: %v): %v", name, ids.ContainerID, ids.HostID, byGid, ids.ContainerFiles)
|
||||||
}
|
}
|
||||||
@@ -209,15 +234,12 @@ func (db syncDB) findFiles(containerPath string, byGid bool) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// findUserFiles is equivalent to findFiles(containerPath, false)
|
// findUserFiles is equivalent to findFiles(containerPath, false)
|
||||||
func (db syncDB) findUserFiles(containerPath string) error { return db.findFiles(containerPath, false) }
|
func (db syncDB) findUserFiles(containerPath string) error { return db.findFiles(containerPath, false) }
|
||||||
|
|
||||||
|
|
||||||
// findGroupFiles is equivalent to findFiles(containerPath, true)
|
// findGroupFiles is equivalent to findFiles(containerPath, true)
|
||||||
func (db syncDB) findGroupFiles(containerPath string) error { return db.findFiles(containerPath, true) }
|
func (db syncDB) findGroupFiles(containerPath string) error { return db.findFiles(containerPath, true) }
|
||||||
|
|
||||||
|
|
||||||
// chownFiles updates found files (see findFiles) to reflect ownership
|
// chownFiles updates found files (see findFiles) to reflect ownership
|
||||||
// using host ids.
|
// using host ids.
|
||||||
//
|
//
|
||||||
@@ -225,20 +247,19 @@ func (db syncDB) findGroupFiles(containerPath string) error { return db.findFile
|
|||||||
// updated.
|
// updated.
|
||||||
func (db syncDB) chownFiles(byGid bool) error {
|
func (db syncDB) chownFiles(byGid bool) error {
|
||||||
for _, ids := range db {
|
for _, ids := range db {
|
||||||
if err := ids.chownFiles(byGid); err != nil { return err }
|
if err := ids.chownFiles(byGid); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// chownUserFiles is equivalent to chownFiles(false)
|
// chownUserFiles is equivalent to chownFiles(false)
|
||||||
func (db syncDB) chownUserFiles() error { return db.chownFiles(false) }
|
func (db syncDB) chownUserFiles() error { return db.chownFiles(false) }
|
||||||
|
|
||||||
|
|
||||||
// chownUserFiles is equivalent to chownFiles(true)
|
// chownUserFiles is equivalent to chownFiles(true)
|
||||||
func (db syncDB) chownGroupFiles() error { return db.chownFiles(true) }
|
func (db syncDB) chownGroupFiles() error { return db.chownFiles(true) }
|
||||||
|
|
||||||
|
|
||||||
// getOnlyContainerLines returns the lines from fileName (either an
|
// getOnlyContainerLines returns the lines from fileName (either an
|
||||||
// /etc/passwd or /etc/group file) for names that occur only in the
|
// /etc/passwd or /etc/group file) for names that occur only in the
|
||||||
// container.
|
// container.
|
||||||
@@ -247,7 +268,9 @@ func (db syncDB) chownGroupFiles() error { return db.chownFiles(true) }
|
|||||||
// updating the container.
|
// updating the container.
|
||||||
func (db syncDB) getOnlyContainerLines(fileName string) ([]string, error) {
|
func (db syncDB) getOnlyContainerLines(fileName string) ([]string, error) {
|
||||||
file, err := os.Open(fileName)
|
file, err := os.Open(fileName)
|
||||||
if err != nil { return nil, err }
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
fileScanner := bufio.NewScanner(file)
|
fileScanner := bufio.NewScanner(file)
|
||||||
|
|
||||||
@@ -268,7 +291,6 @@ func (db syncDB) getOnlyContainerLines(fileName string) ([]string, error) {
|
|||||||
return lines, nil
|
return lines, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// update replaces containerPath with hostPath and adds lines from
|
// update replaces containerPath with hostPath and adds lines from
|
||||||
// getOnlyContainerLines to the end of containerPath. This is used to
|
// getOnlyContainerLines to the end of containerPath. This is used to
|
||||||
// replace /etc/passwd (or /etc/group) in the container with the
|
// replace /etc/passwd (or /etc/group) in the container with the
|
||||||
@@ -279,14 +301,19 @@ func (db syncDB) update(containerPath string, hostPath string) error {
|
|||||||
if lines, err := db.getOnlyContainerLines(containerPath); err != nil {
|
if lines, err := db.getOnlyContainerLines(containerPath); err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
if err := os.Remove(containerPath); err != nil { return err }
|
if err := os.Remove(containerPath); err != nil {
|
||||||
if err := util.CopyFile(hostPath, containerPath); err != nil { return err }
|
return err
|
||||||
if err := util.AppendLines(containerPath, lines); err != nil { return err }
|
}
|
||||||
|
if err := util.CopyFile(hostPath, containerPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := util.AppendLines(containerPath, lines); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// needsSync returns true if the syncDB map indicates that ids between
|
// needsSync returns true if the syncDB map indicates that ids between
|
||||||
// the container and host are out-of-sync.
|
// the container and host are out-of-sync.
|
||||||
func (db syncDB) needsSync() bool {
|
func (db syncDB) needsSync() bool {
|
||||||
@@ -306,7 +333,6 @@ func (db syncDB) needsSync() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// sycncInfo correlates the numerical id of a name on the host
|
// sycncInfo correlates the numerical id of a name on the host
|
||||||
// (HostID) and the container (ContainerID), along with the files in
|
// (HostID) and the container (ContainerID), along with the files in
|
||||||
// the container that are owned by that name. This allows affected
|
// the container that are owned by that name. This allows affected
|
||||||
@@ -317,49 +343,42 @@ type syncInfo struct {
|
|||||||
ContainerFiles []string `access:"r,w"`
|
ContainerFiles []string `access:"r,w"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// inHost returns true if info has a record of an id for this name in
|
// inHost returns true if info has a record of an id for this name in
|
||||||
// the host.
|
// the host.
|
||||||
func (info *syncInfo) inHost() bool {
|
func (info *syncInfo) inHost() bool {
|
||||||
return info.HostID != -1
|
return info.HostID != -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// inContainer returns true if info has a record of an id for this
|
// inContainer returns true if info has a record of an id for this
|
||||||
// name in the container.
|
// name in the container.
|
||||||
func (info *syncInfo) inContainer() bool {
|
func (info *syncInfo) inContainer() bool {
|
||||||
return info.ContainerID != -1
|
return info.ContainerID != -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// onlyHost returns true if info has a record of an id for this name
|
// onlyHost returns true if info has a record of an id for this name
|
||||||
// in the host and not in the container.
|
// in the host and not in the container.
|
||||||
func (info *syncInfo) onlyHost() bool {
|
func (info *syncInfo) onlyHost() bool {
|
||||||
return info.inHost() && !info.inContainer()
|
return info.inHost() && !info.inContainer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// onlyHost returns true if info has a record of an id for this name
|
// onlyHost returns true if info has a record of an id for this name
|
||||||
// in the container and not in the host.
|
// in the container and not in the host.
|
||||||
func (info *syncInfo) onlyContainer() bool {
|
func (info *syncInfo) onlyContainer() bool {
|
||||||
return info.inContainer() && !info.inHost()
|
return info.inContainer() && !info.inHost()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// match returns true if info represents a name that exists with the
|
// match returns true if info represents a name that exists with the
|
||||||
// same numerical id in both the host and the container.
|
// same numerical id in both the host and the container.
|
||||||
func (info *syncInfo) match() bool {
|
func (info *syncInfo) match() bool {
|
||||||
return info.inContainer() && info.inHost() && info.HostID == info.ContainerID
|
return info.inContainer() && info.inHost() && info.HostID == info.ContainerID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// differ returns true if info represents a name that exists in both
|
// differ returns true if info represents a name that exists in both
|
||||||
// the host and the container but with different numerical ids.
|
// the host and the container but with different numerical ids.
|
||||||
func (info *syncInfo) differ() bool {
|
func (info *syncInfo) differ() bool {
|
||||||
return info.inContainer() && info.inHost() && info.HostID != info.ContainerID
|
return info.inContainer() && info.inHost() && info.HostID != info.ContainerID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// findFiles walks containerPath to find files owned by the name
|
// findFiles walks containerPath to find files owned by the name
|
||||||
// represented by info and records them in info.ContainerFiles.
|
// represented by info and records them in info.ContainerFiles.
|
||||||
//
|
//
|
||||||
@@ -367,7 +386,7 @@ func (info *syncInfo) differ() bool {
|
|||||||
// uid is checked.
|
// uid is checked.
|
||||||
func (info *syncInfo) findFiles(containerPath string, byGid bool) error {
|
func (info *syncInfo) findFiles(containerPath string, byGid bool) error {
|
||||||
var containerFiles []string
|
var containerFiles []string
|
||||||
if (info.inHost() && !info.match()) {
|
if info.inHost() && !info.match() {
|
||||||
if err := filepath.Walk(containerPath, func(filePath string, fileInfo fs.FileInfo, err error) error {
|
if err := filepath.Walk(containerPath, func(filePath string, fileInfo fs.FileInfo, err error) error {
|
||||||
if stat, ok := fileInfo.Sys().(*syscall.Stat_t); ok {
|
if stat, ok := fileInfo.Sys().(*syscall.Stat_t); ok {
|
||||||
var id int
|
var id int
|
||||||
@@ -389,7 +408,6 @@ func (info *syncInfo) findFiles(containerPath string, byGid bool) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// chownFiles updates the files recorded in info.ContainerFiles to use
|
// chownFiles updates the files recorded in info.ContainerFiles to use
|
||||||
// the numerical IDs from the host.
|
// the numerical IDs from the host.
|
||||||
//
|
//
|
||||||
@@ -409,7 +427,9 @@ func (info *syncInfo) chownFiles(byGid bool) error {
|
|||||||
newUid = info.HostID
|
newUid = info.HostID
|
||||||
newGid = -1
|
newGid = -1
|
||||||
}
|
}
|
||||||
if err := os.Chown(file, newUid, newGid); err != nil { return err }
|
if err := os.Chown(file, newUid, newGid); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func writeTempFile(t *testing.T, input string) string {
|
||||||
func writeTempFile(t *testing.T, input string) (string) {
|
|
||||||
tempFile, createTempError := os.CreateTemp("", "syncuids-*")
|
tempFile, createTempError := os.CreateTemp("", "syncuids-*")
|
||||||
assert.NoError(t, createTempError)
|
assert.NoError(t, createTempError)
|
||||||
_, writeError := tempFile.Write([]byte(input))
|
_, writeError := tempFile.Write([]byte(input))
|
||||||
@@ -17,8 +16,7 @@ func writeTempFile(t *testing.T, input string) (string) {
|
|||||||
return tempFile.Name()
|
return tempFile.Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeSyncDB(t *testing.T, hostInput string, containerInput string) syncDB {
|
||||||
func makeSyncDB(t *testing.T, hostInput string, containerInput string) (syncDB) {
|
|
||||||
hostFileName := writeTempFile(t, hostInput)
|
hostFileName := writeTempFile(t, hostInput)
|
||||||
defer os.Remove(hostFileName)
|
defer os.Remove(hostFileName)
|
||||||
containerFileName := writeTempFile(t, containerInput)
|
containerFileName := writeTempFile(t, containerInput)
|
||||||
@@ -32,7 +30,6 @@ func makeSyncDB(t *testing.T, hostInput string, containerInput string) (syncDB)
|
|||||||
return db
|
return db
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func Test_readFromHost_single(t *testing.T) {
|
func Test_readFromHost_single(t *testing.T) {
|
||||||
hostFileName := writeTempFile(t, `testuser:x:1001:1001::/home/testuser:/bin/bash`)
|
hostFileName := writeTempFile(t, `testuser:x:1001:1001::/home/testuser:/bin/bash`)
|
||||||
defer os.Remove(hostFileName)
|
defer os.Remove(hostFileName)
|
||||||
@@ -46,7 +43,6 @@ func Test_readFromHost_single(t *testing.T) {
|
|||||||
assert.Equal(t, -1, db["testuser"].ContainerID)
|
assert.Equal(t, -1, db["testuser"].ContainerID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func Test_readFromHost_multiple(t *testing.T) {
|
func Test_readFromHost_multiple(t *testing.T) {
|
||||||
hostFileName := writeTempFile(t, `
|
hostFileName := writeTempFile(t, `
|
||||||
testuser1:x:1001:1001::/home/testuser:/bin/bash
|
testuser1:x:1001:1001::/home/testuser:/bin/bash
|
||||||
@@ -65,7 +61,6 @@ testuser2:x:1002:1002::/home/testuser:/bin/bash
|
|||||||
assert.Equal(t, -1, db["testuser2"].ContainerID)
|
assert.Equal(t, -1, db["testuser2"].ContainerID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func Test_readFromContainer_single(t *testing.T) {
|
func Test_readFromContainer_single(t *testing.T) {
|
||||||
containerFileName := writeTempFile(t, `testuser:x:1001:1001::/home/testuser:/bin/bash`)
|
containerFileName := writeTempFile(t, `testuser:x:1001:1001::/home/testuser:/bin/bash`)
|
||||||
defer os.Remove(containerFileName)
|
defer os.Remove(containerFileName)
|
||||||
@@ -79,7 +74,6 @@ func Test_readFromContainer_single(t *testing.T) {
|
|||||||
assert.Equal(t, -1, db["testuser"].HostID)
|
assert.Equal(t, -1, db["testuser"].HostID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func Test_readFromContainer_multiple(t *testing.T) {
|
func Test_readFromContainer_multiple(t *testing.T) {
|
||||||
containerFileName := writeTempFile(t, `
|
containerFileName := writeTempFile(t, `
|
||||||
testuser1:x:1001:1001::/home/testuser:/bin/bash
|
testuser1:x:1001:1001::/home/testuser:/bin/bash
|
||||||
@@ -97,7 +91,6 @@ testuser2:x:1002:1002::/home/testuser:/bin/bash
|
|||||||
assert.Equal(t, -1, db["testuser2"].HostID)
|
assert.Equal(t, -1, db["testuser2"].HostID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func Test_readFromBoth_multiple(t *testing.T) {
|
func Test_readFromBoth_multiple(t *testing.T) {
|
||||||
containerFileName := writeTempFile(t, `
|
containerFileName := writeTempFile(t, `
|
||||||
testuser1:x:1001:1001::/home/testuser:/bin/bash
|
testuser1:x:1001:1001::/home/testuser:/bin/bash
|
||||||
@@ -105,7 +98,6 @@ testuser2:x:1002:1002::/home/testuser:/bin/bash
|
|||||||
`)
|
`)
|
||||||
defer os.Remove(containerFileName)
|
defer os.Remove(containerFileName)
|
||||||
|
|
||||||
|
|
||||||
hostFileName := writeTempFile(t, `
|
hostFileName := writeTempFile(t, `
|
||||||
testuser1:x:2001:2001::/home/testuser:/bin/bash
|
testuser1:x:2001:2001::/home/testuser:/bin/bash
|
||||||
testuser3:x:2003:2003::/home/testuser:/bin/bash
|
testuser3:x:2003:2003::/home/testuser:/bin/bash
|
||||||
@@ -127,19 +119,16 @@ testuser3:x:2003:2003::/home/testuser:/bin/bash
|
|||||||
assert.Equal(t, 2003, db["testuser3"].HostID)
|
assert.Equal(t, 2003, db["testuser3"].HostID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func Test_checkConflicts_empty(t *testing.T) {
|
func Test_checkConflicts_empty(t *testing.T) {
|
||||||
db := makeSyncDB(t, "", "")
|
db := makeSyncDB(t, "", "")
|
||||||
assert.NoError(t, db.checkConflicts())
|
assert.NoError(t, db.checkConflicts())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func Test_checkConflicts_single(t *testing.T) {
|
func Test_checkConflicts_single(t *testing.T) {
|
||||||
db := makeSyncDB(t, "", "testuser:x:1001:1001::/home/testuser:/bin/bash")
|
db := makeSyncDB(t, "", "testuser:x:1001:1001::/home/testuser:/bin/bash")
|
||||||
assert.NoError(t, db.checkConflicts())
|
assert.NoError(t, db.checkConflicts())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func Test_checkConflicts_match(t *testing.T) {
|
func Test_checkConflicts_match(t *testing.T) {
|
||||||
db := makeSyncDB(t,
|
db := makeSyncDB(t,
|
||||||
"testuser:x:1001:1001::/home/testuser:/bin/bash",
|
"testuser:x:1001:1001::/home/testuser:/bin/bash",
|
||||||
@@ -147,7 +136,6 @@ func Test_checkConflicts_match(t *testing.T) {
|
|||||||
assert.NoError(t, db.checkConflicts())
|
assert.NoError(t, db.checkConflicts())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func Test_checkConflicts_conflict(t *testing.T) {
|
func Test_checkConflicts_conflict(t *testing.T) {
|
||||||
db := makeSyncDB(t,
|
db := makeSyncDB(t,
|
||||||
"testuser2:x:1001:1001::/home/testuser:/bin/bash",
|
"testuser2:x:1001:1001::/home/testuser:/bin/bash",
|
||||||
@@ -155,7 +143,6 @@ func Test_checkConflicts_conflict(t *testing.T) {
|
|||||||
assert.Error(t, db.checkConflicts())
|
assert.Error(t, db.checkConflicts())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func Test_getOnlyContainerLines(t *testing.T) {
|
func Test_getOnlyContainerLines(t *testing.T) {
|
||||||
containerFileName := writeTempFile(t, `
|
containerFileName := writeTempFile(t, `
|
||||||
testuser1:x:1001:1001::/home/testuser:/bin/bash
|
testuser1:x:1001:1001::/home/testuser:/bin/bash
|
||||||
@@ -163,7 +150,6 @@ testuser2:x:1002:1002::/home/testuser:/bin/bash
|
|||||||
`)
|
`)
|
||||||
defer os.Remove(containerFileName)
|
defer os.Remove(containerFileName)
|
||||||
|
|
||||||
|
|
||||||
hostFileName := writeTempFile(t, `
|
hostFileName := writeTempFile(t, `
|
||||||
testuser1:x:2001:2001::/home/testuser:/bin/bash
|
testuser1:x:2001:2001::/home/testuser:/bin/bash
|
||||||
testuser3:x:2003:2003::/home/testuser:/bin/bash
|
testuser3:x:2003:2003::/home/testuser:/bin/bash
|
||||||
@@ -184,13 +170,11 @@ testuser3:x:2003:2003::/home/testuser:/bin/bash
|
|||||||
assert.Equal(t, lines[0], "testuser2:x:1002:1002::/home/testuser:/bin/bash")
|
assert.Equal(t, lines[0], "testuser2:x:1002:1002::/home/testuser:/bin/bash")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func Test_needsSync_empty(t *testing.T) {
|
func Test_needsSync_empty(t *testing.T) {
|
||||||
db := makeSyncDB(t, "", "")
|
db := makeSyncDB(t, "", "")
|
||||||
assert.False(t, db.needsSync())
|
assert.False(t, db.needsSync())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func Test_needsSync_containerOnly(t *testing.T) {
|
func Test_needsSync_containerOnly(t *testing.T) {
|
||||||
db := makeSyncDB(t, "", `
|
db := makeSyncDB(t, "", `
|
||||||
testuser1:x:1001:1001::/home/testuser:/bin/bash
|
testuser1:x:1001:1001::/home/testuser:/bin/bash
|
||||||
@@ -199,7 +183,6 @@ testuser2:x:1002:1002::/home/testuser:/bin/bash`)
|
|||||||
assert.False(t, db.needsSync())
|
assert.False(t, db.needsSync())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func Test_needsSync_hostOnly(t *testing.T) {
|
func Test_needsSync_hostOnly(t *testing.T) {
|
||||||
db := makeSyncDB(t, `
|
db := makeSyncDB(t, `
|
||||||
testuser1:x:1001:1001::/home/testuser:/bin/bash
|
testuser1:x:1001:1001::/home/testuser:/bin/bash
|
||||||
@@ -208,7 +191,6 @@ testuser2:x:1002:1002::/home/testuser:/bin/bash`, "")
|
|||||||
assert.True(t, db.needsSync())
|
assert.True(t, db.needsSync())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func Test_needsSync_match(t *testing.T) {
|
func Test_needsSync_match(t *testing.T) {
|
||||||
db := makeSyncDB(t,
|
db := makeSyncDB(t,
|
||||||
"testuser:x:1001:1001::/home/testuser:/bin/bash",
|
"testuser:x:1001:1001::/home/testuser:/bin/bash",
|
||||||
@@ -217,7 +199,6 @@ func Test_needsSync_match(t *testing.T) {
|
|||||||
assert.False(t, db.needsSync())
|
assert.False(t, db.needsSync())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func Test_needsSync_differ(t *testing.T) {
|
func Test_needsSync_differ(t *testing.T) {
|
||||||
db := makeSyncDB(t,
|
db := makeSyncDB(t,
|
||||||
`
|
`
|
||||||
@@ -230,7 +211,6 @@ testuser2:x:1002:1002::/home/testuser:/bin/bash`)
|
|||||||
assert.True(t, db.needsSync())
|
assert.True(t, db.needsSync())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func Test_onlyHost(t *testing.T) {
|
func Test_onlyHost(t *testing.T) {
|
||||||
db := makeSyncDB(t, "testuser1:x:2001:2001::/home/testuser:/bin/bash", "")
|
db := makeSyncDB(t, "testuser1:x:2001:2001::/home/testuser:/bin/bash", "")
|
||||||
entry := db["testuser1"]
|
entry := db["testuser1"]
|
||||||
@@ -242,7 +222,6 @@ func Test_onlyHost(t *testing.T) {
|
|||||||
assert.False(t, entry.differ())
|
assert.False(t, entry.differ())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func Test_onlyContainer(t *testing.T) {
|
func Test_onlyContainer(t *testing.T) {
|
||||||
db := makeSyncDB(t, "", "testuser1:x:2001:2001::/home/testuser:/bin/bash")
|
db := makeSyncDB(t, "", "testuser1:x:2001:2001::/home/testuser:/bin/bash")
|
||||||
entry := db["testuser1"]
|
entry := db["testuser1"]
|
||||||
@@ -254,7 +233,6 @@ func Test_onlyContainer(t *testing.T) {
|
|||||||
assert.False(t, entry.differ())
|
assert.False(t, entry.differ())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func Test_match(t *testing.T) {
|
func Test_match(t *testing.T) {
|
||||||
db := makeSyncDB(t,
|
db := makeSyncDB(t,
|
||||||
"testuser1:x:2001:2001::/home/testuser:/bin/bash",
|
"testuser1:x:2001:2001::/home/testuser:/bin/bash",
|
||||||
@@ -268,7 +246,6 @@ func Test_match(t *testing.T) {
|
|||||||
assert.False(t, entry.differ())
|
assert.False(t, entry.differ())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func Test_differ(t *testing.T) {
|
func Test_differ(t *testing.T) {
|
||||||
db := makeSyncDB(t,
|
db := makeSyncDB(t,
|
||||||
"testuser1:x:1001:1001::/home/testuser:/bin/bash",
|
"testuser1:x:1001:1001::/home/testuser:/bin/bash",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}}
|
|||||||
Use "{{.CommandPath}} COMMAND --help" for more information about a COMMAND.
|
Use "{{.CommandPath}} COMMAND --help" for more information about a COMMAND.
|
||||||
{{end}}
|
{{end}}
|
||||||
`
|
`
|
||||||
|
|
||||||
// End UsageTemplate
|
// End UsageTemplate
|
||||||
|
|
||||||
// HelpTemplate replaces the default help template from cobra
|
// HelpTemplate replaces the default help template from cobra
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ import (
|
|||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
|
||||||
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package node
|
package node
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newConstructorPrimaryNetworkTest() NodeYaml {
|
func newConstructorPrimaryNetworkTest() NodeYaml {
|
||||||
@@ -107,13 +107,12 @@ func Test_Primary_Network(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var findDiscoverableNodeTests = []struct {
|
||||||
var findDiscoverableNodeTests = []struct{
|
description string
|
||||||
description string
|
discoverable_nodes []string
|
||||||
discoverable_nodes []string
|
discovered_node string
|
||||||
discovered_node string
|
|
||||||
discovered_interface string
|
discovered_interface string
|
||||||
succeed bool
|
succeed bool
|
||||||
}{
|
}{
|
||||||
{"no discoverable nodes", []string{}, "", "", false},
|
{"no discoverable nodes", []string{}, "", "", false},
|
||||||
{"all nodes discoverable", []string{"test_node1", "test_node2", "test_node3", "test_node4"}, "test_node1", "net0", true},
|
{"all nodes discoverable", []string{"test_node1", "test_node2", "test_node3", "test_node4"}, "test_node1", "net0", true},
|
||||||
|
|||||||
@@ -229,4 +229,3 @@ type FileSystemEntry struct {
|
|||||||
|
|
||||||
// string which is printed if no value is set
|
// string which is printed if no value is set
|
||||||
const NoValue = "--"
|
const NoValue = "--"
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package node
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gopkg.in/yaml.v2"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNodeUpdate(t *testing.T) {
|
func TestNodeUpdate(t *testing.T) {
|
||||||
@@ -31,7 +31,7 @@ nodes:
|
|||||||
|
|
||||||
err = nodeYaml.NodeUpdate(
|
err = nodeYaml.NodeUpdate(
|
||||||
NodeInfo{
|
NodeInfo{
|
||||||
Id: Entry {
|
Id: Entry{
|
||||||
value: []string{"n0000"},
|
value: []string{"n0000"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -39,7 +39,6 @@ nodes:
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func TestNodeDisk(t *testing.T) {
|
func TestNodeDisk(t *testing.T) {
|
||||||
node_config := `WW_INTERNAL: 43
|
node_config := `WW_INTERNAL: 43
|
||||||
nodes:
|
nodes:
|
||||||
|
|||||||
@@ -8,6 +8,6 @@ import (
|
|||||||
var defaultCachePath = filepath.Join(warewulfconf.Get().Warewulf.DataStore, "/container-cache/oci/")
|
var defaultCachePath = filepath.Join(warewulfconf.Get().Warewulf.DataStore, "/container-cache/oci/")
|
||||||
|
|
||||||
const (
|
const (
|
||||||
blobPrefix = "blobs"
|
blobPrefix = "blobs"
|
||||||
rootfsPrefix = "rootfs"
|
rootfsPrefix = "rootfs"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
|
||||||
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func OverlaySourceTopDir() string {
|
func OverlaySourceTopDir() string {
|
||||||
@@ -48,7 +48,7 @@ func OverlayImage(nodeName string, context string, overlayNames []string) string
|
|||||||
}
|
}
|
||||||
name = "__" + strings.ToUpper(context) + "__.img"
|
name = "__" + strings.ToUpper(context) + "__.img"
|
||||||
} else if len(overlayNames) > 0 {
|
} else if len(overlayNames) > 0 {
|
||||||
name = strings.Join(overlayNames, "-")+".img"
|
name = strings.Join(overlayNames, "-") + ".img"
|
||||||
} else {
|
} else {
|
||||||
wwlog.Warn("unable to generate overlay image path: no context or overlays specified")
|
wwlog.Warn("unable to generate overlay image path: no context or overlays specified")
|
||||||
return ""
|
return ""
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
package overlay
|
package overlay
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
|
||||||
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
var overlayImageTests = []struct{
|
var overlayImageTests = []struct {
|
||||||
description string
|
description string
|
||||||
node string
|
node string
|
||||||
context string
|
context string
|
||||||
overlays []string
|
overlays []string
|
||||||
image string
|
image string
|
||||||
}{
|
}{
|
||||||
{"all empty", "", "", nil, ""},
|
{"all empty", "", "", nil, ""},
|
||||||
{"empty with named context", "", "system", nil, "p/overlays/__SYSTEM__.img"},
|
{"empty with named context", "", "system", nil, "p/overlays/__SYSTEM__.img"},
|
||||||
@@ -30,7 +30,7 @@ func Test_OverlayImage(t *testing.T) {
|
|||||||
for _, tt := range overlayImageTests {
|
for _, tt := range overlayImageTests {
|
||||||
t.Run(tt.description, func(t *testing.T) {
|
t.Run(tt.description, func(t *testing.T) {
|
||||||
out := OverlayImage(tt.node, tt.context, tt.overlays)
|
out := OverlayImage(tt.node, tt.context, tt.overlays)
|
||||||
if tt.image != out {
|
if tt.image != out {
|
||||||
t.Errorf("got %q, want %q", out, tt.image)
|
t.Errorf("got %q, want %q", out, tt.image)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package overlay
|
package overlay
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_createIgnitionJson(t *testing.T) {
|
func Test_createIgnitionJson(t *testing.T) {
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
package overlay
|
package overlay
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||||
|
"github.com/sassoftware/go-rpmutils/cpio"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/sassoftware/go-rpmutils/cpio"
|
|
||||||
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var buildOverlayTests = []struct{
|
var buildOverlayTests = []struct {
|
||||||
description string
|
description string
|
||||||
nodeName string
|
nodeName string
|
||||||
context string
|
context string
|
||||||
overlays []string
|
overlays []string
|
||||||
image string
|
image string
|
||||||
contents []string
|
contents []string
|
||||||
}{
|
}{
|
||||||
{"empty", "", "", nil, "", nil},
|
{"empty", "", "", nil, "", nil},
|
||||||
{"empty node", "node1", "", nil, "", nil},
|
{"empty node", "node1", "", nil, "", nil},
|
||||||
@@ -42,9 +42,15 @@ func Test_BuildOverlay(t *testing.T) {
|
|||||||
defer os.RemoveAll(overlayDir)
|
defer os.RemoveAll(overlayDir)
|
||||||
conf.Paths.WWOverlaydir = overlayDir
|
conf.Paths.WWOverlaydir = overlayDir
|
||||||
assert.NoError(t, os.Mkdir(path.Join(overlayDir, "o1"), 0700))
|
assert.NoError(t, os.Mkdir(path.Join(overlayDir, "o1"), 0700))
|
||||||
{ _, err := os.Create(path.Join(overlayDir, "o1", "o1.txt")); assert.NoError(t, err) }
|
{
|
||||||
|
_, err := os.Create(path.Join(overlayDir, "o1", "o1.txt"))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
assert.NoError(t, os.Mkdir(path.Join(overlayDir, "o2"), 0700))
|
assert.NoError(t, os.Mkdir(path.Join(overlayDir, "o2"), 0700))
|
||||||
{ _, err := os.Create(path.Join(overlayDir, "o2", "o2.txt")); assert.NoError(t, err) }
|
{
|
||||||
|
_, err := os.Create(path.Join(overlayDir, "o2", "o2.txt"))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
for _, tt := range buildOverlayTests {
|
for _, tt := range buildOverlayTests {
|
||||||
assert.True(t, (tt.image != "" && tt.contents != nil) || (tt.image == "" && tt.contents == nil),
|
assert.True(t, (tt.image != "" && tt.contents != nil) || (tt.image == "" && tt.contents == nil),
|
||||||
@@ -78,12 +84,12 @@ func Test_BuildOverlay(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var buildAllOverlaysTests = []struct{
|
var buildAllOverlaysTests = []struct {
|
||||||
description string
|
description string
|
||||||
nodes []string
|
nodes []string
|
||||||
systemOverlays []string
|
systemOverlays []string
|
||||||
runtimeOverlays []string
|
runtimeOverlays []string
|
||||||
succeed bool
|
succeed bool
|
||||||
}{
|
}{
|
||||||
{"no nodes", nil, nil, nil, true},
|
{"no nodes", nil, nil, nil, true},
|
||||||
{"single empty node", []string{"node1"}, nil, nil, false},
|
{"single empty node", []string{"node1"}, nil, nil, false},
|
||||||
@@ -102,7 +108,6 @@ var buildAllOverlaysTests = []struct{
|
|||||||
[]string{"o1", "o1,o2"}, []string{"o2", "o2"}, true},
|
[]string{"o1", "o1,o2"}, []string{"o2", "o2"}, true},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func Test_BuildAllOverlays(t *testing.T) {
|
func Test_BuildAllOverlays(t *testing.T) {
|
||||||
conf := warewulfconf.Get()
|
conf := warewulfconf.Get()
|
||||||
overlayDir, overlayDirErr := os.MkdirTemp(os.TempDir(), "ww-test-overlay-*")
|
overlayDir, overlayDirErr := os.MkdirTemp(os.TempDir(), "ww-test-overlay-*")
|
||||||
@@ -145,12 +150,12 @@ func Test_BuildAllOverlays(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var buildSpecificOverlaysTests = []struct{
|
var buildSpecificOverlaysTests = []struct {
|
||||||
description string
|
description string
|
||||||
nodes []string
|
nodes []string
|
||||||
overlays string
|
overlays string
|
||||||
images []string
|
images []string
|
||||||
succeed bool
|
succeed bool
|
||||||
}{
|
}{
|
||||||
{"no nodes", nil, "", nil, true},
|
{"no nodes", nil, "", nil, true},
|
||||||
{"single empty node", []string{"node1"}, "", nil, false},
|
{"single empty node", []string{"node1"}, "", nil, false},
|
||||||
@@ -165,7 +170,6 @@ var buildSpecificOverlaysTests = []struct{
|
|||||||
[]string{"node1/o1.img", "node1/o2.img", "node2/o1.img", "node2/o2.img"}, true},
|
[]string{"node1/o1.img", "node1/o2.img", "node2/o1.img", "node2/o2.img"}, true},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func Test_BuildSpecificOverlays(t *testing.T) {
|
func Test_BuildSpecificOverlays(t *testing.T) {
|
||||||
conf := warewulfconf.Get()
|
conf := warewulfconf.Get()
|
||||||
overlayDir, overlayDirErr := os.MkdirTemp(os.TempDir(), "ww-test-overlay-*")
|
overlayDir, overlayDirErr := os.MkdirTemp(os.TempDir(), "ww-test-overlay-*")
|
||||||
@@ -220,13 +224,17 @@ func dirIsEmpty(t *testing.T, name string) bool {
|
|||||||
|
|
||||||
func cpioFiles(t *testing.T, name string) (files []string) {
|
func cpioFiles(t *testing.T, name string) (files []string) {
|
||||||
f, openErr := os.Open(name)
|
f, openErr := os.Open(name)
|
||||||
if openErr != nil { return }
|
if openErr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
reader := cpio.NewReader(f)
|
reader := cpio.NewReader(f)
|
||||||
for {
|
for {
|
||||||
header, err := reader.Next()
|
header, err := reader.Next()
|
||||||
if err != nil { return }
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
files = append(files, header.Filename())
|
files = append(files, header.Filename())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ func New(t *testing.T) (env *TestEnv) {
|
|||||||
conf.Paths.WWChrootdir,
|
conf.Paths.WWChrootdir,
|
||||||
conf.Paths.WWProvisiondir,
|
conf.Paths.WWProvisiondir,
|
||||||
conf.Paths.WWClientdir,
|
conf.Paths.WWClientdir,
|
||||||
}{
|
} {
|
||||||
env.MkdirAll(t, confPath)
|
env.MkdirAll(t, confPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -79,7 +79,6 @@ func getNodeOrSetDiscoverable(hwaddr string) (node.NodeInfo, error) {
|
|||||||
// to ensure the condition on which the node is updated is still satisfied
|
// to ensure the condition on which the node is updated is still satisfied
|
||||||
// after the DB is read back in.
|
// after the DB is read back in.
|
||||||
|
|
||||||
|
|
||||||
n, err := getNode(hwaddr)
|
n, err := getNode(hwaddr)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return n, nil
|
return n, nil
|
||||||
|
|||||||
@@ -49,19 +49,19 @@ func parseReq(req *http.Request) (parserInfo, error) {
|
|||||||
|
|
||||||
if len(req.URL.Query()["stage"]) > 0 {
|
if len(req.URL.Query()["stage"]) > 0 {
|
||||||
ret.stage = req.URL.Query()["stage"][0]
|
ret.stage = req.URL.Query()["stage"][0]
|
||||||
}else{
|
} else {
|
||||||
|
|
||||||
if stage == "ipxe" || stage == "provision" {
|
if stage == "ipxe" || stage == "provision" {
|
||||||
ret.stage = "ipxe"
|
ret.stage = "ipxe"
|
||||||
}else if stage == "kernel" {
|
} else if stage == "kernel" {
|
||||||
ret.stage = "kernel"
|
ret.stage = "kernel"
|
||||||
}else if stage == "kmods" {
|
} else if stage == "kmods" {
|
||||||
ret.stage = "kmods"
|
ret.stage = "kmods"
|
||||||
}else if stage == "container" {
|
} else if stage == "container" {
|
||||||
ret.stage = "container"
|
ret.stage = "container"
|
||||||
}else if stage == "overlay-system" {
|
} else if stage == "overlay-system" {
|
||||||
ret.stage = "system"
|
ret.stage = "system"
|
||||||
}else if stage == "overlay-runtime" {
|
} else if stage == "overlay-runtime" {
|
||||||
ret.stage = "runtime"
|
ret.stage = "runtime"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
|
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/container"
|
"github.com/hpcng/warewulf/internal/pkg/container"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/kernel"
|
"github.com/hpcng/warewulf/internal/pkg/kernel"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||||
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,23 @@
|
|||||||
package warewulfd
|
package warewulfd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"testing"
|
"testing"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
|
||||||
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var provisionSendTests = []struct {
|
||||||
var provisionSendTests = []struct{
|
|
||||||
description string
|
description string
|
||||||
url string
|
url string
|
||||||
body string
|
body string
|
||||||
status int
|
status int
|
||||||
}{
|
}{
|
||||||
{"system overlay", "/overlay-system/00:00:00:ff:ff:ff", "system overlay", 200},
|
{"system overlay", "/overlay-system/00:00:00:ff:ff:ff", "system overlay", 200},
|
||||||
{"runtime overlay", "/overlay-runtime/00:00:00:ff:ff:ff", "runtime overlay", 200},
|
{"runtime overlay", "/overlay-runtime/00:00:00:ff:ff:ff", "runtime overlay", 200},
|
||||||
@@ -30,12 +29,15 @@ func Test_ProvisionSend(t *testing.T) {
|
|||||||
file, err := os.CreateTemp(os.TempDir(), "ww-test-nodes.conf-*")
|
file, err := os.CreateTemp(os.TempDir(), "ww-test-nodes.conf-*")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
{ _, err := file.WriteString(`WW_INTERNAL: 43
|
{
|
||||||
|
_, err := file.WriteString(`WW_INTERNAL: 43
|
||||||
nodes:
|
nodes:
|
||||||
n1:
|
n1:
|
||||||
network devices:
|
network devices:
|
||||||
default:
|
default:
|
||||||
hwaddr: 00:00:00:ff:ff:ff`); assert.NoError(t, err) }
|
hwaddr: 00:00:00:ff:ff:ff`)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
assert.NoError(t, file.Sync())
|
assert.NoError(t, file.Sync())
|
||||||
node.ConfigFile = file.Name()
|
node.ConfigFile = file.Name()
|
||||||
dbErr := LoadNodeDB()
|
dbErr := LoadNodeDB()
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ func sendFile(
|
|||||||
req,
|
req,
|
||||||
filename,
|
filename,
|
||||||
stat.ModTime(),
|
stat.ModTime(),
|
||||||
fd )
|
fd)
|
||||||
|
|
||||||
wwlog.Send("%15s: %s", sendto, filename)
|
wwlog.Send("%15s: %s", sendto, filename)
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
package warewulfd
|
package warewulfd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
var getOverlayFileTests = []struct{
|
var getOverlayFileTests = []struct {
|
||||||
description string
|
description string
|
||||||
node string
|
node string
|
||||||
context string
|
context string
|
||||||
overlays []string
|
overlays []string
|
||||||
result string
|
result string
|
||||||
succeed bool
|
succeed bool
|
||||||
}{
|
}{
|
||||||
{"empty", "", "", nil, "", true},
|
{"empty", "", "", nil, "", true},
|
||||||
{"empty node", "node1", "", nil, "", true},
|
{"empty node", "node1", "", nil, "", true},
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
func Test_Single(t *testing.T) {
|
func Test_Single(t *testing.T) {
|
||||||
assert.Equal(t, []string{"node1"}, Expand([]string{"node1"}))
|
assert.Equal(t, []string{"node1"}, Expand([]string{"node1"}))
|
||||||
}
|
}
|
||||||
@@ -15,12 +14,10 @@ func Test_Multiple(t *testing.T) {
|
|||||||
assert.Equal(t, []string{"node1", "node2"}, Expand([]string{"node1", "node2"}))
|
assert.Equal(t, []string{"node1", "node2"}, Expand([]string{"node1", "node2"}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func Test_Range(t *testing.T) {
|
func Test_Range(t *testing.T) {
|
||||||
assert.Equal(t, []string{"node1", "node2"}, Expand([]string{"node[1-2]"}))
|
assert.Equal(t, []string{"node1", "node2"}, Expand([]string{"node[1-2]"}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func Test_Internal_Comma(t *testing.T) {
|
func Test_Internal_Comma(t *testing.T) {
|
||||||
assert.Equal(t, []string{"node1", "node2"}, Expand([]string{"node[1,2]"}))
|
assert.Equal(t, []string{"node1", "node2"}, Expand([]string{"node[1,2]"}))
|
||||||
}
|
}
|
||||||
@@ -29,7 +26,6 @@ func Test_Mixed_Range_Comma(t *testing.T) {
|
|||||||
assert.Equal(t, []string{"node1", "node2", "node3"}, Expand([]string{"node[1,2-3]"}))
|
assert.Equal(t, []string{"node1", "node2", "node3"}, Expand([]string{"node[1,2-3]"}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// not currently supported
|
// not currently supported
|
||||||
//
|
//
|
||||||
// func Test_External_Comma(t *testing.T) {
|
// func Test_External_Comma(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user