github.com/thomasobenaus/nomad@v0.11.1/nomad/operator_endpoint_test.go (about)

     1  package nomad
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"strings"
     7  	"testing"
     8  
     9  	msgpackrpc "github.com/hashicorp/net-rpc-msgpackrpc"
    10  	"github.com/hashicorp/nomad/acl"
    11  	"github.com/hashicorp/nomad/helper/freeport"
    12  	"github.com/hashicorp/nomad/nomad/mock"
    13  	"github.com/hashicorp/nomad/nomad/structs"
    14  	"github.com/hashicorp/nomad/testutil"
    15  	"github.com/hashicorp/raft"
    16  	"github.com/stretchr/testify/assert"
    17  	"github.com/stretchr/testify/require"
    18  )
    19  
    20  func TestOperator_RaftGetConfiguration(t *testing.T) {
    21  	t.Parallel()
    22  
    23  	s1, cleanupS1 := TestServer(t, nil)
    24  	defer cleanupS1()
    25  	codec := rpcClient(t, s1)
    26  	testutil.WaitForLeader(t, s1.RPC)
    27  
    28  	arg := structs.GenericRequest{
    29  		QueryOptions: structs.QueryOptions{
    30  			Region: s1.config.Region,
    31  		},
    32  	}
    33  	var reply structs.RaftConfigurationResponse
    34  	if err := msgpackrpc.CallWithCodec(codec, "Operator.RaftGetConfiguration", &arg, &reply); err != nil {
    35  		t.Fatalf("err: %v", err)
    36  	}
    37  
    38  	future := s1.raft.GetConfiguration()
    39  	if err := future.Error(); err != nil {
    40  		t.Fatalf("err: %v", err)
    41  	}
    42  	if len(future.Configuration().Servers) != 1 {
    43  		t.Fatalf("bad: %v", future.Configuration().Servers)
    44  	}
    45  	me := future.Configuration().Servers[0]
    46  	expected := structs.RaftConfigurationResponse{
    47  		Servers: []*structs.RaftServer{
    48  			{
    49  				ID:           me.ID,
    50  				Node:         fmt.Sprintf("%v.%v", s1.config.NodeName, s1.config.Region),
    51  				Address:      me.Address,
    52  				Leader:       true,
    53  				Voter:        true,
    54  				RaftProtocol: fmt.Sprintf("%d", s1.config.RaftConfig.ProtocolVersion),
    55  			},
    56  		},
    57  		Index: future.Index(),
    58  	}
    59  	if !reflect.DeepEqual(reply, expected) {
    60  		t.Fatalf("bad: got %+v; want %+v", reply, expected)
    61  	}
    62  }
    63  
    64  func TestOperator_RaftGetConfiguration_ACL(t *testing.T) {
    65  	t.Parallel()
    66  
    67  	s1, root, cleanupS1 := TestACLServer(t, nil)
    68  	defer cleanupS1()
    69  	codec := rpcClient(t, s1)
    70  	testutil.WaitForLeader(t, s1.RPC)
    71  	assert := assert.New(t)
    72  	state := s1.fsm.State()
    73  
    74  	// Create ACL token
    75  	invalidToken := mock.CreatePolicyAndToken(t, state, 1001, "test-invalid", mock.NodePolicy(acl.PolicyWrite))
    76  
    77  	arg := structs.GenericRequest{
    78  		QueryOptions: structs.QueryOptions{
    79  			Region: s1.config.Region,
    80  		},
    81  	}
    82  
    83  	// Try with no token and expect permission denied
    84  	{
    85  		var reply structs.RaftConfigurationResponse
    86  		err := msgpackrpc.CallWithCodec(codec, "Operator.RaftGetConfiguration", &arg, &reply)
    87  		assert.NotNil(err)
    88  		assert.Equal(err.Error(), structs.ErrPermissionDenied.Error())
    89  	}
    90  
    91  	// Try with an invalid token and expect permission denied
    92  	{
    93  		arg.AuthToken = invalidToken.SecretID
    94  		var reply structs.RaftConfigurationResponse
    95  		err := msgpackrpc.CallWithCodec(codec, "Operator.RaftGetConfiguration", &arg, &reply)
    96  		assert.NotNil(err)
    97  		assert.Equal(err.Error(), structs.ErrPermissionDenied.Error())
    98  	}
    99  
   100  	// Use management token
   101  	{
   102  		arg.AuthToken = root.SecretID
   103  		var reply structs.RaftConfigurationResponse
   104  		assert.Nil(msgpackrpc.CallWithCodec(codec, "Operator.RaftGetConfiguration", &arg, &reply))
   105  
   106  		future := s1.raft.GetConfiguration()
   107  		assert.Nil(future.Error())
   108  		assert.Len(future.Configuration().Servers, 1)
   109  
   110  		me := future.Configuration().Servers[0]
   111  		expected := structs.RaftConfigurationResponse{
   112  			Servers: []*structs.RaftServer{
   113  				{
   114  					ID:           me.ID,
   115  					Node:         fmt.Sprintf("%v.%v", s1.config.NodeName, s1.config.Region),
   116  					Address:      me.Address,
   117  					Leader:       true,
   118  					Voter:        true,
   119  					RaftProtocol: fmt.Sprintf("%d", s1.config.RaftConfig.ProtocolVersion),
   120  				},
   121  			},
   122  			Index: future.Index(),
   123  		}
   124  		assert.Equal(expected, reply)
   125  	}
   126  }
   127  
   128  func TestOperator_RaftRemovePeerByAddress(t *testing.T) {
   129  	t.Parallel()
   130  
   131  	s1, cleanupS1 := TestServer(t, func(c *Config) {
   132  		c.RaftConfig.ProtocolVersion = raft.ProtocolVersion(2)
   133  	})
   134  	defer cleanupS1()
   135  	codec := rpcClient(t, s1)
   136  	testutil.WaitForLeader(t, s1.RPC)
   137  
   138  	ports := freeport.MustTake(1)
   139  	defer freeport.Return(ports)
   140  
   141  	// Try to remove a peer that's not there.
   142  	arg := structs.RaftPeerByAddressRequest{
   143  		Address: raft.ServerAddress(fmt.Sprintf("127.0.0.1:%d", ports[0])),
   144  	}
   145  	arg.Region = s1.config.Region
   146  	var reply struct{}
   147  	err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply)
   148  	if err == nil || !strings.Contains(err.Error(), "not found in the Raft configuration") {
   149  		t.Fatalf("err: %v", err)
   150  	}
   151  
   152  	// Add it manually to Raft.
   153  	{
   154  		future := s1.raft.AddPeer(arg.Address)
   155  		if err := future.Error(); err != nil {
   156  			t.Fatalf("err: %v", err)
   157  		}
   158  	}
   159  
   160  	// Make sure it's there.
   161  	{
   162  		future := s1.raft.GetConfiguration()
   163  		if err := future.Error(); err != nil {
   164  			t.Fatalf("err: %v", err)
   165  		}
   166  		configuration := future.Configuration()
   167  		if len(configuration.Servers) != 2 {
   168  			t.Fatalf("bad: %v", configuration)
   169  		}
   170  	}
   171  
   172  	// Remove it, now it should go through.
   173  	if err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply); err != nil {
   174  		t.Fatalf("err: %v", err)
   175  	}
   176  
   177  	// Make sure it's not there.
   178  	{
   179  		future := s1.raft.GetConfiguration()
   180  		if err := future.Error(); err != nil {
   181  			t.Fatalf("err: %v", err)
   182  		}
   183  		configuration := future.Configuration()
   184  		if len(configuration.Servers) != 1 {
   185  			t.Fatalf("bad: %v", configuration)
   186  		}
   187  	}
   188  }
   189  
   190  func TestOperator_RaftRemovePeerByAddress_ACL(t *testing.T) {
   191  	t.Parallel()
   192  
   193  	s1, root, cleanupS1 := TestACLServer(t, func(c *Config) {
   194  		c.RaftConfig.ProtocolVersion = raft.ProtocolVersion(2)
   195  	})
   196  
   197  	defer cleanupS1()
   198  	codec := rpcClient(t, s1)
   199  	testutil.WaitForLeader(t, s1.RPC)
   200  	assert := assert.New(t)
   201  	state := s1.fsm.State()
   202  
   203  	// Create ACL token
   204  	invalidToken := mock.CreatePolicyAndToken(t, state, 1001, "test-invalid", mock.NodePolicy(acl.PolicyWrite))
   205  
   206  	ports := freeport.MustTake(1)
   207  	defer freeport.Return(ports)
   208  
   209  	arg := structs.RaftPeerByAddressRequest{
   210  		Address: raft.ServerAddress(fmt.Sprintf("127.0.0.1:%d", ports[0])),
   211  	}
   212  	arg.Region = s1.config.Region
   213  
   214  	// Add peer manually to Raft.
   215  	{
   216  		future := s1.raft.AddPeer(arg.Address)
   217  		assert.Nil(future.Error())
   218  	}
   219  
   220  	var reply struct{}
   221  
   222  	// Try with no token and expect permission denied
   223  	{
   224  		err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply)
   225  		assert.NotNil(err)
   226  		assert.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   227  	}
   228  
   229  	// Try with an invalid token and expect permission denied
   230  	{
   231  		arg.AuthToken = invalidToken.SecretID
   232  		err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply)
   233  		assert.NotNil(err)
   234  		assert.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   235  	}
   236  
   237  	// Try with a management token
   238  	{
   239  		arg.AuthToken = root.SecretID
   240  		err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply)
   241  		assert.Nil(err)
   242  	}
   243  }
   244  
   245  func TestOperator_RaftRemovePeerByID(t *testing.T) {
   246  	t.Parallel()
   247  
   248  	s1, cleanupS1 := TestServer(t, func(c *Config) {
   249  		c.RaftConfig.ProtocolVersion = 3
   250  	})
   251  	defer cleanupS1()
   252  	codec := rpcClient(t, s1)
   253  	testutil.WaitForLeader(t, s1.RPC)
   254  
   255  	// Try to remove a peer that's not there.
   256  	arg := structs.RaftPeerByIDRequest{
   257  		ID: raft.ServerID("e35bde83-4e9c-434f-a6ef-453f44ee21ea"),
   258  	}
   259  	arg.Region = s1.config.Region
   260  	var reply struct{}
   261  	err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByID", &arg, &reply)
   262  	if err == nil || !strings.Contains(err.Error(), "not found in the Raft configuration") {
   263  		t.Fatalf("err: %v", err)
   264  	}
   265  
   266  	ports := freeport.MustTake(1)
   267  	defer freeport.Return(ports)
   268  
   269  	// Add it manually to Raft.
   270  	{
   271  		future := s1.raft.AddVoter(arg.ID, raft.ServerAddress(fmt.Sprintf("127.0.0.1:%d", ports[0])), 0, 0)
   272  		if err := future.Error(); err != nil {
   273  			t.Fatalf("err: %v", err)
   274  		}
   275  	}
   276  
   277  	// Make sure it's there.
   278  	{
   279  		future := s1.raft.GetConfiguration()
   280  		if err := future.Error(); err != nil {
   281  			t.Fatalf("err: %v", err)
   282  		}
   283  		configuration := future.Configuration()
   284  		if len(configuration.Servers) != 2 {
   285  			t.Fatalf("bad: %v", configuration)
   286  		}
   287  	}
   288  
   289  	// Remove it, now it should go through.
   290  	if err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByID", &arg, &reply); err != nil {
   291  		t.Fatalf("err: %v", err)
   292  	}
   293  
   294  	// Make sure it's not there.
   295  	{
   296  		future := s1.raft.GetConfiguration()
   297  		if err := future.Error(); err != nil {
   298  			t.Fatalf("err: %v", err)
   299  		}
   300  		configuration := future.Configuration()
   301  		if len(configuration.Servers) != 1 {
   302  			t.Fatalf("bad: %v", configuration)
   303  		}
   304  	}
   305  }
   306  
   307  func TestOperator_RaftRemovePeerByID_ACL(t *testing.T) {
   308  	t.Parallel()
   309  
   310  	s1, root, cleanupS1 := TestACLServer(t, func(c *Config) {
   311  		c.RaftConfig.ProtocolVersion = 3
   312  	})
   313  	defer cleanupS1()
   314  	codec := rpcClient(t, s1)
   315  	testutil.WaitForLeader(t, s1.RPC)
   316  	assert := assert.New(t)
   317  	state := s1.fsm.State()
   318  
   319  	// Create ACL token
   320  	invalidToken := mock.CreatePolicyAndToken(t, state, 1001, "test-invalid", mock.NodePolicy(acl.PolicyWrite))
   321  
   322  	arg := structs.RaftPeerByIDRequest{
   323  		ID: raft.ServerID("e35bde83-4e9c-434f-a6ef-453f44ee21ea"),
   324  	}
   325  	arg.Region = s1.config.Region
   326  
   327  	ports := freeport.MustTake(1)
   328  	defer freeport.Return(ports)
   329  
   330  	// Add peer manually to Raft.
   331  	{
   332  		future := s1.raft.AddVoter(arg.ID, raft.ServerAddress(fmt.Sprintf("127.0.0.1:%d", ports[0])), 0, 0)
   333  		assert.Nil(future.Error())
   334  	}
   335  
   336  	var reply struct{}
   337  
   338  	// Try with no token and expect permission denied
   339  	{
   340  		err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByID", &arg, &reply)
   341  		assert.NotNil(err)
   342  		assert.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   343  	}
   344  
   345  	// Try with an invalid token and expect permission denied
   346  	{
   347  		arg.AuthToken = invalidToken.SecretID
   348  		err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByID", &arg, &reply)
   349  		assert.NotNil(err)
   350  		assert.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   351  	}
   352  
   353  	// Try with a management token
   354  	{
   355  		arg.AuthToken = root.SecretID
   356  		err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByID", &arg, &reply)
   357  		assert.Nil(err)
   358  	}
   359  }
   360  
   361  func TestOperator_SchedulerGetConfiguration(t *testing.T) {
   362  	t.Parallel()
   363  
   364  	s1, cleanupS1 := TestServer(t, func(c *Config) {
   365  		c.Build = "0.9.0+unittest"
   366  	})
   367  	defer cleanupS1()
   368  	codec := rpcClient(t, s1)
   369  	testutil.WaitForLeader(t, s1.RPC)
   370  
   371  	arg := structs.GenericRequest{
   372  		QueryOptions: structs.QueryOptions{
   373  			Region: s1.config.Region,
   374  		},
   375  	}
   376  	var reply structs.SchedulerConfigurationResponse
   377  	if err := msgpackrpc.CallWithCodec(codec, "Operator.SchedulerGetConfiguration", &arg, &reply); err != nil {
   378  		t.Fatalf("err: %v", err)
   379  	}
   380  	require := require.New(t)
   381  	require.NotZero(reply.Index)
   382  	require.True(reply.SchedulerConfig.PreemptionConfig.SystemSchedulerEnabled)
   383  }
   384  
   385  func TestOperator_SchedulerSetConfiguration(t *testing.T) {
   386  	t.Parallel()
   387  
   388  	s1, cleanupS1 := TestServer(t, func(c *Config) {
   389  		c.Build = "0.9.0+unittest"
   390  	})
   391  	defer cleanupS1()
   392  	codec := rpcClient(t, s1)
   393  	testutil.WaitForLeader(t, s1.RPC)
   394  
   395  	require := require.New(t)
   396  
   397  	// Disable preemption
   398  	arg := structs.SchedulerSetConfigRequest{
   399  		Config: structs.SchedulerConfiguration{
   400  			PreemptionConfig: structs.PreemptionConfig{
   401  				SystemSchedulerEnabled: false,
   402  			},
   403  		},
   404  	}
   405  	arg.Region = s1.config.Region
   406  
   407  	var setResponse structs.SchedulerSetConfigurationResponse
   408  	err := msgpackrpc.CallWithCodec(codec, "Operator.SchedulerSetConfiguration", &arg, &setResponse)
   409  	require.Nil(err)
   410  	require.NotZero(setResponse.Index)
   411  
   412  	// Read and verify that preemption is disabled
   413  	readConfig := structs.GenericRequest{
   414  		QueryOptions: structs.QueryOptions{
   415  			Region: s1.config.Region,
   416  		},
   417  	}
   418  	var reply structs.SchedulerConfigurationResponse
   419  	if err := msgpackrpc.CallWithCodec(codec, "Operator.SchedulerGetConfiguration", &readConfig, &reply); err != nil {
   420  		t.Fatalf("err: %v", err)
   421  	}
   422  
   423  	require.NotZero(reply.Index)
   424  	require.False(reply.SchedulerConfig.PreemptionConfig.SystemSchedulerEnabled)
   425  }
   426  
   427  func TestOperator_SchedulerGetConfiguration_ACL(t *testing.T) {
   428  	t.Parallel()
   429  
   430  	s1, root, cleanupS1 := TestACLServer(t, func(c *Config) {
   431  		c.RaftConfig.ProtocolVersion = 3
   432  		c.Build = "0.9.0+unittest"
   433  	})
   434  	defer cleanupS1()
   435  	codec := rpcClient(t, s1)
   436  	testutil.WaitForLeader(t, s1.RPC)
   437  	state := s1.fsm.State()
   438  
   439  	// Create ACL token
   440  	invalidToken := mock.CreatePolicyAndToken(t, state, 1001, "test-invalid", mock.NodePolicy(acl.PolicyWrite))
   441  
   442  	arg := structs.GenericRequest{
   443  		QueryOptions: structs.QueryOptions{
   444  			Region: s1.config.Region,
   445  		},
   446  	}
   447  	require := require.New(t)
   448  	var reply structs.SchedulerConfigurationResponse
   449  
   450  	// Try with no token and expect permission denied
   451  	{
   452  		err := msgpackrpc.CallWithCodec(codec, "Operator.SchedulerGetConfiguration", &arg, &reply)
   453  		require.NotNil(err)
   454  		require.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   455  	}
   456  
   457  	// Try with an invalid token and expect permission denied
   458  	{
   459  		arg.AuthToken = invalidToken.SecretID
   460  		err := msgpackrpc.CallWithCodec(codec, "Operator.SchedulerGetConfiguration", &arg, &reply)
   461  		require.NotNil(err)
   462  		require.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   463  	}
   464  
   465  	// Try with root token, should succeed
   466  	{
   467  		arg.AuthToken = root.SecretID
   468  		err := msgpackrpc.CallWithCodec(codec, "Operator.SchedulerGetConfiguration", &arg, &reply)
   469  		require.Nil(err)
   470  	}
   471  
   472  }
   473  
   474  func TestOperator_SchedulerSetConfiguration_ACL(t *testing.T) {
   475  	t.Parallel()
   476  
   477  	s1, root, cleanupS1 := TestACLServer(t, func(c *Config) {
   478  		c.RaftConfig.ProtocolVersion = 3
   479  		c.Build = "0.9.0+unittest"
   480  	})
   481  	defer cleanupS1()
   482  	codec := rpcClient(t, s1)
   483  	testutil.WaitForLeader(t, s1.RPC)
   484  	state := s1.fsm.State()
   485  
   486  	// Create ACL token
   487  	invalidToken := mock.CreatePolicyAndToken(t, state, 1001, "test-invalid", mock.NodePolicy(acl.PolicyWrite))
   488  
   489  	arg := structs.SchedulerSetConfigRequest{
   490  		Config: structs.SchedulerConfiguration{
   491  			PreemptionConfig: structs.PreemptionConfig{
   492  				SystemSchedulerEnabled: true,
   493  			},
   494  		},
   495  	}
   496  	arg.Region = s1.config.Region
   497  
   498  	require := require.New(t)
   499  	var reply structs.SchedulerSetConfigurationResponse
   500  
   501  	// Try with no token and expect permission denied
   502  	{
   503  		err := msgpackrpc.CallWithCodec(codec, "Operator.SchedulerSetConfiguration", &arg, &reply)
   504  		require.NotNil(err)
   505  		require.Equal(structs.ErrPermissionDenied.Error(), err.Error())
   506  	}
   507  
   508  	// Try with an invalid token and expect permission denied
   509  	{
   510  		arg.AuthToken = invalidToken.SecretID
   511  		err := msgpackrpc.CallWithCodec(codec, "Operator.SchedulerSetConfiguration", &arg, &reply)
   512  		require.NotNil(err)
   513  		require.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   514  	}
   515  
   516  	// Try with root token, should succeed
   517  	{
   518  		arg.AuthToken = root.SecretID
   519  		err := msgpackrpc.CallWithCodec(codec, "Operator.SchedulerSetConfiguration", &arg, &reply)
   520  		require.Nil(err)
   521  	}
   522  
   523  }