github.com/uchennaokeke444/nomad@v0.11.8/nomad/periodic_endpoint_test.go (about) 1 package nomad 2 3 import ( 4 "testing" 5 6 memdb "github.com/hashicorp/go-memdb" 7 msgpackrpc "github.com/hashicorp/net-rpc-msgpackrpc" 8 "github.com/hashicorp/nomad/acl" 9 "github.com/hashicorp/nomad/nomad/mock" 10 "github.com/hashicorp/nomad/nomad/structs" 11 "github.com/hashicorp/nomad/testutil" 12 "github.com/stretchr/testify/assert" 13 ) 14 15 func TestPeriodicEndpoint_Force(t *testing.T) { 16 t.Parallel() 17 18 s1, cleanupS1 := TestServer(t, func(c *Config) { 19 c.NumSchedulers = 0 // Prevent automatic dequeue 20 }) 21 defer cleanupS1() 22 state := s1.fsm.State() 23 codec := rpcClient(t, s1) 24 testutil.WaitForLeader(t, s1.RPC) 25 26 // Create and insert a periodic job. 27 job := mock.PeriodicJob() 28 job.Periodic.ProhibitOverlap = true // Shouldn't affect anything. 29 if err := state.UpsertJob(100, job); err != nil { 30 t.Fatalf("err: %v", err) 31 } 32 s1.periodicDispatcher.Add(job) 33 34 // Force launch it. 35 req := &structs.PeriodicForceRequest{ 36 JobID: job.ID, 37 WriteRequest: structs.WriteRequest{ 38 Region: "global", 39 Namespace: job.Namespace, 40 }, 41 } 42 43 // Fetch the response 44 var resp structs.PeriodicForceResponse 45 if err := msgpackrpc.CallWithCodec(codec, "Periodic.Force", req, &resp); err != nil { 46 t.Fatalf("err: %v", err) 47 } 48 if resp.Index == 0 { 49 t.Fatalf("bad index: %d", resp.Index) 50 } 51 52 // Lookup the evaluation 53 ws := memdb.NewWatchSet() 54 eval, err := state.EvalByID(ws, resp.EvalID) 55 if err != nil { 56 t.Fatalf("err: %v", err) 57 } 58 if eval == nil { 59 t.Fatalf("expected eval") 60 } 61 if eval.CreateIndex != resp.EvalCreateIndex { 62 t.Fatalf("index mis-match") 63 } 64 } 65 66 func TestPeriodicEndpoint_Force_ACL(t *testing.T) { 67 t.Parallel() 68 69 s1, root, cleanupS1 := TestACLServer(t, func(c *Config) { 70 c.NumSchedulers = 0 // Prevent automatic dequeue 71 }) 72 defer cleanupS1() 73 state := s1.fsm.State() 74 assert := assert.New(t) 75 codec := rpcClient(t, s1) 76 testutil.WaitForLeader(t, s1.RPC) 77 78 // Create and insert a periodic job. 79 job := mock.PeriodicJob() 80 job.Periodic.ProhibitOverlap = true // Shouldn't affect anything. 81 assert.Nil(state.UpsertJob(100, job)) 82 err := s1.periodicDispatcher.Add(job) 83 assert.Nil(err) 84 85 // Force launch it. 86 req := &structs.PeriodicForceRequest{ 87 JobID: job.ID, 88 WriteRequest: structs.WriteRequest{ 89 Region: "global", 90 Namespace: job.Namespace, 91 }, 92 } 93 94 // Try with no token and expect permission denied 95 { 96 var resp structs.PeriodicForceResponse 97 err := msgpackrpc.CallWithCodec(codec, "Periodic.Force", req, &resp) 98 assert.NotNil(err) 99 assert.Contains(err.Error(), structs.ErrPermissionDenied.Error()) 100 } 101 102 // Try with an invalid token and expect permission denied 103 { 104 invalidToken := mock.CreatePolicyAndToken(t, state, 1003, "invalid", mock.NodePolicy(acl.PolicyWrite)) 105 req.AuthToken = invalidToken.SecretID 106 var resp structs.PeriodicForceResponse 107 err := msgpackrpc.CallWithCodec(codec, "Periodic.Force", req, &resp) 108 assert.NotNil(err) 109 assert.Contains(err.Error(), structs.ErrPermissionDenied.Error()) 110 } 111 112 // Fetch the response with a valid token 113 { 114 policy := mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilitySubmitJob}) 115 token := mock.CreatePolicyAndToken(t, state, 1005, "valid", policy) 116 req.AuthToken = token.SecretID 117 var resp structs.PeriodicForceResponse 118 assert.Nil(msgpackrpc.CallWithCodec(codec, "Periodic.Force", req, &resp)) 119 assert.NotEqual(uint64(0), resp.Index) 120 121 // Lookup the evaluation 122 ws := memdb.NewWatchSet() 123 eval, err := state.EvalByID(ws, resp.EvalID) 124 assert.Nil(err) 125 if assert.NotNil(eval) { 126 assert.Equal(eval.CreateIndex, resp.EvalCreateIndex) 127 } 128 } 129 130 // Fetch the response with management token 131 { 132 req.AuthToken = root.SecretID 133 var resp structs.PeriodicForceResponse 134 assert.Nil(msgpackrpc.CallWithCodec(codec, "Periodic.Force", req, &resp)) 135 assert.NotEqual(uint64(0), resp.Index) 136 137 // Lookup the evaluation 138 ws := memdb.NewWatchSet() 139 eval, err := state.EvalByID(ws, resp.EvalID) 140 assert.Nil(err) 141 if assert.NotNil(eval) { 142 assert.Equal(eval.CreateIndex, resp.EvalCreateIndex) 143 } 144 } 145 } 146 147 func TestPeriodicEndpoint_Force_NonPeriodic(t *testing.T) { 148 t.Parallel() 149 150 s1, cleanupS1 := TestServer(t, func(c *Config) { 151 c.NumSchedulers = 0 // Prevent automatic dequeue 152 }) 153 defer cleanupS1() 154 state := s1.fsm.State() 155 codec := rpcClient(t, s1) 156 testutil.WaitForLeader(t, s1.RPC) 157 158 // Create and insert a non-periodic job. 159 job := mock.Job() 160 if err := state.UpsertJob(100, job); err != nil { 161 t.Fatalf("err: %v", err) 162 } 163 164 // Force launch it. 165 req := &structs.PeriodicForceRequest{ 166 JobID: job.ID, 167 WriteRequest: structs.WriteRequest{ 168 Region: "global", 169 Namespace: job.Namespace, 170 }, 171 } 172 173 // Fetch the response 174 var resp structs.PeriodicForceResponse 175 if err := msgpackrpc.CallWithCodec(codec, "Periodic.Force", req, &resp); err == nil { 176 t.Fatalf("Force on non-periodic job should err") 177 } 178 }