github.com/adityamillind98/nomad@v0.11.8/nomad/system_endpoint_test.go (about)

     1  package nomad
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"testing"
     7  
     8  	memdb "github.com/hashicorp/go-memdb"
     9  	msgpackrpc "github.com/hashicorp/net-rpc-msgpackrpc"
    10  	"github.com/hashicorp/nomad/acl"
    11  	"github.com/hashicorp/nomad/nomad/mock"
    12  	"github.com/hashicorp/nomad/nomad/structs"
    13  	"github.com/hashicorp/nomad/testutil"
    14  	"github.com/stretchr/testify/assert"
    15  )
    16  
    17  func TestSystemEndpoint_GarbageCollect(t *testing.T) {
    18  	t.Parallel()
    19  
    20  	s1, cleanupS1 := TestServer(t, nil)
    21  	defer cleanupS1()
    22  	codec := rpcClient(t, s1)
    23  	testutil.WaitForLeader(t, s1.RPC)
    24  
    25  	// Insert a job that can be GC'd
    26  	state := s1.fsm.State()
    27  	job := mock.Job()
    28  	job.Type = structs.JobTypeBatch
    29  	job.Stop = true
    30  	if err := state.UpsertJob(1000, job); err != nil {
    31  		t.Fatalf("UpsertJob() failed: %v", err)
    32  	}
    33  
    34  	eval := mock.Eval()
    35  	eval.Status = structs.EvalStatusComplete
    36  	eval.JobID = job.ID
    37  	if err := state.UpsertEvals(1001, []*structs.Evaluation{eval}); err != nil {
    38  		t.Fatalf("UpsertEvals() failed: %v", err)
    39  	}
    40  
    41  	// Make the GC request
    42  	req := &structs.GenericRequest{
    43  		QueryOptions: structs.QueryOptions{
    44  			Region: "global",
    45  		},
    46  	}
    47  	var resp structs.GenericResponse
    48  	if err := msgpackrpc.CallWithCodec(codec, "System.GarbageCollect", req, &resp); err != nil {
    49  		t.Fatalf("expect err")
    50  	}
    51  
    52  	testutil.WaitForResult(func() (bool, error) {
    53  		// Check if the job has been GC'd
    54  		ws := memdb.NewWatchSet()
    55  		exist, err := state.JobByID(ws, job.Namespace, job.ID)
    56  		if err != nil {
    57  			return false, err
    58  		}
    59  		if exist != nil {
    60  			return false, fmt.Errorf("job %+v wasn't garbage collected", job)
    61  		}
    62  		return true, nil
    63  	}, func(err error) {
    64  		t.Fatalf("err: %s", err)
    65  	})
    66  }
    67  
    68  func TestSystemEndpoint_GarbageCollect_ACL(t *testing.T) {
    69  	t.Parallel()
    70  
    71  	s1, root, cleanupS1 := TestACLServer(t, nil)
    72  	defer cleanupS1()
    73  	codec := rpcClient(t, s1)
    74  	assert := assert.New(t)
    75  	testutil.WaitForLeader(t, s1.RPC)
    76  	state := s1.fsm.State()
    77  
    78  	// Create ACL tokens
    79  	invalidToken := mock.CreatePolicyAndToken(t, state, 1001, "test-invalid", mock.NodePolicy(acl.PolicyWrite))
    80  
    81  	// Make the GC request
    82  	req := &structs.GenericRequest{
    83  		QueryOptions: structs.QueryOptions{
    84  			Region: "global",
    85  		},
    86  	}
    87  
    88  	// Try without a token and expect failure
    89  	{
    90  		var resp structs.GenericResponse
    91  		err := msgpackrpc.CallWithCodec(codec, "System.GarbageCollect", req, &resp)
    92  		assert.NotNil(err)
    93  		assert.Contains(err.Error(), structs.ErrPermissionDenied.Error())
    94  	}
    95  
    96  	// Try with an invalid token and expect failure
    97  	{
    98  		req.AuthToken = invalidToken.SecretID
    99  		var resp structs.GenericResponse
   100  		err := msgpackrpc.CallWithCodec(codec, "System.GarbageCollect", req, &resp)
   101  		assert.NotNil(err)
   102  		assert.Contains(err.Error(), structs.ErrPermissionDenied.Error())
   103  	}
   104  
   105  	// Try with a management token
   106  	{
   107  		req.AuthToken = root.SecretID
   108  		var resp structs.GenericResponse
   109  		assert.Nil(msgpackrpc.CallWithCodec(codec, "System.GarbageCollect", req, &resp))
   110  	}
   111  }
   112  
   113  func TestSystemEndpoint_ReconcileSummaries(t *testing.T) {
   114  	t.Parallel()
   115  
   116  	s1, cleanupS1 := TestServer(t, nil)
   117  	defer cleanupS1()
   118  	codec := rpcClient(t, s1)
   119  	testutil.WaitForLeader(t, s1.RPC)
   120  
   121  	// Insert a job that can be GC'd
   122  	state := s1.fsm.State()
   123  	s1.fsm.State()
   124  	job := mock.Job()
   125  	if err := state.UpsertJob(1000, job); err != nil {
   126  		t.Fatalf("UpsertJob() failed: %v", err)
   127  	}
   128  
   129  	// Delete the job summary
   130  	state.DeleteJobSummary(1001, job.Namespace, job.ID)
   131  
   132  	// Make the GC request
   133  	req := &structs.GenericRequest{
   134  		QueryOptions: structs.QueryOptions{
   135  			Region: "global",
   136  		},
   137  	}
   138  	var resp structs.GenericResponse
   139  	if err := msgpackrpc.CallWithCodec(codec, "System.ReconcileJobSummaries", req, &resp); err != nil {
   140  		t.Fatalf("expect err: %v", err)
   141  	}
   142  
   143  	testutil.WaitForResult(func() (bool, error) {
   144  		// Check if Nomad has reconciled the summary for the job
   145  		ws := memdb.NewWatchSet()
   146  		summary, err := state.JobSummaryByID(ws, job.Namespace, job.ID)
   147  		if err != nil {
   148  			return false, err
   149  		}
   150  		if summary.CreateIndex == 0 || summary.ModifyIndex == 0 {
   151  			t.Fatalf("create index: %v, modify index: %v", summary.CreateIndex, summary.ModifyIndex)
   152  		}
   153  
   154  		// setting the modifyindex and createindex of the expected summary to
   155  		// the output so that we can do deep equal
   156  		expectedSummary := structs.JobSummary{
   157  			JobID:     job.ID,
   158  			Namespace: job.Namespace,
   159  			Summary: map[string]structs.TaskGroupSummary{
   160  				"web": {
   161  					Queued: 10,
   162  				},
   163  			},
   164  			ModifyIndex: summary.ModifyIndex,
   165  			CreateIndex: summary.CreateIndex,
   166  		}
   167  		if !reflect.DeepEqual(&expectedSummary, summary) {
   168  			return false, fmt.Errorf("expected: %v, actual: %v", expectedSummary, summary)
   169  		}
   170  		return true, nil
   171  	}, func(err error) {
   172  		t.Fatalf("err: %s", err)
   173  	})
   174  }
   175  
   176  func TestSystemEndpoint_ReconcileJobSummaries_ACL(t *testing.T) {
   177  	t.Parallel()
   178  
   179  	s1, root, cleanupS1 := TestACLServer(t, nil)
   180  	defer cleanupS1()
   181  	codec := rpcClient(t, s1)
   182  	assert := assert.New(t)
   183  	testutil.WaitForLeader(t, s1.RPC)
   184  	state := s1.fsm.State()
   185  
   186  	// Create ACL tokens
   187  	invalidToken := mock.CreatePolicyAndToken(t, state, 1001, "test-invalid", mock.NodePolicy(acl.PolicyWrite))
   188  
   189  	// Make the request
   190  	req := &structs.GenericRequest{
   191  		QueryOptions: structs.QueryOptions{
   192  			Region: "global",
   193  		},
   194  	}
   195  
   196  	// Try without a token and expect failure
   197  	{
   198  		var resp structs.GenericResponse
   199  		err := msgpackrpc.CallWithCodec(codec, "System.ReconcileJobSummaries", req, &resp)
   200  		assert.NotNil(err)
   201  		assert.Contains(err.Error(), structs.ErrPermissionDenied.Error())
   202  	}
   203  
   204  	// Try with an invalid token and expect failure
   205  	{
   206  		req.AuthToken = invalidToken.SecretID
   207  		var resp structs.GenericResponse
   208  		err := msgpackrpc.CallWithCodec(codec, "System.ReconcileJobSummaries", req, &resp)
   209  		assert.NotNil(err)
   210  		assert.Contains(err.Error(), structs.ErrPermissionDenied.Error())
   211  	}
   212  
   213  	// Try with a management token
   214  	{
   215  		req.AuthToken = root.SecretID
   216  		var resp structs.GenericResponse
   217  		assert.Nil(msgpackrpc.CallWithCodec(codec, "System.ReconcileJobSummaries", req, &resp))
   218  	}
   219  }