2015-09-22 21:04:40 +00:00
|
|
|
package agent
|
|
|
|
|
|
|
|
import (
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
2019-01-08 15:07:36 +00:00
|
|
|
"path/filepath"
|
2015-09-22 21:04:40 +00:00
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/mitchellh/cli"
|
2020-10-05 14:52:07 +00:00
|
|
|
|
|
|
|
"github.com/hashicorp/nomad/version"
|
2015-09-22 21:04:40 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestCommand_Implements(t *testing.T) {
|
2017-07-20 05:42:15 +00:00
|
|
|
t.Parallel()
|
2015-09-22 21:04:40 +00:00
|
|
|
var _ cli.Command = &Command{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCommand_Args(t *testing.T) {
|
2017-07-20 05:42:15 +00:00
|
|
|
t.Parallel()
|
2015-09-22 21:04:40 +00:00
|
|
|
tmpDir, err := ioutil.TempDir("", "nomad")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
defer os.RemoveAll(tmpDir)
|
|
|
|
|
|
|
|
type tcase struct {
|
|
|
|
args []string
|
|
|
|
errOut string
|
|
|
|
}
|
|
|
|
tcases := []tcase{
|
|
|
|
{
|
|
|
|
[]string{},
|
2015-10-01 23:46:42 +00:00
|
|
|
"Must specify either server, client or dev mode for the agent.",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
[]string{"-client", "-data-dir=" + tmpDir, "-bootstrap-expect=1"},
|
2015-09-22 21:04:40 +00:00
|
|
|
"Bootstrap requires server mode to be enabled",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
[]string{"-data-dir=" + tmpDir, "-server", "-bootstrap-expect=1"},
|
|
|
|
"WARNING: Bootstrap mode enabled!",
|
|
|
|
},
|
2015-10-01 23:46:42 +00:00
|
|
|
{
|
|
|
|
[]string{"-server"},
|
|
|
|
"Must specify data directory",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
[]string{"-client", "-alloc-dir="},
|
2018-08-30 20:43:09 +00:00
|
|
|
"Must specify the state, alloc dir, and plugin dir if data-dir is omitted.",
|
2015-10-01 23:46:42 +00:00
|
|
|
},
|
2019-01-07 16:42:44 +00:00
|
|
|
{
|
|
|
|
[]string{"-client", "-data-dir=" + tmpDir, "-meta=invalid..key=inaccessible-value"},
|
|
|
|
"Invalid Client.Meta key: invalid..key",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
[]string{"-client", "-data-dir=" + tmpDir, "-meta=.invalid=inaccessible-value"},
|
|
|
|
"Invalid Client.Meta key: .invalid",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
[]string{"-client", "-data-dir=" + tmpDir, "-meta=invalid.=inaccessible-value"},
|
|
|
|
"Invalid Client.Meta key: invalid.",
|
|
|
|
},
|
2015-09-22 21:04:40 +00:00
|
|
|
}
|
|
|
|
for _, tc := range tcases {
|
2018-03-11 17:58:48 +00:00
|
|
|
// Make a new command. We preemptively close the shutdownCh
|
2015-09-22 21:04:40 +00:00
|
|
|
// so that the command exits immediately instead of blocking.
|
2020-10-05 14:07:41 +00:00
|
|
|
ui := cli.NewMockUi()
|
2015-09-22 21:04:40 +00:00
|
|
|
shutdownCh := make(chan struct{})
|
|
|
|
close(shutdownCh)
|
|
|
|
cmd := &Command{
|
2017-08-16 23:14:59 +00:00
|
|
|
Version: version.GetVersion(),
|
2015-09-22 21:04:40 +00:00
|
|
|
Ui: ui,
|
|
|
|
ShutdownCh: shutdownCh,
|
|
|
|
}
|
|
|
|
|
2016-11-09 00:22:04 +00:00
|
|
|
// To prevent test failures on hosts whose hostname resolves to
|
|
|
|
// a loopback address, we must append a bind address
|
2016-11-09 19:37:41 +00:00
|
|
|
tc.args = append(tc.args, "-bind=169.254.0.1")
|
2015-09-22 21:04:40 +00:00
|
|
|
if code := cmd.Run(tc.args); code != 1 {
|
|
|
|
t.Fatalf("args: %v\nexit: %d\n", tc.args, code)
|
|
|
|
}
|
|
|
|
|
|
|
|
if expect := tc.errOut; expect != "" {
|
|
|
|
out := ui.ErrorWriter.String()
|
|
|
|
if !strings.Contains(out, expect) {
|
|
|
|
t.Fatalf("expect to find %q\n\n%s", expect, out)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-01-08 15:07:36 +00:00
|
|
|
|
|
|
|
func TestCommand_MetaConfigValidation(t *testing.T) {
|
|
|
|
tmpDir, err := ioutil.TempDir("", "nomad")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
defer os.RemoveAll(tmpDir)
|
|
|
|
|
|
|
|
tcases := []string{
|
|
|
|
"foo..invalid",
|
|
|
|
".invalid",
|
|
|
|
"invalid.",
|
|
|
|
}
|
|
|
|
for _, tc := range tcases {
|
|
|
|
configFile := filepath.Join(tmpDir, "conf1.hcl")
|
|
|
|
err = ioutil.WriteFile(configFile, []byte(`client{
|
|
|
|
enabled = true
|
|
|
|
meta = {
|
|
|
|
"valid" = "yes"
|
|
|
|
"`+tc+`" = "kaboom!"
|
|
|
|
"nested.var" = "is nested"
|
|
|
|
"deeply.nested.var" = "is deeply nested"
|
|
|
|
}
|
|
|
|
}`), 0600)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make a new command. We preemptively close the shutdownCh
|
|
|
|
// so that the command exits immediately instead of blocking.
|
2020-10-05 14:07:41 +00:00
|
|
|
ui := cli.NewMockUi()
|
2019-01-08 15:07:36 +00:00
|
|
|
shutdownCh := make(chan struct{})
|
|
|
|
close(shutdownCh)
|
|
|
|
cmd := &Command{
|
|
|
|
Version: version.GetVersion(),
|
|
|
|
Ui: ui,
|
|
|
|
ShutdownCh: shutdownCh,
|
|
|
|
}
|
|
|
|
|
|
|
|
// To prevent test failures on hosts whose hostname resolves to
|
|
|
|
// a loopback address, we must append a bind address
|
|
|
|
args := []string{"-client", "-data-dir=" + tmpDir, "-config=" + configFile, "-bind=169.254.0.1"}
|
|
|
|
if code := cmd.Run(args); code != 1 {
|
|
|
|
t.Fatalf("args: %v\nexit: %d\n", args, code)
|
|
|
|
}
|
|
|
|
|
|
|
|
expect := "Invalid Client.Meta key: " + tc
|
|
|
|
out := ui.ErrorWriter.String()
|
|
|
|
if !strings.Contains(out, expect) {
|
|
|
|
t.Fatalf("expect to find %q\n\n%s", expect, out)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-10-05 14:52:07 +00:00
|
|
|
|
|
|
|
func TestCommand_NullCharInDatacenter(t *testing.T) {
|
|
|
|
tmpDir, err := ioutil.TempDir("", "nomad")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
defer os.RemoveAll(tmpDir)
|
|
|
|
|
|
|
|
tcases := []string{
|
|
|
|
"char-\\000-in-the-middle",
|
|
|
|
"ends-with-\\000",
|
|
|
|
"\\000-at-the-beginning",
|
|
|
|
}
|
|
|
|
for _, tc := range tcases {
|
|
|
|
configFile := filepath.Join(tmpDir, "conf1.hcl")
|
|
|
|
err = ioutil.WriteFile(configFile, []byte(`
|
|
|
|
datacenter = "`+tc+`"
|
|
|
|
client{
|
|
|
|
enabled = true
|
|
|
|
}`), 0600)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make a new command. We preemptively close the shutdownCh
|
|
|
|
// so that the command exits immediately instead of blocking.
|
|
|
|
ui := cli.NewMockUi()
|
|
|
|
shutdownCh := make(chan struct{})
|
|
|
|
close(shutdownCh)
|
|
|
|
cmd := &Command{
|
|
|
|
Version: version.GetVersion(),
|
|
|
|
Ui: ui,
|
|
|
|
ShutdownCh: shutdownCh,
|
|
|
|
}
|
|
|
|
|
|
|
|
// To prevent test failures on hosts whose hostname resolves to
|
|
|
|
// a loopback address, we must append a bind address
|
|
|
|
args := []string{"-client", "-data-dir=" + tmpDir, "-config=" + configFile, "-bind=169.254.0.1"}
|
|
|
|
if code := cmd.Run(args); code != 1 {
|
|
|
|
t.Fatalf("args: %v\nexit: %d\n", args, code)
|
|
|
|
}
|
|
|
|
|
|
|
|
out := ui.ErrorWriter.String()
|
|
|
|
exp := "Datacenter contains invalid characters"
|
|
|
|
if !strings.Contains(out, exp) {
|
|
|
|
t.Fatalf("expect to find %q\n\n%s", exp, out)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCommand_NullCharInRegion(t *testing.T) {
|
|
|
|
tmpDir, err := ioutil.TempDir("", "nomad")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
defer os.RemoveAll(tmpDir)
|
|
|
|
|
|
|
|
tcases := []string{
|
|
|
|
"char-\\000-in-the-middle",
|
|
|
|
"ends-with-\\000",
|
|
|
|
"\\000-at-the-beginning",
|
|
|
|
}
|
|
|
|
for _, tc := range tcases {
|
|
|
|
configFile := filepath.Join(tmpDir, "conf1.hcl")
|
|
|
|
err = ioutil.WriteFile(configFile, []byte(`
|
|
|
|
region = "`+tc+`"
|
|
|
|
client{
|
|
|
|
enabled = true
|
|
|
|
}`), 0600)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make a new command. We preemptively close the shutdownCh
|
|
|
|
// so that the command exits immediately instead of blocking.
|
|
|
|
ui := cli.NewMockUi()
|
|
|
|
shutdownCh := make(chan struct{})
|
|
|
|
close(shutdownCh)
|
|
|
|
cmd := &Command{
|
|
|
|
Version: version.GetVersion(),
|
|
|
|
Ui: ui,
|
|
|
|
ShutdownCh: shutdownCh,
|
|
|
|
}
|
|
|
|
|
|
|
|
// To prevent test failures on hosts whose hostname resolves to
|
|
|
|
// a loopback address, we must append a bind address
|
|
|
|
args := []string{"-client", "-data-dir=" + tmpDir, "-config=" + configFile, "-bind=169.254.0.1"}
|
|
|
|
if code := cmd.Run(args); code != 1 {
|
|
|
|
t.Fatalf("args: %v\nexit: %d\n", args, code)
|
|
|
|
}
|
|
|
|
|
|
|
|
out := ui.ErrorWriter.String()
|
|
|
|
exp := "Region contains invalid characters"
|
|
|
|
if !strings.Contains(out, exp) {
|
|
|
|
t.Fatalf("expect to find %q\n\n%s", exp, out)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|