github.com/hernad/nomad@v1.6.112/nomad/namespace_endpoint_test.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package nomad
     5  
     6  import (
     7  	"fmt"
     8  	"testing"
     9  	"time"
    10  
    11  	msgpackrpc "github.com/hashicorp/net-rpc-msgpackrpc"
    12  	"github.com/hernad/nomad/acl"
    13  	"github.com/hernad/nomad/ci"
    14  	"github.com/hernad/nomad/helper/uuid"
    15  	"github.com/hernad/nomad/nomad/mock"
    16  	"github.com/hernad/nomad/nomad/structs"
    17  	"github.com/hernad/nomad/testutil"
    18  	"github.com/stretchr/testify/assert"
    19  )
    20  
    21  func TestNamespaceEndpoint_GetNamespace(t *testing.T) {
    22  	ci.Parallel(t)
    23  	assert := assert.New(t)
    24  	s1, cleanupS1 := TestServer(t, nil)
    25  	defer cleanupS1()
    26  	codec := rpcClient(t, s1)
    27  	testutil.WaitForLeader(t, s1.RPC)
    28  
    29  	// Create the register request
    30  	ns := mock.Namespace()
    31  	s1.fsm.State().UpsertNamespaces(1000, []*structs.Namespace{ns})
    32  
    33  	// Lookup the namespace
    34  	get := &structs.NamespaceSpecificRequest{
    35  		Name:         ns.Name,
    36  		QueryOptions: structs.QueryOptions{Region: "global"},
    37  	}
    38  	var resp structs.SingleNamespaceResponse
    39  	assert.Nil(msgpackrpc.CallWithCodec(codec, "Namespace.GetNamespace", get, &resp))
    40  	assert.EqualValues(1000, resp.Index)
    41  	assert.Equal(ns, resp.Namespace)
    42  
    43  	// Lookup non-existing namespace
    44  	get.Name = uuid.Generate()
    45  	assert.Nil(msgpackrpc.CallWithCodec(codec, "Namespace.GetNamespace", get, &resp))
    46  	assert.EqualValues(1000, resp.Index)
    47  	assert.Nil(resp.Namespace)
    48  }
    49  
    50  func TestNamespaceEndpoint_GetNamespace_ACL(t *testing.T) {
    51  	ci.Parallel(t)
    52  	assert := assert.New(t)
    53  	s1, root, cleanupS1 := TestACLServer(t, nil)
    54  	defer cleanupS1()
    55  	codec := rpcClient(t, s1)
    56  	testutil.WaitForLeader(t, s1.RPC)
    57  
    58  	// Create the register request
    59  	ns1 := mock.Namespace()
    60  	ns2 := mock.Namespace()
    61  	state := s1.fsm.State()
    62  	s1.fsm.State().UpsertNamespaces(1000, []*structs.Namespace{ns1, ns2})
    63  
    64  	// Create the policy and tokens
    65  	validToken := mock.CreatePolicyAndToken(t, state, 1002, "test-valid",
    66  		mock.NamespacePolicy(ns1.Name, "", []string{acl.NamespaceCapabilityReadJob}))
    67  	invalidToken := mock.CreatePolicyAndToken(t, state, 1003, "test-invalid",
    68  		mock.NamespacePolicy(ns2.Name, "", []string{acl.NamespaceCapabilityReadJob}))
    69  
    70  	get := &structs.NamespaceSpecificRequest{
    71  		Name:         ns1.Name,
    72  		QueryOptions: structs.QueryOptions{Region: "global"},
    73  	}
    74  
    75  	// Lookup the namespace without a token and expect failure
    76  	{
    77  		var resp structs.SingleNamespaceResponse
    78  		err := msgpackrpc.CallWithCodec(codec, "Namespace.GetNamespace", get, &resp)
    79  		assert.NotNil(err)
    80  		assert.Equal(err.Error(), structs.ErrPermissionDenied.Error())
    81  	}
    82  
    83  	// Try with an invalid token
    84  	get.AuthToken = invalidToken.SecretID
    85  	{
    86  		var resp structs.SingleNamespaceResponse
    87  		err := msgpackrpc.CallWithCodec(codec, "Namespace.GetNamespace", get, &resp)
    88  		assert.NotNil(err)
    89  		assert.Equal(err.Error(), structs.ErrPermissionDenied.Error())
    90  	}
    91  
    92  	// Try with a valid token
    93  	get.AuthToken = validToken.SecretID
    94  	{
    95  		var resp structs.SingleNamespaceResponse
    96  		assert.Nil(msgpackrpc.CallWithCodec(codec, "Namespace.GetNamespace", get, &resp))
    97  		assert.EqualValues(1000, resp.Index)
    98  		assert.Equal(ns1, resp.Namespace)
    99  	}
   100  
   101  	// Try with a root token
   102  	get.AuthToken = root.SecretID
   103  	{
   104  		var resp structs.SingleNamespaceResponse
   105  		assert.Nil(msgpackrpc.CallWithCodec(codec, "Namespace.GetNamespace", get, &resp))
   106  		assert.EqualValues(1000, resp.Index)
   107  		assert.Equal(ns1, resp.Namespace)
   108  	}
   109  }
   110  
   111  func TestNamespaceEndpoint_GetNamespace_Blocking(t *testing.T) {
   112  	ci.Parallel(t)
   113  	assert := assert.New(t)
   114  	s1, cleanupS1 := TestServer(t, nil)
   115  	defer cleanupS1()
   116  	state := s1.fsm.State()
   117  	codec := rpcClient(t, s1)
   118  	testutil.WaitForLeader(t, s1.RPC)
   119  
   120  	// Create the namespaces
   121  	ns1 := mock.Namespace()
   122  	ns2 := mock.Namespace()
   123  
   124  	// First create an namespace
   125  	time.AfterFunc(100*time.Millisecond, func() {
   126  		assert.Nil(state.UpsertNamespaces(100, []*structs.Namespace{ns1}))
   127  	})
   128  
   129  	// Upsert the namespace we are watching later
   130  	time.AfterFunc(200*time.Millisecond, func() {
   131  		assert.Nil(state.UpsertNamespaces(200, []*structs.Namespace{ns2}))
   132  	})
   133  
   134  	// Lookup the namespace
   135  	req := &structs.NamespaceSpecificRequest{
   136  		Name: ns2.Name,
   137  		QueryOptions: structs.QueryOptions{
   138  			Region:        "global",
   139  			MinQueryIndex: 150,
   140  		},
   141  	}
   142  	var resp structs.SingleNamespaceResponse
   143  	start := time.Now()
   144  	assert.Nil(msgpackrpc.CallWithCodec(codec, "Namespace.GetNamespace", req, &resp))
   145  	assert.EqualValues(200, resp.Index)
   146  	assert.NotNil(resp.Namespace)
   147  	assert.Equal(ns2.Name, resp.Namespace.Name)
   148  
   149  	if elapsed := time.Since(start); elapsed < 200*time.Millisecond {
   150  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp)
   151  	}
   152  
   153  	// Namespace delete triggers watches
   154  	time.AfterFunc(100*time.Millisecond, func() {
   155  		assert.Nil(state.DeleteNamespaces(300, []string{ns2.Name}))
   156  	})
   157  
   158  	req.QueryOptions.MinQueryIndex = 250
   159  	var resp2 structs.SingleNamespaceResponse
   160  	start = time.Now()
   161  	assert.Nil(msgpackrpc.CallWithCodec(codec, "Namespace.GetNamespace", req, &resp2))
   162  	assert.EqualValues(300, resp2.Index)
   163  	assert.Nil(resp2.Namespace)
   164  
   165  	if elapsed := time.Since(start); elapsed < 100*time.Millisecond {
   166  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp2)
   167  	}
   168  }
   169  
   170  func TestNamespaceEndpoint_GetNamespaces(t *testing.T) {
   171  	ci.Parallel(t)
   172  	assert := assert.New(t)
   173  	s1, cleanupS1 := TestServer(t, nil)
   174  	defer cleanupS1()
   175  	codec := rpcClient(t, s1)
   176  	testutil.WaitForLeader(t, s1.RPC)
   177  
   178  	// Create the register request
   179  	ns1 := mock.Namespace()
   180  	ns2 := mock.Namespace()
   181  	s1.fsm.State().UpsertNamespaces(1000, []*structs.Namespace{ns1, ns2})
   182  
   183  	// Lookup the namespace
   184  	get := &structs.NamespaceSetRequest{
   185  		Namespaces:   []string{ns1.Name, ns2.Name},
   186  		QueryOptions: structs.QueryOptions{Region: "global"},
   187  	}
   188  	var resp structs.NamespaceSetResponse
   189  	assert.Nil(msgpackrpc.CallWithCodec(codec, "Namespace.GetNamespaces", get, &resp))
   190  	assert.EqualValues(1000, resp.Index)
   191  	assert.Len(resp.Namespaces, 2)
   192  	assert.Contains(resp.Namespaces, ns1.Name)
   193  	assert.Contains(resp.Namespaces, ns2.Name)
   194  }
   195  
   196  func TestNamespaceEndpoint_GetNamespaces_ACL(t *testing.T) {
   197  	ci.Parallel(t)
   198  	assert := assert.New(t)
   199  	s1, root, cleanupS1 := TestACLServer(t, nil)
   200  	defer cleanupS1()
   201  	codec := rpcClient(t, s1)
   202  	testutil.WaitForLeader(t, s1.RPC)
   203  
   204  	// Create the register request
   205  	ns1 := mock.Namespace()
   206  	ns2 := mock.Namespace()
   207  	state := s1.fsm.State()
   208  	state.UpsertNamespaces(1000, []*structs.Namespace{ns1, ns2})
   209  
   210  	// Create the policy and tokens
   211  	validToken := mock.CreatePolicyAndToken(t, state, 1002, "test-valid",
   212  		mock.NamespacePolicy(ns1.Name, "", []string{acl.NamespaceCapabilityReadJob}))
   213  
   214  	// Lookup the namespace
   215  	get := &structs.NamespaceSetRequest{
   216  		Namespaces:   []string{ns1.Name, ns2.Name},
   217  		QueryOptions: structs.QueryOptions{Region: "global"},
   218  	}
   219  
   220  	// Lookup the namespaces without a token and expect a failure
   221  	{
   222  		var resp structs.NamespaceSetResponse
   223  		assert.NotNil(msgpackrpc.CallWithCodec(codec, "Namespace.GetNamespaces", get, &resp))
   224  	}
   225  
   226  	// Try with an non-management token
   227  	get.AuthToken = validToken.SecretID
   228  	{
   229  		var resp structs.NamespaceSetResponse
   230  		assert.NotNil(msgpackrpc.CallWithCodec(codec, "Namespace.GetNamespaces", get, &resp))
   231  	}
   232  
   233  	// Try with a root token
   234  	get.AuthToken = root.SecretID
   235  	{
   236  		var resp structs.NamespaceSetResponse
   237  		assert.Nil(msgpackrpc.CallWithCodec(codec, "Namespace.GetNamespaces", get, &resp))
   238  		assert.EqualValues(1000, resp.Index)
   239  		assert.Len(resp.Namespaces, 2)
   240  		assert.Contains(resp.Namespaces, ns1.Name)
   241  		assert.Contains(resp.Namespaces, ns2.Name)
   242  	}
   243  }
   244  
   245  func TestNamespaceEndpoint_GetNamespaces_Blocking(t *testing.T) {
   246  	ci.Parallel(t)
   247  	assert := assert.New(t)
   248  	s1, cleanupS1 := TestServer(t, nil)
   249  	defer cleanupS1()
   250  	state := s1.fsm.State()
   251  	codec := rpcClient(t, s1)
   252  	testutil.WaitForLeader(t, s1.RPC)
   253  
   254  	// Create the namespaces
   255  	ns1 := mock.Namespace()
   256  	ns2 := mock.Namespace()
   257  
   258  	// First create an namespace
   259  	time.AfterFunc(100*time.Millisecond, func() {
   260  		assert.Nil(state.UpsertNamespaces(100, []*structs.Namespace{ns1}))
   261  	})
   262  
   263  	// Upsert the namespace we are watching later
   264  	time.AfterFunc(200*time.Millisecond, func() {
   265  		assert.Nil(state.UpsertNamespaces(200, []*structs.Namespace{ns2}))
   266  	})
   267  
   268  	// Lookup the namespace
   269  	req := &structs.NamespaceSetRequest{
   270  		Namespaces: []string{ns2.Name},
   271  		QueryOptions: structs.QueryOptions{
   272  			Region:        "global",
   273  			MinQueryIndex: 150,
   274  		},
   275  	}
   276  	var resp structs.NamespaceSetResponse
   277  	start := time.Now()
   278  	assert.Nil(msgpackrpc.CallWithCodec(codec, "Namespace.GetNamespaces", req, &resp))
   279  	assert.EqualValues(200, resp.Index)
   280  	assert.Len(resp.Namespaces, 1)
   281  	assert.Contains(resp.Namespaces, ns2.Name)
   282  
   283  	if elapsed := time.Since(start); elapsed < 200*time.Millisecond {
   284  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp)
   285  	}
   286  
   287  	// Namespace delete triggers watches
   288  	time.AfterFunc(100*time.Millisecond, func() {
   289  		assert.Nil(state.DeleteNamespaces(300, []string{ns2.Name}))
   290  	})
   291  
   292  	req.QueryOptions.MinQueryIndex = 250
   293  	var resp2 structs.NamespaceSetResponse
   294  	start = time.Now()
   295  	assert.Nil(msgpackrpc.CallWithCodec(codec, "Namespace.GetNamespaces", req, &resp2))
   296  	assert.EqualValues(300, resp2.Index)
   297  	assert.Empty(resp2.Namespaces)
   298  
   299  	if elapsed := time.Since(start); elapsed < 100*time.Millisecond {
   300  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp2)
   301  	}
   302  }
   303  
   304  func TestNamespaceEndpoint_List(t *testing.T) {
   305  	ci.Parallel(t)
   306  	assert := assert.New(t)
   307  	s1, cleanupS1 := TestServer(t, nil)
   308  	defer cleanupS1()
   309  	codec := rpcClient(t, s1)
   310  	testutil.WaitForLeader(t, s1.RPC)
   311  
   312  	// Create the register request
   313  	ns1 := mock.Namespace()
   314  	ns2 := mock.Namespace()
   315  
   316  	ns1.Name = "aaaaaaaa-3350-4b4b-d185-0e1992ed43e9"
   317  	ns2.Name = "aaaabbbb-3350-4b4b-d185-0e1992ed43e9"
   318  	assert.Nil(s1.fsm.State().UpsertNamespaces(1000, []*structs.Namespace{ns1, ns2}))
   319  
   320  	// Lookup the namespaces
   321  	get := &structs.NamespaceListRequest{
   322  		QueryOptions: structs.QueryOptions{Region: "global"},
   323  	}
   324  	var resp structs.NamespaceListResponse
   325  	assert.Nil(msgpackrpc.CallWithCodec(codec, "Namespace.ListNamespaces", get, &resp))
   326  	assert.EqualValues(1000, resp.Index)
   327  	assert.Len(resp.Namespaces, 3)
   328  
   329  	// Lookup the namespaces by prefix
   330  	get = &structs.NamespaceListRequest{
   331  		QueryOptions: structs.QueryOptions{
   332  			Region: "global",
   333  			Prefix: "aaaabb",
   334  		},
   335  	}
   336  	var resp2 structs.NamespaceListResponse
   337  	assert.Nil(msgpackrpc.CallWithCodec(codec, "Namespace.ListNamespaces", get, &resp2))
   338  	assert.EqualValues(1000, resp2.Index)
   339  	assert.Len(resp2.Namespaces, 1)
   340  }
   341  
   342  func TestNamespaceEndpoint_List_ACL(t *testing.T) {
   343  	ci.Parallel(t)
   344  	assert := assert.New(t)
   345  	s1, root, cleanupS1 := TestACLServer(t, nil)
   346  	defer cleanupS1()
   347  	codec := rpcClient(t, s1)
   348  	testutil.WaitForLeader(t, s1.RPC)
   349  
   350  	// Create the register request
   351  	ns1 := mock.Namespace()
   352  	ns2 := mock.Namespace()
   353  	state := s1.fsm.State()
   354  
   355  	ns1.Name = "aaaaaaaa-3350-4b4b-d185-0e1992ed43e9"
   356  	ns2.Name = "bbbbbbbb-3350-4b4b-d185-0e1992ed43e9"
   357  	assert.Nil(s1.fsm.State().UpsertNamespaces(1000, []*structs.Namespace{ns1, ns2}))
   358  
   359  	validDefToken := mock.CreatePolicyAndToken(t, state, 1001, "test-def-valid",
   360  		mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityReadFS}))
   361  	validMultiToken := mock.CreatePolicyAndToken(t, state, 1002, "test-multi-valid", fmt.Sprintf("%s\n%s",
   362  		mock.NamespacePolicy(ns1.Name, "", []string{acl.NamespaceCapabilityReadJob}),
   363  		mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityReadJob})))
   364  	invalidToken := mock.CreatePolicyAndToken(t, state, 1003, "test-invalid",
   365  		mock.NamespacePolicy("invalid-namespace", "", []string{acl.NamespaceCapabilityReadJob}))
   366  
   367  	get := &structs.NamespaceListRequest{
   368  		QueryOptions: structs.QueryOptions{Region: "global"},
   369  	}
   370  
   371  	// Lookup the namespaces without a token and expect a failure
   372  	{
   373  		var resp structs.NamespaceListResponse
   374  		err := msgpackrpc.CallWithCodec(codec, "Namespace.ListNamespaces", get, &resp)
   375  		assert.Nil(err)
   376  		assert.Len(resp.Namespaces, 0)
   377  	}
   378  
   379  	// Try with an invalid token
   380  	get.AuthToken = invalidToken.SecretID
   381  	{
   382  		var resp structs.NamespaceListResponse
   383  		err := msgpackrpc.CallWithCodec(codec, "Namespace.ListNamespaces", get, &resp)
   384  		assert.Nil(err)
   385  		assert.Len(resp.Namespaces, 0)
   386  	}
   387  
   388  	// Try with a valid token for one
   389  	get.AuthToken = validDefToken.SecretID
   390  	{
   391  		var resp structs.NamespaceListResponse
   392  		assert.Nil(msgpackrpc.CallWithCodec(codec, "Namespace.ListNamespaces", get, &resp))
   393  		assert.EqualValues(1000, resp.Index)
   394  		assert.Len(resp.Namespaces, 1)
   395  	}
   396  
   397  	// Try with a valid token for two
   398  	get.AuthToken = validMultiToken.SecretID
   399  	{
   400  		var resp structs.NamespaceListResponse
   401  		assert.Nil(msgpackrpc.CallWithCodec(codec, "Namespace.ListNamespaces", get, &resp))
   402  		assert.EqualValues(1000, resp.Index)
   403  		assert.Len(resp.Namespaces, 2)
   404  	}
   405  
   406  	// Try with a root token
   407  	get.AuthToken = root.SecretID
   408  	{
   409  		var resp structs.NamespaceListResponse
   410  		assert.Nil(msgpackrpc.CallWithCodec(codec, "Namespace.ListNamespaces", get, &resp))
   411  		assert.EqualValues(1000, resp.Index)
   412  		assert.Len(resp.Namespaces, 3)
   413  	}
   414  }
   415  
   416  func TestNamespaceEndpoint_List_Blocking(t *testing.T) {
   417  	ci.Parallel(t)
   418  	assert := assert.New(t)
   419  	s1, cleanupS1 := TestServer(t, nil)
   420  	defer cleanupS1()
   421  	state := s1.fsm.State()
   422  	codec := rpcClient(t, s1)
   423  	testutil.WaitForLeader(t, s1.RPC)
   424  
   425  	// Create the namespace
   426  	ns := mock.Namespace()
   427  
   428  	// Upsert namespace triggers watches
   429  	time.AfterFunc(100*time.Millisecond, func() {
   430  		assert.Nil(state.UpsertNamespaces(200, []*structs.Namespace{ns}))
   431  	})
   432  
   433  	req := &structs.NamespaceListRequest{
   434  		QueryOptions: structs.QueryOptions{
   435  			Region:        "global",
   436  			MinQueryIndex: 150,
   437  		},
   438  	}
   439  	start := time.Now()
   440  	var resp structs.NamespaceListResponse
   441  	assert.Nil(msgpackrpc.CallWithCodec(codec, "Namespace.ListNamespaces", req, &resp))
   442  
   443  	if elapsed := time.Since(start); elapsed < 100*time.Millisecond {
   444  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp)
   445  	}
   446  	assert.EqualValues(200, resp.Index)
   447  	assert.Len(resp.Namespaces, 2)
   448  
   449  	// Namespace deletion triggers watches
   450  	time.AfterFunc(100*time.Millisecond, func() {
   451  		assert.Nil(state.DeleteNamespaces(300, []string{ns.Name}))
   452  	})
   453  
   454  	req.MinQueryIndex = 200
   455  	start = time.Now()
   456  	var resp2 structs.NamespaceListResponse
   457  	assert.Nil(msgpackrpc.CallWithCodec(codec, "Namespace.ListNamespaces", req, &resp2))
   458  
   459  	if elapsed := time.Since(start); elapsed < 100*time.Millisecond {
   460  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp2)
   461  	}
   462  	assert.EqualValues(300, resp2.Index)
   463  	assert.Len(resp2.Namespaces, 1)
   464  }
   465  
   466  func TestNamespaceEndpoint_DeleteNamespaces(t *testing.T) {
   467  	ci.Parallel(t)
   468  	assert := assert.New(t)
   469  	s1, cleanupS1 := TestServer(t, nil)
   470  	defer cleanupS1()
   471  	codec := rpcClient(t, s1)
   472  	testutil.WaitForLeader(t, s1.RPC)
   473  
   474  	// Create the register request
   475  	ns1 := mock.Namespace()
   476  	ns2 := mock.Namespace()
   477  	s1.fsm.State().UpsertNamespaces(1000, []*structs.Namespace{ns1, ns2})
   478  
   479  	// Lookup the namespaces
   480  	req := &structs.NamespaceDeleteRequest{
   481  		Namespaces:   []string{ns1.Name, ns2.Name},
   482  		WriteRequest: structs.WriteRequest{Region: "global"},
   483  	}
   484  	var resp structs.GenericResponse
   485  	assert.Nil(msgpackrpc.CallWithCodec(codec, "Namespace.DeleteNamespaces", req, &resp))
   486  	assert.NotEqual(uint64(0), resp.Index)
   487  }
   488  
   489  func TestNamespaceEndpoint_DeleteNamespaces_NonTerminal_Local(t *testing.T) {
   490  	ci.Parallel(t)
   491  	assert := assert.New(t)
   492  	s1, cleanupS1 := TestServer(t, nil)
   493  	defer cleanupS1()
   494  	codec := rpcClient(t, s1)
   495  	testutil.WaitForLeader(t, s1.RPC)
   496  
   497  	// Create the register request
   498  	ns1 := mock.Namespace()
   499  	ns2 := mock.Namespace()
   500  	s1.fsm.State().UpsertNamespaces(1000, []*structs.Namespace{ns1, ns2})
   501  
   502  	// Create a job in one
   503  	j := mock.Job()
   504  	j.Namespace = ns1.Name
   505  	assert.Nil(s1.fsm.State().UpsertJob(structs.MsgTypeTestSetup, 1001, nil, j))
   506  
   507  	// Lookup the namespaces
   508  	req := &structs.NamespaceDeleteRequest{
   509  		Namespaces:   []string{ns1.Name, ns2.Name},
   510  		WriteRequest: structs.WriteRequest{Region: "global"},
   511  	}
   512  	var resp structs.GenericResponse
   513  	err := msgpackrpc.CallWithCodec(codec, "Namespace.DeleteNamespaces", req, &resp)
   514  	if assert.NotNil(err) {
   515  		assert.Contains(err.Error(), "has non-terminal jobs")
   516  	}
   517  }
   518  
   519  func TestNamespaceEndpoint_DeleteNamespaces_NonTerminal_Federated_ACL(t *testing.T) {
   520  	ci.Parallel(t)
   521  	assert := assert.New(t)
   522  	s1, root, cleanupS1 := TestACLServer(t, func(c *Config) {
   523  		c.Region = "region1"
   524  		c.AuthoritativeRegion = "region1"
   525  		c.ACLEnabled = true
   526  	})
   527  	defer cleanupS1()
   528  	s2, _, cleanupS2 := TestACLServer(t, func(c *Config) {
   529  		c.Region = "region2"
   530  		c.AuthoritativeRegion = "region1"
   531  		c.ACLEnabled = true
   532  		c.ReplicationBackoff = 20 * time.Millisecond
   533  		c.ReplicationToken = root.SecretID
   534  	})
   535  	defer cleanupS2()
   536  	TestJoin(t, s1, s2)
   537  	testutil.WaitForLeader(t, s1.RPC)
   538  	testutil.WaitForLeader(t, s2.RPC)
   539  	codec := rpcClient(t, s1)
   540  
   541  	// Create the register request
   542  	ns1 := mock.Namespace()
   543  	s1.fsm.State().UpsertNamespaces(1000, []*structs.Namespace{ns1})
   544  
   545  	testutil.WaitForResult(func() (bool, error) {
   546  		state := s2.State()
   547  		out, err := state.NamespaceByName(nil, ns1.Name)
   548  		return out != nil, err
   549  	}, func(err error) {
   550  		t.Fatalf("should replicate namespace")
   551  	})
   552  
   553  	// Create a job in the namespace on the non-authority
   554  	j := mock.Job()
   555  	j.Namespace = ns1.Name
   556  	assert.Nil(s2.fsm.State().UpsertJob(structs.MsgTypeTestSetup, 1001, nil, j))
   557  
   558  	// Delete the namespaces without the correct permissions
   559  	req := &structs.NamespaceDeleteRequest{
   560  		Namespaces: []string{ns1.Name},
   561  		WriteRequest: structs.WriteRequest{
   562  			Region: "global",
   563  		},
   564  	}
   565  	var resp structs.GenericResponse
   566  	err := msgpackrpc.CallWithCodec(codec, "Namespace.DeleteNamespaces", req, &resp)
   567  	if assert.NotNil(err) {
   568  		assert.EqualError(err, structs.ErrPermissionDenied.Error())
   569  	}
   570  
   571  	// Try with a auth token
   572  	req.AuthToken = root.SecretID
   573  	var resp2 structs.GenericResponse
   574  	err = msgpackrpc.CallWithCodec(codec, "Namespace.DeleteNamespaces", req, &resp2)
   575  	if assert.NotNil(err) {
   576  		assert.Contains(err.Error(), "has non-terminal jobs")
   577  	}
   578  }
   579  
   580  func TestNamespaceEndpoint_DeleteNamespaces_ACL(t *testing.T) {
   581  	ci.Parallel(t)
   582  	assert := assert.New(t)
   583  	s1, root, cleanupS1 := TestACLServer(t, nil)
   584  	defer cleanupS1()
   585  	codec := rpcClient(t, s1)
   586  	testutil.WaitForLeader(t, s1.RPC)
   587  
   588  	ns1 := mock.Namespace()
   589  	ns2 := mock.Namespace()
   590  	state := s1.fsm.State()
   591  	s1.fsm.State().UpsertNamespaces(1000, []*structs.Namespace{ns1, ns2})
   592  
   593  	// Create the policy and tokens
   594  	invalidToken := mock.CreatePolicyAndToken(t, state, 1003, "test-invalid",
   595  		mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityReadJob}))
   596  
   597  	req := &structs.NamespaceDeleteRequest{
   598  		Namespaces:   []string{ns1.Name, ns2.Name},
   599  		WriteRequest: structs.WriteRequest{Region: "global"},
   600  	}
   601  
   602  	// Delete namespaces without a token and expect failure
   603  	{
   604  		var resp structs.GenericResponse
   605  		err := msgpackrpc.CallWithCodec(codec, "Namespace.DeleteNamespaces", req, &resp)
   606  		assert.NotNil(err)
   607  		assert.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   608  
   609  		// Check we did not delete the namespaces
   610  		out, err := s1.fsm.State().NamespaceByName(nil, ns1.Name)
   611  		assert.Nil(err)
   612  		assert.NotNil(out)
   613  
   614  		out, err = s1.fsm.State().NamespaceByName(nil, ns2.Name)
   615  		assert.Nil(err)
   616  		assert.NotNil(out)
   617  	}
   618  
   619  	// Try with an invalid token
   620  	req.AuthToken = invalidToken.SecretID
   621  	{
   622  		var resp structs.GenericResponse
   623  		err := msgpackrpc.CallWithCodec(codec, "Namespace.DeleteNamespaces", req, &resp)
   624  		assert.NotNil(err)
   625  		assert.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   626  
   627  		// Check we did not delete the namespaces
   628  		out, err := s1.fsm.State().NamespaceByName(nil, ns1.Name)
   629  		assert.Nil(err)
   630  		assert.NotNil(out)
   631  
   632  		out, err = s1.fsm.State().NamespaceByName(nil, ns2.Name)
   633  		assert.Nil(err)
   634  		assert.NotNil(out)
   635  	}
   636  
   637  	// Try with a root token
   638  	req.AuthToken = root.SecretID
   639  	{
   640  		var resp structs.GenericResponse
   641  		assert.Nil(msgpackrpc.CallWithCodec(codec, "Namespace.DeleteNamespaces", req, &resp))
   642  		assert.NotEqual(uint64(0), resp.Index)
   643  
   644  		// Check we deleted the namespaces
   645  		out, err := s1.fsm.State().NamespaceByName(nil, ns1.Name)
   646  		assert.Nil(err)
   647  		assert.Nil(out)
   648  
   649  		out, err = s1.fsm.State().NamespaceByName(nil, ns2.Name)
   650  		assert.Nil(err)
   651  		assert.Nil(out)
   652  	}
   653  }
   654  
   655  func TestNamespaceEndpoint_DeleteNamespaces_Default(t *testing.T) {
   656  	ci.Parallel(t)
   657  	assert := assert.New(t)
   658  	s1, cleanupS1 := TestServer(t, nil)
   659  	defer cleanupS1()
   660  	codec := rpcClient(t, s1)
   661  	testutil.WaitForLeader(t, s1.RPC)
   662  
   663  	// Delete the default namespace
   664  	req := &structs.NamespaceDeleteRequest{
   665  		Namespaces:   []string{structs.DefaultNamespace},
   666  		WriteRequest: structs.WriteRequest{Region: "global"},
   667  	}
   668  	var resp structs.GenericResponse
   669  	assert.NotNil(msgpackrpc.CallWithCodec(codec, "Namespace.DeleteNamespaces", req, &resp))
   670  }
   671  
   672  func TestNamespaceEndpoint_UpsertNamespaces(t *testing.T) {
   673  	ci.Parallel(t)
   674  	assert := assert.New(t)
   675  	s1, cleanupS1 := TestServer(t, nil)
   676  	defer cleanupS1()
   677  	codec := rpcClient(t, s1)
   678  	testutil.WaitForLeader(t, s1.RPC)
   679  
   680  	// Create the register request
   681  	ns1 := mock.Namespace()
   682  	ns2 := mock.Namespace()
   683  
   684  	// Lookup the namespaces
   685  	req := &structs.NamespaceUpsertRequest{
   686  		Namespaces:   []*structs.Namespace{ns1, ns2},
   687  		WriteRequest: structs.WriteRequest{Region: "global"},
   688  	}
   689  	var resp structs.GenericResponse
   690  	assert.Nil(msgpackrpc.CallWithCodec(codec, "Namespace.UpsertNamespaces", req, &resp))
   691  	assert.NotEqual(uint64(0), resp.Index)
   692  
   693  	// Check we created the namespaces
   694  	out, err := s1.fsm.State().NamespaceByName(nil, ns1.Name)
   695  	assert.Nil(err)
   696  	assert.NotNil(out)
   697  
   698  	out, err = s1.fsm.State().NamespaceByName(nil, ns2.Name)
   699  	assert.Nil(err)
   700  	assert.NotNil(out)
   701  }
   702  
   703  func TestNamespaceEndpoint_UpsertNamespaces_ACL(t *testing.T) {
   704  	ci.Parallel(t)
   705  	assert := assert.New(t)
   706  	s1, root, cleanupS1 := TestACLServer(t, nil)
   707  	defer cleanupS1()
   708  	codec := rpcClient(t, s1)
   709  	testutil.WaitForLeader(t, s1.RPC)
   710  
   711  	ns1 := mock.Namespace()
   712  	ns2 := mock.Namespace()
   713  	state := s1.fsm.State()
   714  
   715  	// Create the policy and tokens
   716  	invalidToken := mock.CreatePolicyAndToken(t, state, 1003, "test-invalid",
   717  		mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityReadJob}))
   718  
   719  	// Create the register request
   720  	req := &structs.NamespaceUpsertRequest{
   721  		Namespaces:   []*structs.Namespace{ns1, ns2},
   722  		WriteRequest: structs.WriteRequest{Region: "global"},
   723  	}
   724  
   725  	// Upsert the namespace without a token and expect failure
   726  	{
   727  		var resp structs.GenericResponse
   728  		err := msgpackrpc.CallWithCodec(codec, "Namespace.UpsertNamespaces", req, &resp)
   729  		assert.NotNil(err)
   730  		assert.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   731  
   732  		// Check we did not create the namespaces
   733  		out, err := s1.fsm.State().NamespaceByName(nil, ns1.Name)
   734  		assert.Nil(err)
   735  		assert.Nil(out)
   736  
   737  		out, err = s1.fsm.State().NamespaceByName(nil, ns2.Name)
   738  		assert.Nil(err)
   739  		assert.Nil(out)
   740  	}
   741  
   742  	// Try with an invalid token
   743  	req.AuthToken = invalidToken.SecretID
   744  	{
   745  		var resp structs.GenericResponse
   746  		err := msgpackrpc.CallWithCodec(codec, "Namespace.UpsertNamespaces", req, &resp)
   747  		assert.NotNil(err)
   748  		assert.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   749  
   750  		// Check we did not create the namespaces
   751  		out, err := s1.fsm.State().NamespaceByName(nil, ns1.Name)
   752  		assert.Nil(err)
   753  		assert.Nil(out)
   754  
   755  		out, err = s1.fsm.State().NamespaceByName(nil, ns2.Name)
   756  		assert.Nil(err)
   757  		assert.Nil(out)
   758  	}
   759  
   760  	// Try with a bogus token
   761  	req.AuthToken = uuid.Generate()
   762  	{
   763  		var resp structs.GenericResponse
   764  		err := msgpackrpc.CallWithCodec(codec, "Namespace.UpsertNamespaces", req, &resp)
   765  		assert.NotNil(err)
   766  		assert.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   767  
   768  		// Check we did not create the namespaces
   769  		out, err := s1.fsm.State().NamespaceByName(nil, ns1.Name)
   770  		assert.Nil(err)
   771  		assert.Nil(out)
   772  
   773  		out, err = s1.fsm.State().NamespaceByName(nil, ns2.Name)
   774  		assert.Nil(err)
   775  		assert.Nil(out)
   776  	}
   777  
   778  	// Try with a root token
   779  	req.AuthToken = root.SecretID
   780  	{
   781  		var resp structs.GenericResponse
   782  		assert.Nil(msgpackrpc.CallWithCodec(codec, "Namespace.UpsertNamespaces", req, &resp))
   783  		assert.NotEqual(uint64(0), resp.Index)
   784  
   785  		// Check we created the namespaces
   786  		out, err := s1.fsm.State().NamespaceByName(nil, ns1.Name)
   787  		assert.Nil(err)
   788  		assert.NotNil(out)
   789  
   790  		out, err = s1.fsm.State().NamespaceByName(nil, ns2.Name)
   791  		assert.Nil(err)
   792  		assert.NotNil(out)
   793  	}
   794  }