mirror of
https://github.com/kemko/nomad.git
synced 2026-01-01 16:05:42 +03:00
also remove Error logs from client rpc and promote plugin Debug logs to Error (since they have more info in them)
233 lines
4.9 KiB
Go
233 lines
4.9 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package command
|
|
|
|
import (
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/hashicorp/cli"
|
|
"github.com/hashicorp/hcl"
|
|
"github.com/hashicorp/nomad/api"
|
|
"github.com/hashicorp/nomad/ci"
|
|
"github.com/hashicorp/nomad/command/agent"
|
|
"github.com/shoenig/test/must"
|
|
)
|
|
|
|
func TestHostVolumeCreateCommand_Run(t *testing.T) {
|
|
ci.Parallel(t)
|
|
srv, client, url := testServer(t, true, func(c *agent.Config) {
|
|
c.Client.Meta = map[string]string{"rack": "foo"}
|
|
})
|
|
t.Cleanup(srv.Shutdown)
|
|
|
|
waitForNodes(t, client)
|
|
|
|
_, err := client.Namespaces().Register(&api.Namespace{Name: "prod"}, nil)
|
|
must.NoError(t, err)
|
|
|
|
ui := cli.NewMockUi()
|
|
cmd := &VolumeCreateCommand{Meta: Meta{Ui: ui}}
|
|
|
|
hclTestFile := `
|
|
namespace = "prod"
|
|
name = "database"
|
|
type = "host"
|
|
plugin_id = "mkdir"
|
|
node_pool = "default"
|
|
|
|
capacity_min = "10GiB"
|
|
capacity_max = "20G"
|
|
|
|
constraint {
|
|
attribute = "${meta.rack}"
|
|
value = "foo"
|
|
}
|
|
|
|
capability {
|
|
access_mode = "single-node-writer"
|
|
attachment_mode = "file-system"
|
|
}
|
|
|
|
capability {
|
|
access_mode = "single-node-reader-only"
|
|
attachment_mode = "block-device"
|
|
}
|
|
|
|
parameters {
|
|
mode = "0700"
|
|
}
|
|
`
|
|
|
|
file, err := os.CreateTemp(t.TempDir(), "volume-test-*.hcl")
|
|
must.NoError(t, err)
|
|
_, err = file.WriteString(hclTestFile)
|
|
must.NoError(t, err)
|
|
|
|
args := []string{"-address", url, "-detach", file.Name()}
|
|
|
|
code := cmd.Run(args)
|
|
must.Eq(t, 0, code, must.Sprintf("got error: %s", ui.ErrorWriter.String()))
|
|
|
|
out := ui.OutputWriter.String()
|
|
must.StrContains(t, out, "Created host volume")
|
|
parts := strings.Split(out, " ")
|
|
id := strings.TrimSpace(parts[len(parts)-1])
|
|
|
|
// Verify volume was created
|
|
got, _, err := client.HostVolumes().Get(id, &api.QueryOptions{Namespace: "prod"})
|
|
must.NoError(t, err)
|
|
must.NotNil(t, got)
|
|
|
|
// Verify we can update the volume without changes
|
|
args = []string{"-address", url, "-detach", "-id", got.ID, file.Name()}
|
|
code = cmd.Run(args)
|
|
must.Eq(t, 0, code, must.Sprintf("got error: %s", ui.ErrorWriter.String()))
|
|
list, _, err := client.HostVolumes().List(nil, &api.QueryOptions{Namespace: "prod"})
|
|
must.Len(t, 1, list, must.Sprintf("new volume should not be created on update"))
|
|
}
|
|
|
|
func TestHostVolume_HCLDecode(t *testing.T) {
|
|
ci.Parallel(t)
|
|
|
|
cases := []struct {
|
|
name string
|
|
hcl string
|
|
expected *api.HostVolume
|
|
errMsg string
|
|
}{
|
|
{
|
|
name: "full spec",
|
|
hcl: `
|
|
namespace = "prod"
|
|
name = "database"
|
|
type = "host"
|
|
plugin_id = "mkdir"
|
|
node_pool = "default"
|
|
|
|
capacity_min = "10GiB"
|
|
capacity_max = "20G"
|
|
|
|
constraint {
|
|
attribute = "${attr.kernel.name}"
|
|
value = "linux"
|
|
}
|
|
|
|
constraint {
|
|
attribute = "${meta.rack}"
|
|
value = "foo"
|
|
}
|
|
|
|
capability {
|
|
access_mode = "single-node-writer"
|
|
attachment_mode = "file-system"
|
|
}
|
|
|
|
capability {
|
|
access_mode = "single-node-reader-only"
|
|
attachment_mode = "block-device"
|
|
}
|
|
|
|
parameters {
|
|
foo = "bar"
|
|
}
|
|
`,
|
|
expected: &api.HostVolume{
|
|
Namespace: "prod",
|
|
Name: "database",
|
|
PluginID: "mkdir",
|
|
NodePool: "default",
|
|
Constraints: []*api.Constraint{{
|
|
LTarget: "${attr.kernel.name}",
|
|
RTarget: "linux",
|
|
Operand: "=",
|
|
}, {
|
|
LTarget: "${meta.rack}",
|
|
RTarget: "foo",
|
|
Operand: "=",
|
|
}},
|
|
RequestedCapacityMinBytes: 10737418240,
|
|
RequestedCapacityMaxBytes: 20000000000,
|
|
RequestedCapabilities: []*api.HostVolumeCapability{
|
|
{
|
|
AttachmentMode: api.HostVolumeAttachmentModeFilesystem,
|
|
AccessMode: api.HostVolumeAccessModeSingleNodeWriter,
|
|
},
|
|
{
|
|
AttachmentMode: api.HostVolumeAttachmentModeBlockDevice,
|
|
AccessMode: api.HostVolumeAccessModeSingleNodeReader,
|
|
},
|
|
},
|
|
Parameters: map[string]string{"foo": "bar"},
|
|
},
|
|
},
|
|
|
|
{
|
|
name: "mostly empty spec",
|
|
hcl: `
|
|
namespace = "prod"
|
|
name = "database"
|
|
type = "host"
|
|
plugin_id = "mkdir"
|
|
node_pool = "default"
|
|
`,
|
|
expected: &api.HostVolume{
|
|
Namespace: "prod",
|
|
Name: "database",
|
|
PluginID: "mkdir",
|
|
NodePool: "default",
|
|
},
|
|
},
|
|
|
|
{
|
|
name: "invalid capacity",
|
|
hcl: `
|
|
namespace = "prod"
|
|
name = "database"
|
|
type = "host"
|
|
plugin_id = "mkdir"
|
|
node_pool = "default"
|
|
|
|
capacity_min = "a"
|
|
`,
|
|
expected: nil,
|
|
errMsg: "invalid capacity_min: could not parse value as bytes: strconv.ParseFloat: parsing \"\": invalid syntax",
|
|
},
|
|
|
|
{
|
|
name: "invalid constraint",
|
|
hcl: `
|
|
namespace = "prod"
|
|
name = "database"
|
|
type = "host"
|
|
plugin_id = "mkdir"
|
|
node_pool = "default"
|
|
|
|
constraint {
|
|
distinct_hosts = "foo"
|
|
}
|
|
|
|
`,
|
|
expected: nil,
|
|
errMsg: "invalid constraint: distinct_hosts should be set to true or false; strconv.ParseBool: parsing \"foo\": invalid syntax",
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
ast, err := hcl.ParseString(tc.hcl)
|
|
must.NoError(t, err)
|
|
vol, err := decodeHostVolume(ast)
|
|
if tc.errMsg == "" {
|
|
must.NoError(t, err)
|
|
} else {
|
|
must.EqError(t, err, tc.errMsg)
|
|
}
|
|
must.Eq(t, tc.expected, vol)
|
|
})
|
|
}
|
|
|
|
}
|