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  }