// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package namespaces import ( "fmt" "strings" "testing" "github.com/shoenig/test" "github.com/shoenig/test/must" "github.com/stretchr/testify/require" "github.com/hashicorp/nomad/e2e/e2eutil" "github.com/hashicorp/nomad/helper/uuid" ) // TestNamespacesFiltering exercises the -namespace flag on various commands to // ensure that they are properly isolated func TestNamespacesFiltering(t *testing.T) { namespaceIDs := []string{} namespacedJobIDs := [][2]string{} // [(ns, jobID)] t.Cleanup(func() { for _, nsJobID := range namespacedJobIDs { err := e2eutil.StopJob(nsJobID[1], "-purge", "-detach", "-namespace", nsJobID[0]) test.NoError(t, err) } for _, namespaceID := range namespaceIDs { _, err := e2eutil.Command("nomad", "namespace", "delete", namespaceID) test.NoError(t, err) } _, err := e2eutil.Command("nomad", "system", "gc") test.NoError(t, err) }) _, err := e2eutil.Command("nomad", "namespace", "apply", "-description", "namespace A", "NamespaceA") require.NoError(t, err, "could not create namespace") namespaceIDs = append(namespaceIDs, "NamespaceA") _, err = e2eutil.Command("nomad", "namespace", "apply", "-description", "namespace B", "NamespaceB") require.NoError(t, err, "could not create namespace") namespaceIDs = append(namespaceIDs, "NamespaceB") run := func(jobspec, ns string) string { jobID := "test-namespace-" + uuid.Generate()[0:8] must.NoError(t, e2eutil.Register(jobID, jobspec)) namespacedJobIDs = append(namespacedJobIDs, [2]string{ns, jobID}) expected := []string{"running"} require.NoError(t, e2eutil.WaitForAllocStatusExpected(jobID, ns, expected), "job should be running") return jobID } jobA := run("./input/namespace_a.nomad", "NamespaceA") jobB := run("./input/namespace_b.nomad", "NamespaceB") jobDefault := run("./input/namespace_default.nomad", "") // exercise 'nomad job status' filtering parse := func(out string) []map[string]string { rows, err := e2eutil.ParseColumns(out) require.NoError(t, err, "failed to parse job status output: %v", out) result := make([]map[string]string, 0, len(rows)) for _, row := range rows { jobID := row["Job ID"] if jobID == "" { jobID = row["ID"] } if strings.HasPrefix(jobID, "test-namespace-") { result = append(result, row) } } return result } out, err := e2eutil.Command("nomad", "job", "status", "-namespace", "NamespaceA") require.NoError(t, err, "'nomad job status -namespace NamespaceA' failed") rows := parse(out) must.Len(t, 1, rows) must.Eq(t, rows[0]["ID"], jobA) out, err = e2eutil.Command("nomad", "job", "status", "-namespace", "NamespaceB") require.NoError(t, err, "'nomad job status -namespace NamespaceB' failed") rows = parse(out) must.Len(t, 1, rows) must.Eq(t, rows[0]["ID"], jobB) out, err = e2eutil.Command("nomad", "job", "status", "-namespace", "*") require.NoError(t, err, "'nomad job status -namespace *' failed") rows = parse(out) must.Len(t, 3, rows) out, err = e2eutil.Command("nomad", "job", "status") require.NoError(t, err, "'nomad job status' failed") rows = parse(out) must.Len(t, 1, rows) must.Eq(t, rows[0]["ID"], jobDefault) // exercise 'nomad status' filtering out, err = e2eutil.Command("nomad", "status", "-namespace", "NamespaceA") require.NoError(t, err, "'nomad job status -namespace NamespaceA' failed") rows = parse(out) must.Len(t, 1, rows) must.Eq(t, rows[0]["ID"], jobA) out, err = e2eutil.Command("nomad", "status", "-namespace", "NamespaceB") require.NoError(t, err, "'nomad job status -namespace NamespaceB' failed") rows = parse(out) must.Len(t, 1, rows) must.Eq(t, rows[0]["ID"], jobB) out, err = e2eutil.Command("nomad", "status", "-namespace", "*") require.NoError(t, err, "'nomad job status -namespace *' failed") rows = parse(out) must.Len(t, 3, rows) out, err = e2eutil.Command("nomad", "status") require.NoError(t, err, "'nomad status' failed") rows = parse(out) must.Len(t, 1, rows) must.Eq(t, rows[0]["ID"], jobDefault) // exercise 'nomad deployment list' filtering // note: '-namespace *' is only supported for job and alloc subcommands out, err = e2eutil.Command("nomad", "deployment", "list", "-namespace", "NamespaceA") require.NoError(t, err, "'nomad job status -namespace NamespaceA' failed") rows = parse(out) must.Len(t, 1, rows) must.Eq(t, rows[0]["Job ID"], jobA) out, err = e2eutil.Command("nomad", "deployment", "list", "-namespace", "NamespaceB") require.NoError(t, err, "'nomad job status -namespace NamespaceB' failed") rows = parse(out) must.Eq(t, len(rows), 1) must.Eq(t, rows[0]["Job ID"], jobB) out, err = e2eutil.Command("nomad", "deployment", "list") require.NoError(t, err, "'nomad deployment list' failed") rows = parse(out) must.Len(t, 1, rows) must.Eq(t, rows[0]["Job ID"], jobDefault) out, err = e2eutil.Command("nomad", "job", "stop", jobA) must.Eq(t, fmt.Sprintf("No job(s) with prefix or ID %q found\n", jobA), out) must.StrContains(t, err.Error(), "exit status 1") err = e2eutil.StopJob(jobA, "-namespace", "NamespaceA") require.NoError(t, err, "could not stop job in namespace") }