fe92d8b3cb
Adds new CLI commands for applying, dismissing and detailing Nomad recommendations under a new top level recommendation command.
176 lines
7.3 KiB
Go
176 lines
7.3 KiB
Go
package command
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"testing"
|
|
|
|
"github.com/hashicorp/nomad/api"
|
|
"github.com/hashicorp/nomad/testutil"
|
|
"github.com/mitchellh/cli"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestRecommendationListCommand_Run(t *testing.T) {
|
|
require := require.New(t)
|
|
t.Parallel()
|
|
srv, client, url := testServer(t, true, nil)
|
|
defer srv.Shutdown()
|
|
testutil.WaitForResult(func() (bool, error) {
|
|
nodes, _, err := client.Nodes().List(nil)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if len(nodes) == 0 {
|
|
return false, fmt.Errorf("missing node")
|
|
}
|
|
if _, ok := nodes[0].Drivers["mock_driver"]; !ok {
|
|
return false, fmt.Errorf("mock_driver not ready")
|
|
}
|
|
return true, nil
|
|
}, func(err error) {
|
|
t.Fatalf("err: %s", err)
|
|
})
|
|
|
|
ui := cli.NewMockUi()
|
|
cmd := &RecommendationListCommand{Meta: Meta{Ui: ui}}
|
|
|
|
// Perform an initial list, which should return zero results.
|
|
code := cmd.Run([]string{"-address=" + url})
|
|
if srv.Enterprise {
|
|
require.Equal(0, code)
|
|
out := ui.OutputWriter.String()
|
|
require.Contains(out, "No recommendations found")
|
|
} else {
|
|
require.Equal(1, code)
|
|
require.Contains(ui.ErrorWriter.String(), "Nomad Enterprise only endpoint")
|
|
}
|
|
|
|
// Register a test job to write a recommendation against.
|
|
testJob := testJob("recommendation_list")
|
|
regResp, _, err := client.Jobs().Register(testJob, nil)
|
|
require.NoError(err)
|
|
registerCode := waitForSuccess(ui, client, fullId, t, regResp.EvalID)
|
|
require.Equal(0, registerCode)
|
|
|
|
// Write a recommendation.
|
|
rec := api.Recommendation{
|
|
JobID: *testJob.ID,
|
|
Group: *testJob.TaskGroups[0].Name,
|
|
Task: testJob.TaskGroups[0].Tasks[0].Name,
|
|
Resource: "CPU",
|
|
Value: 1050,
|
|
Meta: map[string]interface{}{"test-meta-entry": "test-meta-value"},
|
|
Stats: map[string]float64{"p13": 1.13},
|
|
}
|
|
_, _, err = client.Recommendations().Upsert(&rec, nil)
|
|
if srv.Enterprise {
|
|
require.NoError(err)
|
|
} else {
|
|
require.Error(err, "Nomad Enterprise only endpoint")
|
|
}
|
|
|
|
// Perform a new list which should yield results.
|
|
code = cmd.Run([]string{"-address=" + url})
|
|
if srv.Enterprise {
|
|
require.Equal(0, code)
|
|
out := ui.OutputWriter.String()
|
|
require.Contains(out, "ID")
|
|
require.Contains(out, "Job")
|
|
require.Contains(out, "Group")
|
|
require.Contains(out, "Task")
|
|
require.Contains(out, "Resource")
|
|
require.Contains(out, "Value")
|
|
require.Contains(out, "CPU")
|
|
} else {
|
|
require.Equal(1, code)
|
|
require.Contains(ui.ErrorWriter.String(), "Nomad Enterprise only endpoint")
|
|
}
|
|
}
|
|
|
|
func TestRecommendationList_Sort(t *testing.T) {
|
|
testCases := []struct {
|
|
inputRecommendationList []*api.Recommendation
|
|
expectedOutputList []*api.Recommendation
|
|
name string
|
|
}{
|
|
{
|
|
inputRecommendationList: []*api.Recommendation{
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "MemoryMB"},
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "CPU"},
|
|
},
|
|
expectedOutputList: []*api.Recommendation{
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "CPU"},
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "MemoryMB"},
|
|
},
|
|
name: "single job with both resources",
|
|
},
|
|
{
|
|
inputRecommendationList: []*api.Recommendation{
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "MemoryMB"},
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "CPU"},
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "mongodb", Resource: "MemoryMB"},
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "mongodb", Resource: "CPU"},
|
|
},
|
|
expectedOutputList: []*api.Recommendation{
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "mongodb", Resource: "CPU"},
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "mongodb", Resource: "MemoryMB"},
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "CPU"},
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "MemoryMB"},
|
|
},
|
|
name: "single job with multiple groups",
|
|
},
|
|
{
|
|
inputRecommendationList: []*api.Recommendation{
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "MemoryMB"},
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "CPU"},
|
|
{Namespace: "default", JobID: "distro", Group: "cache", Task: "redis", Resource: "MemoryMB"},
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "mongodb", Resource: "MemoryMB"},
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "mongodb", Resource: "CPU"},
|
|
{Namespace: "default", JobID: "distro", Group: "cache", Task: "redis", Resource: "CPU"},
|
|
},
|
|
expectedOutputList: []*api.Recommendation{
|
|
{Namespace: "default", JobID: "distro", Group: "cache", Task: "redis", Resource: "CPU"},
|
|
{Namespace: "default", JobID: "distro", Group: "cache", Task: "redis", Resource: "MemoryMB"},
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "mongodb", Resource: "CPU"},
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "mongodb", Resource: "MemoryMB"},
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "CPU"},
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "MemoryMB"},
|
|
},
|
|
name: "multiple jobs",
|
|
},
|
|
{
|
|
inputRecommendationList: []*api.Recommendation{
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "MemoryMB"},
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "CPU"},
|
|
{Namespace: "cefault", JobID: "distro", Group: "cache", Task: "redis", Resource: "MemoryMB"},
|
|
{Namespace: "default", JobID: "distro", Group: "cache", Task: "redis", Resource: "MemoryMB"},
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "mongodb", Resource: "MemoryMB"},
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "mongodb", Resource: "CPU"},
|
|
{Namespace: "default", JobID: "distro", Group: "cache", Task: "redis", Resource: "CPU"},
|
|
{Namespace: "cefault", JobID: "distro", Group: "cache", Task: "redis", Resource: "CPU"},
|
|
},
|
|
expectedOutputList: []*api.Recommendation{
|
|
{Namespace: "cefault", JobID: "distro", Group: "cache", Task: "redis", Resource: "CPU"},
|
|
{Namespace: "cefault", JobID: "distro", Group: "cache", Task: "redis", Resource: "MemoryMB"},
|
|
{Namespace: "default", JobID: "distro", Group: "cache", Task: "redis", Resource: "CPU"},
|
|
{Namespace: "default", JobID: "distro", Group: "cache", Task: "redis", Resource: "MemoryMB"},
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "mongodb", Resource: "CPU"},
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "mongodb", Resource: "MemoryMB"},
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "CPU"},
|
|
{Namespace: "default", JobID: "example", Group: "cache", Task: "redis", Resource: "MemoryMB"},
|
|
},
|
|
name: "multiple namespaces",
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
sortedRecs := recommendationList{r: tc.inputRecommendationList}
|
|
sort.Sort(sortedRecs)
|
|
assert.Equal(t, tc.expectedOutputList, sortedRecs.r, tc.name)
|
|
})
|
|
}
|
|
}
|