github.com/bigcommerce/nomad@v0.9.3-bc/e2e/consul/consul.go (about) 1 package consul 2 3 import ( 4 "time" 5 6 "github.com/hashicorp/nomad/api" 7 "github.com/hashicorp/nomad/e2e/e2eutil" 8 "github.com/hashicorp/nomad/e2e/framework" 9 "github.com/hashicorp/nomad/helper/uuid" 10 . "github.com/onsi/gomega" 11 "github.com/stretchr/testify/require" 12 ) 13 14 type ConsulE2ETest struct { 15 framework.TC 16 jobIds []string 17 } 18 19 func init() { 20 framework.AddSuites(&framework.TestSuite{ 21 Component: "Consul", 22 CanRunLocal: true, 23 Consul: true, 24 Cases: []framework.TestCase{ 25 new(ConsulE2ETest), 26 }, 27 }) 28 } 29 30 func (tc *ConsulE2ETest) BeforeAll(f *framework.F) { 31 // Ensure cluster has leader before running tests 32 e2eutil.WaitForLeader(f.T(), tc.Nomad()) 33 // Ensure that we have four client nodes in ready state 34 e2eutil.WaitForNodesReady(f.T(), tc.Nomad(), 1) 35 } 36 37 type serviceNameTagPair struct { 38 serviceName string 39 tags map[string]struct{} 40 } 41 42 // This test runs a job that registers in Consul with specific tags 43 func (tc *ConsulE2ETest) TestConsulRegistration(f *framework.F) { 44 nomadClient := tc.Nomad() 45 uuid := uuid.Generate() 46 jobId := "consul" + uuid[0:8] 47 tc.jobIds = append(tc.jobIds, jobId) 48 49 allocs := e2eutil.RegisterAndWaitForAllocs(f.T(), nomadClient, "consul/input/consul_example.nomad", jobId) 50 consulClient := tc.Consul() 51 require := require.New(f.T()) 52 require.Equal(3, len(allocs)) 53 54 // Query consul catalog for service 55 catalog := consulClient.Catalog() 56 g := NewGomegaWithT(f.T()) 57 58 expectedTags := map[string]struct{}{} 59 expectedTags["global"] = struct{}{} 60 expectedTags["cache"] = struct{}{} 61 62 g.Eventually(func() []serviceNameTagPair { 63 consulService, _, err := catalog.Service("redis-cache", "", nil) 64 require.Nil(err) 65 var serviceInfo []serviceNameTagPair 66 for _, serviceInstance := range consulService { 67 tags := map[string]struct{}{} 68 for _, tag := range serviceInstance.ServiceTags { 69 tags[tag] = struct{}{} 70 } 71 serviceInfo = append(serviceInfo, serviceNameTagPair{serviceInstance.ServiceName, tags}) 72 } 73 return serviceInfo 74 }, 5*time.Second, time.Second).Should(ConsistOf([]serviceNameTagPair{ 75 {"redis-cache", expectedTags}, 76 {"redis-cache", expectedTags}, 77 {"redis-cache", expectedTags}, 78 })) 79 80 jobs := nomadClient.Jobs() 81 // Stop all jobs in test 82 for _, id := range tc.jobIds { 83 jobs.Deregister(id, true, nil) 84 } 85 // Garbage collect 86 nomadClient.System().GarbageCollect() 87 88 // Verify that services were deregistered in Consul 89 g.Eventually(func() []string { 90 consulService, _, err := catalog.Service("redis-cache", "", nil) 91 require.Nil(err) 92 var serviceIDs []string 93 for _, serviceInstance := range consulService { 94 serviceIDs = append(serviceIDs, serviceInstance.ServiceID) 95 } 96 return serviceIDs 97 }, 5*time.Second, time.Second).Should(BeEmpty()) 98 } 99 100 // This test verifies setting and unsetting canary tags 101 func (tc *ConsulE2ETest) TestCanaryInplaceUpgrades(f *framework.F) { 102 nomadClient := tc.Nomad() 103 uuid := uuid.Generate() 104 jobId := "consul" + uuid[0:8] 105 tc.jobIds = append(tc.jobIds, jobId) 106 107 allocs := e2eutil.RegisterAndWaitForAllocs(f.T(), nomadClient, "consul/input/canary_tags.nomad", jobId) 108 consulClient := tc.Consul() 109 require := require.New(f.T()) 110 require.Equal(2, len(allocs)) 111 112 jobs := nomadClient.Jobs() 113 g := NewGomegaWithT(f.T()) 114 115 g.Eventually(func() []string { 116 deploys, _, err := jobs.Deployments(jobId, false, nil) 117 require.Nil(err) 118 healthyDeploys := make([]string, 0, len(deploys)) 119 for _, d := range deploys { 120 if d.Status == "successful" { 121 healthyDeploys = append(healthyDeploys, d.ID) 122 } 123 } 124 return healthyDeploys 125 }, 5*time.Second, 20*time.Millisecond).Should(HaveLen(1)) 126 127 // Start a deployment 128 job, _, err := jobs.Info(jobId, nil) 129 require.Nil(err) 130 job.Meta = map[string]string{"version": "2"} 131 resp, _, err := jobs.Register(job, nil) 132 require.Nil(err) 133 require.NotEmpty(resp.EvalID) 134 135 // Eventually have a canary 136 var deploys []*api.Deployment 137 g.Eventually(func() []*api.Deployment { 138 deploys, _, err = jobs.Deployments(*job.ID, false, nil) 139 require.Nil(err) 140 return deploys 141 }, 2*time.Second, 20*time.Millisecond).Should(HaveLen(2)) 142 143 deployments := nomadClient.Deployments() 144 var deploy *api.Deployment 145 g.Eventually(func() []string { 146 deploy, _, err = deployments.Info(deploys[0].ID, nil) 147 require.Nil(err) 148 return deploy.TaskGroups["consul_canary_test"].PlacedCanaries 149 }, 2*time.Second, 20*time.Millisecond).Should(HaveLen(1)) 150 151 allocations := nomadClient.Allocations() 152 g.Eventually(func() bool { 153 allocID := deploy.TaskGroups["consul_canary_test"].PlacedCanaries[0] 154 alloc, _, err := allocations.Info(allocID, nil) 155 require.Nil(err) 156 return alloc.DeploymentStatus != nil && alloc.DeploymentStatus.Healthy != nil && *alloc.DeploymentStatus.Healthy 157 }, 3*time.Second, 20*time.Millisecond).Should(BeTrue()) 158 159 // Query consul catalog for service 160 catalog := consulClient.Catalog() 161 // Check Consul for canary tags 162 g.Eventually(func() []string { 163 consulServices, _, err := catalog.Service("canarytest", "", nil) 164 require.Nil(err) 165 166 for _, serviceInstance := range consulServices { 167 for _, tag := range serviceInstance.ServiceTags { 168 if tag == "canary" { 169 return serviceInstance.ServiceTags 170 } 171 } 172 } 173 174 return nil 175 }, 2*time.Second, 20*time.Millisecond).Should( 176 Equal([]string{"foo", "canary"})) 177 178 // Manually promote 179 { 180 resp, _, err := deployments.PromoteAll(deploys[0].ID, nil) 181 require.Nil(err) 182 require.NotEmpty(resp.EvalID) 183 } 184 185 // Eventually canary is removed 186 g.Eventually(func() bool { 187 allocID := deploy.TaskGroups["consul_canary_test"].PlacedCanaries[0] 188 alloc, _, err := allocations.Info(allocID, nil) 189 require.Nil(err) 190 return alloc.DeploymentStatus.Canary 191 }, 2*time.Second, 20*time.Millisecond).Should(BeFalse()) 192 193 // Verify that no instances have canary tags 194 expectedTags := map[string]struct{}{} 195 expectedTags["foo"] = struct{}{} 196 expectedTags["bar"] = struct{}{} 197 198 g.Eventually(func() []serviceNameTagPair { 199 consulServices, _, err := catalog.Service("canarytest", "", nil) 200 require.Nil(err) 201 var serviceInfo []serviceNameTagPair 202 for _, serviceInstance := range consulServices { 203 tags := map[string]struct{}{} 204 for _, tag := range serviceInstance.ServiceTags { 205 tags[tag] = struct{}{} 206 } 207 serviceInfo = append(serviceInfo, serviceNameTagPair{serviceInstance.ServiceName, tags}) 208 } 209 return serviceInfo 210 }, 3*time.Second, 20*time.Millisecond).Should(ConsistOf([]serviceNameTagPair{ 211 {"canarytest", expectedTags}, 212 {"canarytest", expectedTags}, 213 })) 214 215 } 216 217 func (tc *ConsulE2ETest) AfterEach(f *framework.F) { 218 nomadClient := tc.Nomad() 219 jobs := nomadClient.Jobs() 220 // Stop all jobs in test 221 for _, id := range tc.jobIds { 222 jobs.Deregister(id, true, nil) 223 } 224 // Garbage collect 225 nomadClient.System().GarbageCollect() 226 }