github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/e2e/events/events.go (about) 1 package events 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/hashicorp/nomad/api" 8 "github.com/hashicorp/nomad/e2e/e2eutil" 9 "github.com/hashicorp/nomad/e2e/framework" 10 "github.com/hashicorp/nomad/helper/uuid" 11 "github.com/hashicorp/nomad/nomad/structs" 12 "github.com/hashicorp/nomad/testutil" 13 "github.com/stretchr/testify/require" 14 ) 15 16 type EventsTest struct { 17 framework.TC 18 jobIDs []string 19 } 20 21 func init() { 22 framework.AddSuites(&framework.TestSuite{ 23 Component: "Events", 24 CanRunLocal: true, 25 Cases: []framework.TestCase{ 26 new(EventsTest), 27 }, 28 }) 29 } 30 31 func (tc *EventsTest) BeforeAll(f *framework.F) { 32 e2eutil.WaitForLeader(f.T(), tc.Nomad()) 33 } 34 35 func (tc *EventsTest) AfterEach(f *framework.F) { 36 nomadClient := tc.Nomad() 37 j := nomadClient.Jobs() 38 39 for _, id := range tc.jobIDs { 40 j.Deregister(id, true, nil) 41 } 42 _, err := e2eutil.Command("nomad", "system", "gc") 43 f.NoError(err) 44 } 45 46 // TestDeploymentEvents registers a job then applies a change 47 // An event stream listening to Deployment Events asserts that 48 // a DeploymentPromotion event is emitted 49 func (tc *EventsTest) TestDeploymentEvents(f *framework.F) { 50 t := f.T() 51 52 nomadClient := tc.Nomad() 53 events := nomadClient.EventStream() 54 55 uuid := uuid.Generate() 56 jobID := fmt.Sprintf("deployment-%s", uuid[0:8]) 57 tc.jobIDs = append(tc.jobIDs, jobID) 58 ctx, cancel := context.WithCancel(context.Background()) 59 defer cancel() 60 61 topics := map[api.Topic][]string{ 62 api.TopicDeployment: {jobID}, 63 } 64 65 var deployEvents []api.Event 66 streamCh, err := events.Stream(ctx, topics, 0, nil) 67 require.NoError(t, err) 68 69 // gather deployment events 70 go func() { 71 for { 72 select { 73 case <-ctx.Done(): 74 return 75 case event := <-streamCh: 76 if event.IsHeartbeat() { 77 continue 78 } 79 80 deployEvents = append(deployEvents, event.Events...) 81 } 82 } 83 }() 84 85 // register job 86 e2eutil.RegisterAndWaitForAllocs(t, nomadClient, "events/input/initial.nomad", jobID, "") 87 88 // update job 89 e2eutil.RegisterAllocs(t, nomadClient, "events/input/deploy.nomad", jobID, "") 90 91 ds := e2eutil.DeploymentsForJob(t, nomadClient, jobID) 92 require.Equal(t, 2, len(ds)) 93 deploy := ds[0] 94 95 // wait for deployment to be running and ready for auto promote 96 e2eutil.WaitForDeployment(t, nomadClient, deploy.ID, structs.DeploymentStatusRunning, structs.DeploymentStatusDescriptionRunningAutoPromotion) 97 98 // ensure there is a deployment promotion event 99 testutil.WaitForResult(func() (bool, error) { 100 for _, e := range deployEvents { 101 if e.Type == "DeploymentPromotion" { 102 return true, nil 103 } 104 } 105 var got []string 106 for _, e := range deployEvents { 107 got = append(got, e.Type) 108 } 109 return false, fmt.Errorf("expected to receive deployment promotion event, got: %#v", got) 110 }, func(e error) { 111 f.NoError(e) 112 }) 113 } 114 115 // TestBlockedEvalEvents applies a job with a large memory requirement. The 116 // event stream checks for a failed task group alloc 117 func (tc *EventsTest) TestBlockedEvalEvents(f *framework.F) { 118 t := f.T() 119 120 nomadClient := tc.Nomad() 121 events := nomadClient.EventStream() 122 123 uuid := uuid.Generate() 124 jobID := fmt.Sprintf("blocked-deploy-%s", uuid[0:8]) 125 tc.jobIDs = append(tc.jobIDs, jobID) 126 ctx, cancel := context.WithCancel(context.Background()) 127 defer cancel() 128 129 topics := map[api.Topic][]string{ 130 api.TopicEvaluation: {"*"}, 131 } 132 133 var evalEvents []api.Event 134 streamCh, err := events.Stream(ctx, topics, 0, nil) 135 require.NoError(t, err) 136 137 // gather deployment events 138 go func() { 139 for { 140 select { 141 case <-ctx.Done(): 142 return 143 case event := <-streamCh: 144 if event.IsHeartbeat() { 145 continue 146 } 147 148 evalEvents = append(evalEvents, event.Events...) 149 } 150 } 151 }() 152 153 // register job 154 e2eutil.Register(jobID, "events/input/large-job.nomad") 155 156 // ensure there is a deployment promotion event 157 testutil.WaitForResult(func() (bool, error) { 158 for _, e := range evalEvents { 159 eval, err := e.Evaluation() 160 if err != nil { 161 return false, fmt.Errorf("event was not an evaluation %w", err) 162 } 163 164 ftg := eval.FailedTGAllocs 165 166 tg, ok := ftg["one"] 167 if !ok { 168 continue 169 } 170 171 mem := tg.DimensionExhausted["memory"] 172 require.NotNil(t, mem, "memory dimension was nil") 173 require.Greater(t, mem, 0, "memory dimension was zero") 174 return true, nil 175 176 } 177 return false, fmt.Errorf("expected blocked eval with memory exhausted, got: %#v", evalEvents) 178 }, func(e error) { 179 require.NoError(t, e) 180 }) 181 } 182 183 // TestStartIndex applies a job, then connects to the stream with a start 184 // index to verify that the events from before the job are not included. 185 func (tc *EventsTest) TestStartIndex(f *framework.F) { 186 t := f.T() 187 188 nomadClient := tc.Nomad() 189 events := nomadClient.EventStream() 190 191 uuid := uuid.Generate() 192 jobID := fmt.Sprintf("deployment-%s", uuid[0:8]) 193 jobID2 := fmt.Sprintf("deployment2-%s", uuid[0:8]) 194 tc.jobIDs = append(tc.jobIDs, jobID, jobID2) 195 ctx, cancel := context.WithCancel(context.Background()) 196 defer cancel() 197 198 // register job 199 err := e2eutil.Register(jobID, "events/input/initial.nomad") 200 require.NoError(t, err) 201 job, _, err := nomadClient.Jobs().Info(jobID, nil) 202 require.NoError(t, err) 203 startIndex := *job.JobModifyIndex + 1 204 205 topics := map[api.Topic][]string{ 206 api.TopicJob: {"*"}, 207 } 208 209 // starting at Job.ModifyIndex + 1, the next (and only) JobRegistered event that we see 210 // should be from a different job registration 211 streamCh, err := events.Stream(ctx, topics, startIndex, nil) 212 require.NoError(t, err) 213 214 var jobEvents []api.Event 215 // gather job register events 216 go func() { 217 for { 218 select { 219 case <-ctx.Done(): 220 return 221 case event, ok := <-streamCh: 222 if !ok { 223 return 224 } 225 if event.IsHeartbeat() { 226 continue 227 } 228 jobEvents = append(jobEvents, event.Events...) 229 } 230 } 231 }() 232 233 // new job (to make sure we get a JobRegistered event) 234 err = e2eutil.Register(jobID2, "events/input/deploy.nomad") 235 require.NoError(t, err) 236 237 // ensure there is a deployment promotion event 238 foundUnexpected := false 239 testutil.WaitForResult(func() (bool, error) { 240 for _, e := range jobEvents { 241 if e.Type == "JobRegistered" { 242 if e.Index <= startIndex { 243 foundUnexpected = true 244 } 245 if e.Index >= startIndex { 246 return true, nil 247 } 248 } 249 } 250 return false, fmt.Errorf("expected to receive JobRegistered event for index at least %v", startIndex) 251 }, func(e error) { 252 f.NoError(e) 253 }) 254 require.False(t, foundUnexpected, "found events from earlier-than-expected indices") 255 }