2023-03-28 18:39:22 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
2023-08-11 13:12:13 +00:00
|
|
|
// SPDX-License-Identifier: BUSL-1.1
|
2023-03-28 18:39:22 +00:00
|
|
|
|
2022-11-14 20:35:12 +00:00
|
|
|
package operator
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
2023-01-27 15:17:07 +00:00
|
|
|
"testing"
|
|
|
|
|
2022-11-14 20:35:12 +00:00
|
|
|
"github.com/hashicorp/go-hclog"
|
|
|
|
"github.com/stretchr/testify/mock"
|
2023-01-27 15:17:07 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2023-02-17 21:14:46 +00:00
|
|
|
|
2022-11-14 20:35:12 +00:00
|
|
|
"google.golang.org/grpc"
|
|
|
|
|
2023-01-27 15:17:07 +00:00
|
|
|
"github.com/hashicorp/consul/acl"
|
|
|
|
"github.com/hashicorp/consul/acl/resolver"
|
|
|
|
"github.com/hashicorp/consul/agent/structs"
|
2023-02-17 21:14:46 +00:00
|
|
|
"github.com/hashicorp/consul/proto/private/pboperator"
|
2022-11-14 20:35:12 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type MockBackend struct {
|
|
|
|
mock.Mock
|
|
|
|
authorizer acl.Authorizer
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *MockBackend) TransferLeader(ctx context.Context, request *pboperator.TransferLeaderRequest) (*pboperator.TransferLeaderResponse, error) {
|
|
|
|
called := m.Called(ctx, request)
|
|
|
|
ret := called.Get(0)
|
|
|
|
if ret == nil {
|
|
|
|
return nil, called.Error(1)
|
|
|
|
}
|
|
|
|
return ret.(*pboperator.TransferLeaderResponse), called.Error(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *MockBackend) ResolveTokenAndDefaultMeta(token string, entMeta *acl.EnterpriseMeta, authzCtx *acl.AuthorizerContext) (resolver.Result, error) {
|
|
|
|
return resolver.Result{Authorizer: m.authorizer}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestLeaderTransfer_ACL_Deny(t *testing.T) {
|
|
|
|
authorizer := acl.MockAuthorizer{}
|
|
|
|
authorizer.On("OperatorWrite", mock.Anything).Return(acl.Deny)
|
|
|
|
server := NewServer(Config{Datacenter: "dc1", Backend: &MockBackend{authorizer: &authorizer}, Logger: hclog.New(nil), ForwardRPC: doForwardRPC})
|
|
|
|
|
|
|
|
_, err := server.TransferLeader(context.Background(), &pboperator.TransferLeaderRequest{})
|
|
|
|
require.Error(t, err)
|
2023-01-27 15:17:07 +00:00
|
|
|
require.Equal(t, "Permission denied: token with AccessorID '' lacks permission 'operator:write'", err.Error())
|
2022-11-14 20:35:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestLeaderTransfer_ACL_Allowed(t *testing.T) {
|
|
|
|
authorizer := &acl.MockAuthorizer{}
|
|
|
|
authorizer.On("OperatorWrite", mock.Anything).Return(acl.Allow)
|
|
|
|
|
|
|
|
backend := &MockBackend{authorizer: authorizer}
|
|
|
|
backend.On("TransferLeader", mock.Anything, mock.Anything).Return(nil, nil)
|
|
|
|
server := NewServer(Config{Datacenter: "dc1", Backend: backend, Logger: hclog.New(nil), ForwardRPC: doForwardRPC})
|
|
|
|
|
|
|
|
_, err := server.TransferLeader(context.Background(), &pboperator.TransferLeaderRequest{})
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestLeaderTransfer_LeaderTransfer_Fail(t *testing.T) {
|
|
|
|
authorizer := &acl.MockAuthorizer{}
|
|
|
|
authorizer.On("OperatorWrite", mock.Anything).Return(acl.Allow)
|
|
|
|
|
|
|
|
backend := &MockBackend{authorizer: authorizer}
|
|
|
|
backend.On("TransferLeader", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("test"))
|
|
|
|
server := NewServer(Config{Datacenter: "dc1", Backend: backend, Logger: hclog.New(nil), ForwardRPC: doForwardRPC})
|
|
|
|
|
|
|
|
_, err := server.TransferLeader(context.Background(), &pboperator.TransferLeaderRequest{})
|
|
|
|
require.Error(t, err)
|
|
|
|
require.Equal(t, "test", err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestLeaderTransfer_LeaderTransfer_Success(t *testing.T) {
|
|
|
|
authorizer := &acl.MockAuthorizer{}
|
|
|
|
authorizer.On("OperatorWrite", mock.Anything).Return(acl.Allow)
|
|
|
|
|
|
|
|
backend := &MockBackend{authorizer: authorizer}
|
|
|
|
backend.On("TransferLeader", mock.Anything, mock.Anything).Return(&pboperator.TransferLeaderResponse{Success: true}, nil)
|
|
|
|
server := NewServer(Config{Datacenter: "dc1", Backend: backend, Logger: hclog.New(nil), ForwardRPC: doForwardRPC})
|
|
|
|
|
|
|
|
ret, err := server.TransferLeader(context.Background(), &pboperator.TransferLeaderRequest{})
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, ret)
|
|
|
|
require.True(t, ret.Success)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestLeaderTransfer_LeaderTransfer_ForwardRPC(t *testing.T) {
|
|
|
|
authorizer := &acl.MockAuthorizer{}
|
|
|
|
authorizer.On("OperatorWrite", mock.Anything).Return(acl.Allow)
|
|
|
|
|
|
|
|
backend := &MockBackend{authorizer: authorizer}
|
|
|
|
backend.On("TransferLeader", mock.Anything, mock.Anything).Return(&pboperator.TransferLeaderResponse{}, nil)
|
|
|
|
server := NewServer(Config{Datacenter: "dc1", Backend: backend, Logger: hclog.New(nil), ForwardRPC: noopForwardRPC})
|
|
|
|
|
|
|
|
ret, err := server.TransferLeader(context.Background(), &pboperator.TransferLeaderRequest{})
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, ret)
|
|
|
|
require.False(t, ret.Success)
|
|
|
|
}
|
|
|
|
func noopForwardRPC(structs.RPCInfo, func(*grpc.ClientConn) error) (bool, error) {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func doForwardRPC(structs.RPCInfo, func(*grpc.ClientConn) error) (bool, error) {
|
|
|
|
return false, nil
|
|
|
|
}
|