github.com/djenriquez/nomad-1@v0.8.1/nomad/operator_endpoint_test.go (about)

     1  package nomad
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"strings"
     7  	"testing"
     8  
     9  	"github.com/hashicorp/consul/lib/freeport"
    10  	"github.com/hashicorp/net-rpc-msgpackrpc"
    11  	"github.com/hashicorp/nomad/acl"
    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  )
    18  
    19  func TestOperator_RaftGetConfiguration(t *testing.T) {
    20  	t.Parallel()
    21  	s1 := TestServer(t, nil)
    22  	defer s1.Shutdown()
    23  	codec := rpcClient(t, s1)
    24  	testutil.WaitForLeader(t, s1.RPC)
    25  
    26  	arg := structs.GenericRequest{
    27  		QueryOptions: structs.QueryOptions{
    28  			Region: s1.config.Region,
    29  		},
    30  	}
    31  	var reply structs.RaftConfigurationResponse
    32  	if err := msgpackrpc.CallWithCodec(codec, "Operator.RaftGetConfiguration", &arg, &reply); err != nil {
    33  		t.Fatalf("err: %v", err)
    34  	}
    35  
    36  	future := s1.raft.GetConfiguration()
    37  	if err := future.Error(); err != nil {
    38  		t.Fatalf("err: %v", err)
    39  	}
    40  	if len(future.Configuration().Servers) != 1 {
    41  		t.Fatalf("bad: %v", future.Configuration().Servers)
    42  	}
    43  	me := future.Configuration().Servers[0]
    44  	expected := structs.RaftConfigurationResponse{
    45  		Servers: []*structs.RaftServer{
    46  			{
    47  				ID:           me.ID,
    48  				Node:         fmt.Sprintf("%v.%v", s1.config.NodeName, s1.config.Region),
    49  				Address:      me.Address,
    50  				Leader:       true,
    51  				Voter:        true,
    52  				RaftProtocol: fmt.Sprintf("%d", s1.config.RaftConfig.ProtocolVersion),
    53  			},
    54  		},
    55  		Index: future.Index(),
    56  	}
    57  	if !reflect.DeepEqual(reply, expected) {
    58  		t.Fatalf("bad: got %+v; want %+v", reply, expected)
    59  	}
    60  }
    61  
    62  func TestOperator_RaftGetConfiguration_ACL(t *testing.T) {
    63  	t.Parallel()
    64  	s1, root := TestACLServer(t, nil)
    65  	defer s1.Shutdown()
    66  	codec := rpcClient(t, s1)
    67  	testutil.WaitForLeader(t, s1.RPC)
    68  	assert := assert.New(t)
    69  	state := s1.fsm.State()
    70  
    71  	// Create ACL token
    72  	invalidToken := mock.CreatePolicyAndToken(t, state, 1001, "test-invalid", mock.NodePolicy(acl.PolicyWrite))
    73  
    74  	arg := structs.GenericRequest{
    75  		QueryOptions: structs.QueryOptions{
    76  			Region: s1.config.Region,
    77  		},
    78  	}
    79  
    80  	// Try with no token and expect permission denied
    81  	{
    82  		var reply structs.RaftConfigurationResponse
    83  		err := msgpackrpc.CallWithCodec(codec, "Operator.RaftGetConfiguration", &arg, &reply)
    84  		assert.NotNil(err)
    85  		assert.Equal(err.Error(), structs.ErrPermissionDenied.Error())
    86  	}
    87  
    88  	// Try with an invalid token and expect permission denied
    89  	{
    90  		arg.AuthToken = invalidToken.SecretID
    91  		var reply structs.RaftConfigurationResponse
    92  		err := msgpackrpc.CallWithCodec(codec, "Operator.RaftGetConfiguration", &arg, &reply)
    93  		assert.NotNil(err)
    94  		assert.Equal(err.Error(), structs.ErrPermissionDenied.Error())
    95  	}
    96  
    97  	// Use management token
    98  	{
    99  		arg.AuthToken = root.SecretID
   100  		var reply structs.RaftConfigurationResponse
   101  		assert.Nil(msgpackrpc.CallWithCodec(codec, "Operator.RaftGetConfiguration", &arg, &reply))
   102  
   103  		future := s1.raft.GetConfiguration()
   104  		assert.Nil(future.Error())
   105  		assert.Len(future.Configuration().Servers, 1)
   106  
   107  		me := future.Configuration().Servers[0]
   108  		expected := structs.RaftConfigurationResponse{
   109  			Servers: []*structs.RaftServer{
   110  				{
   111  					ID:           me.ID,
   112  					Node:         fmt.Sprintf("%v.%v", s1.config.NodeName, s1.config.Region),
   113  					Address:      me.Address,
   114  					Leader:       true,
   115  					Voter:        true,
   116  					RaftProtocol: fmt.Sprintf("%d", s1.config.RaftConfig.ProtocolVersion),
   117  				},
   118  			},
   119  			Index: future.Index(),
   120  		}
   121  		assert.Equal(expected, reply)
   122  	}
   123  }
   124  
   125  func TestOperator_RaftRemovePeerByAddress(t *testing.T) {
   126  	t.Parallel()
   127  	s1 := TestServer(t, nil)
   128  	defer s1.Shutdown()
   129  	codec := rpcClient(t, s1)
   130  	testutil.WaitForLeader(t, s1.RPC)
   131  
   132  	// Try to remove a peer that's not there.
   133  	arg := structs.RaftPeerByAddressRequest{
   134  		Address: raft.ServerAddress(fmt.Sprintf("127.0.0.1:%d", freeport.GetT(t, 1)[0])),
   135  	}
   136  	arg.Region = s1.config.Region
   137  	var reply struct{}
   138  	err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply)
   139  	if err == nil || !strings.Contains(err.Error(), "not found in the Raft configuration") {
   140  		t.Fatalf("err: %v", err)
   141  	}
   142  
   143  	// Add it manually to Raft.
   144  	{
   145  		future := s1.raft.AddPeer(arg.Address)
   146  		if err := future.Error(); err != nil {
   147  			t.Fatalf("err: %v", err)
   148  		}
   149  	}
   150  
   151  	// Make sure it's there.
   152  	{
   153  		future := s1.raft.GetConfiguration()
   154  		if err := future.Error(); err != nil {
   155  			t.Fatalf("err: %v", err)
   156  		}
   157  		configuration := future.Configuration()
   158  		if len(configuration.Servers) != 2 {
   159  			t.Fatalf("bad: %v", configuration)
   160  		}
   161  	}
   162  
   163  	// Remove it, now it should go through.
   164  	if err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply); err != nil {
   165  		t.Fatalf("err: %v", err)
   166  	}
   167  
   168  	// Make sure it's not there.
   169  	{
   170  		future := s1.raft.GetConfiguration()
   171  		if err := future.Error(); err != nil {
   172  			t.Fatalf("err: %v", err)
   173  		}
   174  		configuration := future.Configuration()
   175  		if len(configuration.Servers) != 1 {
   176  			t.Fatalf("bad: %v", configuration)
   177  		}
   178  	}
   179  }
   180  
   181  func TestOperator_RaftRemovePeerByAddress_ACL(t *testing.T) {
   182  	t.Parallel()
   183  	s1, root := TestACLServer(t, nil)
   184  	defer s1.Shutdown()
   185  	codec := rpcClient(t, s1)
   186  	testutil.WaitForLeader(t, s1.RPC)
   187  	assert := assert.New(t)
   188  	state := s1.fsm.State()
   189  
   190  	// Create ACL token
   191  	invalidToken := mock.CreatePolicyAndToken(t, state, 1001, "test-invalid", mock.NodePolicy(acl.PolicyWrite))
   192  
   193  	arg := structs.RaftPeerByAddressRequest{
   194  		Address: raft.ServerAddress(fmt.Sprintf("127.0.0.1:%d", freeport.GetT(t, 1)[0])),
   195  	}
   196  	arg.Region = s1.config.Region
   197  
   198  	// Add peer manually to Raft.
   199  	{
   200  		future := s1.raft.AddPeer(arg.Address)
   201  		assert.Nil(future.Error())
   202  	}
   203  
   204  	var reply struct{}
   205  
   206  	// Try with no token and expect permission denied
   207  	{
   208  		err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply)
   209  		assert.NotNil(err)
   210  		assert.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   211  	}
   212  
   213  	// Try with an invalid token and expect permission denied
   214  	{
   215  		arg.AuthToken = invalidToken.SecretID
   216  		err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply)
   217  		assert.NotNil(err)
   218  		assert.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   219  	}
   220  
   221  	// Try with a management token
   222  	{
   223  		arg.AuthToken = root.SecretID
   224  		err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByAddress", &arg, &reply)
   225  		assert.Nil(err)
   226  	}
   227  }
   228  
   229  func TestOperator_RaftRemovePeerByID(t *testing.T) {
   230  	t.Parallel()
   231  	s1 := TestServer(t, func(c *Config) {
   232  		c.RaftConfig.ProtocolVersion = 3
   233  	})
   234  	defer s1.Shutdown()
   235  	codec := rpcClient(t, s1)
   236  	testutil.WaitForLeader(t, s1.RPC)
   237  
   238  	// Try to remove a peer that's not there.
   239  	arg := structs.RaftPeerByIDRequest{
   240  		ID: raft.ServerID("e35bde83-4e9c-434f-a6ef-453f44ee21ea"),
   241  	}
   242  	arg.Region = s1.config.Region
   243  	var reply struct{}
   244  	err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByID", &arg, &reply)
   245  	if err == nil || !strings.Contains(err.Error(), "not found in the Raft configuration") {
   246  		t.Fatalf("err: %v", err)
   247  	}
   248  
   249  	// Add it manually to Raft.
   250  	{
   251  		future := s1.raft.AddVoter(arg.ID, raft.ServerAddress(fmt.Sprintf("127.0.0.1:%d", freeport.GetT(t, 1)[0])), 0, 0)
   252  		if err := future.Error(); err != nil {
   253  			t.Fatalf("err: %v", err)
   254  		}
   255  	}
   256  
   257  	// Make sure it's there.
   258  	{
   259  		future := s1.raft.GetConfiguration()
   260  		if err := future.Error(); err != nil {
   261  			t.Fatalf("err: %v", err)
   262  		}
   263  		configuration := future.Configuration()
   264  		if len(configuration.Servers) != 2 {
   265  			t.Fatalf("bad: %v", configuration)
   266  		}
   267  	}
   268  
   269  	// Remove it, now it should go through.
   270  	if err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByID", &arg, &reply); err != nil {
   271  		t.Fatalf("err: %v", err)
   272  	}
   273  
   274  	// Make sure it's not there.
   275  	{
   276  		future := s1.raft.GetConfiguration()
   277  		if err := future.Error(); err != nil {
   278  			t.Fatalf("err: %v", err)
   279  		}
   280  		configuration := future.Configuration()
   281  		if len(configuration.Servers) != 1 {
   282  			t.Fatalf("bad: %v", configuration)
   283  		}
   284  	}
   285  }
   286  
   287  func TestOperator_RaftRemovePeerByID_ACL(t *testing.T) {
   288  	t.Parallel()
   289  	s1, root := TestACLServer(t, func(c *Config) {
   290  		c.RaftConfig.ProtocolVersion = 3
   291  	})
   292  	defer s1.Shutdown()
   293  	codec := rpcClient(t, s1)
   294  	testutil.WaitForLeader(t, s1.RPC)
   295  	assert := assert.New(t)
   296  	state := s1.fsm.State()
   297  
   298  	// Create ACL token
   299  	invalidToken := mock.CreatePolicyAndToken(t, state, 1001, "test-invalid", mock.NodePolicy(acl.PolicyWrite))
   300  
   301  	arg := structs.RaftPeerByIDRequest{
   302  		ID: raft.ServerID("e35bde83-4e9c-434f-a6ef-453f44ee21ea"),
   303  	}
   304  	arg.Region = s1.config.Region
   305  
   306  	// Add peer manually to Raft.
   307  	{
   308  		future := s1.raft.AddVoter(arg.ID, raft.ServerAddress(fmt.Sprintf("127.0.0.1:%d", freeport.GetT(t, 1)[0])), 0, 0)
   309  		assert.Nil(future.Error())
   310  	}
   311  
   312  	var reply struct{}
   313  
   314  	// Try with no token and expect permission denied
   315  	{
   316  		err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByID", &arg, &reply)
   317  		assert.NotNil(err)
   318  		assert.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   319  	}
   320  
   321  	// Try with an invalid token and expect permission denied
   322  	{
   323  		arg.AuthToken = invalidToken.SecretID
   324  		err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByID", &arg, &reply)
   325  		assert.NotNil(err)
   326  		assert.Equal(err.Error(), structs.ErrPermissionDenied.Error())
   327  	}
   328  
   329  	// Try with a management token
   330  	{
   331  		arg.AuthToken = root.SecretID
   332  		err := msgpackrpc.CallWithCodec(codec, "Operator.RaftRemovePeerByID", &arg, &reply)
   333  		assert.Nil(err)
   334  	}
   335  }