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