github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/e2e/consul/consul.go (about)

     1  package consul
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     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"
    11  	"github.com/hashicorp/nomad/helper/uuid"
    12  	"github.com/hashicorp/nomad/nomad/structs"
    13  	"github.com/hashicorp/nomad/testutil"
    14  	"github.com/stretchr/testify/require"
    15  )
    16  
    17  const (
    18  	consulJobBasic      = "consul/input/consul_example.nomad"
    19  	consulJobCanaryTags = "consul/input/canary_tags.nomad"
    20  
    21  	consulJobRegisterOnUpdatePart1 = "consul/input/services_empty.nomad"
    22  	consulJobRegisterOnUpdatePart2 = "consul/input/services_present.nomad"
    23  )
    24  
    25  type ConsulE2ETest struct {
    26  	framework.TC
    27  	jobIds []string
    28  }
    29  
    30  func init() {
    31  	framework.AddSuites(&framework.TestSuite{
    32  		Component:   "Consul",
    33  		CanRunLocal: true,
    34  		Consul:      true,
    35  		Cases: []framework.TestCase{
    36  			new(ConsulE2ETest),
    37  			new(ScriptChecksE2ETest),
    38  			new(CheckRestartE2ETest),
    39  			new(OnUpdateChecksTest),
    40  		},
    41  	})
    42  }
    43  
    44  func (tc *ConsulE2ETest) BeforeAll(f *framework.F) {
    45  	e2eutil.WaitForLeader(f.T(), tc.Nomad())
    46  	e2eutil.WaitForNodesReady(f.T(), tc.Nomad(), 1)
    47  }
    48  
    49  func (tc *ConsulE2ETest) AfterEach(f *framework.F) {
    50  	if os.Getenv("NOMAD_TEST_SKIPCLEANUP") == "1" {
    51  		return
    52  	}
    53  
    54  	for _, id := range tc.jobIds {
    55  		_, _, err := tc.Nomad().Jobs().Deregister(id, true, nil)
    56  		require.NoError(f.T(), err)
    57  	}
    58  	tc.jobIds = []string{}
    59  	require.NoError(f.T(), tc.Nomad().System().GarbageCollect())
    60  }
    61  
    62  // TestConsulRegistration asserts that a job registers services with tags in Consul.
    63  func (tc *ConsulE2ETest) TestConsulRegistration(f *framework.F) {
    64  	t := f.T()
    65  	r := require.New(t)
    66  
    67  	nomadClient := tc.Nomad()
    68  	jobId := "consul" + uuid.Short()
    69  	tc.jobIds = append(tc.jobIds, jobId)
    70  
    71  	allocations := e2eutil.RegisterAndWaitForAllocs(f.T(), nomadClient, consulJobBasic, jobId, "")
    72  	require.Equal(t, 3, len(allocations))
    73  	allocIDs := e2eutil.AllocIDsFromAllocationListStubs(allocations)
    74  	e2eutil.WaitForAllocsRunning(t, tc.Nomad(), allocIDs)
    75  
    76  	expectedTags := []string{
    77  		"cache",
    78  		"global",
    79  	}
    80  
    81  	// Assert services get registered
    82  	e2eutil.RequireConsulRegistered(r, tc.Consul(), "consul-example", 3)
    83  	services, _, err := tc.Consul().Catalog().Service("consul-example", "", nil)
    84  	require.NoError(t, err)
    85  	for _, s := range services {
    86  		// If we've made it this far the tags should *always* match
    87  		require.ElementsMatch(t, expectedTags, s.ServiceTags)
    88  	}
    89  
    90  	// Stop the job
    91  	e2eutil.WaitForJobStopped(t, nomadClient, jobId)
    92  
    93  	// Verify that services were de-registered in Consul
    94  	e2eutil.RequireConsulDeregistered(r, tc.Consul(), "consul-example")
    95  }
    96  
    97  func (tc *ConsulE2ETest) TestConsulRegisterOnUpdate(f *framework.F) {
    98  	t := f.T()
    99  	r := require.New(t)
   100  
   101  	nomadClient := tc.Nomad()
   102  	catalog := tc.Consul().Catalog()
   103  	jobID := "consul" + uuid.Short()
   104  	tc.jobIds = append(tc.jobIds, jobID)
   105  
   106  	// Initial job has no services for task.
   107  	allocations := e2eutil.RegisterAndWaitForAllocs(t, nomadClient, consulJobRegisterOnUpdatePart1, jobID, "")
   108  	require.Equal(t, 1, len(allocations))
   109  	allocIDs := e2eutil.AllocIDsFromAllocationListStubs(allocations)
   110  	e2eutil.WaitForAllocsRunning(t, tc.Nomad(), allocIDs)
   111  
   112  	// Assert service not yet registered.
   113  	results, _, err := catalog.Service("nc-service", "", nil)
   114  	require.NoError(t, err)
   115  	require.Empty(t, results)
   116  
   117  	// On update, add services for task.
   118  	allocations = e2eutil.RegisterAndWaitForAllocs(t, nomadClient, consulJobRegisterOnUpdatePart2, jobID, "")
   119  	require.Equal(t, 1, len(allocations))
   120  	allocIDs = e2eutil.AllocIDsFromAllocationListStubs(allocations)
   121  	e2eutil.WaitForAllocsRunning(t, tc.Nomad(), allocIDs)
   122  
   123  	// Assert service is now registered.
   124  	e2eutil.RequireConsulRegistered(r, tc.Consul(), "nc-service", 1)
   125  }
   126  
   127  // TestCanaryInplaceUpgrades verifies setting and unsetting canary tags
   128  func (tc *ConsulE2ETest) TestCanaryInplaceUpgrades(f *framework.F) {
   129  	t := f.T()
   130  
   131  	// TODO(shoenig) https://github.com/hashicorp/nomad/issues/9627
   132  	t.Skip("THIS TEST IS BROKEN (#9627)")
   133  
   134  	nomadClient := tc.Nomad()
   135  	consulClient := tc.Consul()
   136  	jobId := "consul" + uuid.Generate()[0:8]
   137  	tc.jobIds = append(tc.jobIds, jobId)
   138  
   139  	allocs := e2eutil.RegisterAndWaitForAllocs(f.T(), nomadClient, consulJobCanaryTags, jobId, "")
   140  	require.Equal(t, 2, len(allocs))
   141  
   142  	allocIDs := e2eutil.AllocIDsFromAllocationListStubs(allocs)
   143  	e2eutil.WaitForAllocsRunning(t, nomadClient, allocIDs)
   144  
   145  	// Start a deployment
   146  	job, _, err := nomadClient.Jobs().Info(jobId, nil)
   147  	require.NoError(t, err)
   148  	job.Meta = map[string]string{"version": "2"}
   149  	resp, _, err := nomadClient.Jobs().Register(job, nil)
   150  	require.NoError(t, err)
   151  	require.NotEmpty(t, resp.EvalID)
   152  
   153  	// Eventually have a canary
   154  	var activeDeploy *api.Deployment
   155  	testutil.WaitForResult(func() (bool, error) {
   156  		deploys, _, err := nomadClient.Jobs().Deployments(jobId, false, nil)
   157  		if err != nil {
   158  			return false, err
   159  		}
   160  		if expected := 2; len(deploys) != expected {
   161  			return false, fmt.Errorf("expected 2 deploys but found %v", deploys)
   162  		}
   163  
   164  		for _, d := range deploys {
   165  			if d.Status == structs.DeploymentStatusRunning {
   166  				activeDeploy = d
   167  				break
   168  			}
   169  		}
   170  		if activeDeploy == nil {
   171  			return false, fmt.Errorf("no running deployments: %v", deploys)
   172  		}
   173  		if expected := 1; len(activeDeploy.TaskGroups["consul_canary_test"].PlacedCanaries) != expected {
   174  			return false, fmt.Errorf("expected %d placed canaries but found %#v",
   175  				expected, activeDeploy.TaskGroups["consul_canary_test"])
   176  		}
   177  
   178  		return true, nil
   179  	}, func(err error) {
   180  		f.NoError(err, "error while waiting for deploys")
   181  	})
   182  
   183  	allocID := activeDeploy.TaskGroups["consul_canary_test"].PlacedCanaries[0]
   184  	testutil.WaitForResult(func() (bool, error) {
   185  		alloc, _, err := nomadClient.Allocations().Info(allocID, nil)
   186  		if err != nil {
   187  			return false, err
   188  		}
   189  
   190  		if alloc.DeploymentStatus == nil {
   191  			return false, fmt.Errorf("canary alloc %s has no deployment status", allocID)
   192  		}
   193  		if alloc.DeploymentStatus.Healthy == nil {
   194  			return false, fmt.Errorf("canary alloc %s has no deployment health: %#v",
   195  				allocID, alloc.DeploymentStatus)
   196  		}
   197  		return *alloc.DeploymentStatus.Healthy, fmt.Errorf("expected healthy canary but found: %#v",
   198  			alloc.DeploymentStatus)
   199  	}, func(err error) {
   200  		f.NoError(err, "error waiting for canary to be healthy")
   201  	})
   202  
   203  	// Check Consul for canary tags
   204  	testutil.WaitForResult(func() (bool, error) {
   205  		consulServices, _, err := consulClient.Catalog().Service("canarytest", "", nil)
   206  		if err != nil {
   207  			return false, err
   208  		}
   209  		for _, s := range consulServices {
   210  			if helper.CompareSliceSetString([]string{"canary", "foo"}, s.ServiceTags) {
   211  				return true, nil
   212  			}
   213  		}
   214  		return false, fmt.Errorf(`could not find service tags {"canary", "foo"}: %#v`, consulServices)
   215  	}, func(err error) {
   216  		f.NoError(err, "error waiting for canary tags")
   217  	})
   218  
   219  	// Promote canary
   220  	{
   221  		resp, _, err := nomadClient.Deployments().PromoteAll(activeDeploy.ID, nil)
   222  		require.NoError(t, err)
   223  		require.NotEmpty(t, resp.EvalID)
   224  	}
   225  
   226  	// Eventually canary is promoted
   227  	testutil.WaitForResult(func() (bool, error) {
   228  		alloc, _, err := nomadClient.Allocations().Info(allocID, nil)
   229  		if err != nil {
   230  			return false, err
   231  		}
   232  		return !alloc.DeploymentStatus.Canary, fmt.Errorf("still a canary")
   233  	}, func(err error) {
   234  		require.NoError(t, err, "error waiting for canary to be promoted")
   235  	})
   236  
   237  	// Verify that no instances have canary tags
   238  	expected := []string{"foo", "bar"}
   239  	testutil.WaitForResult(func() (bool, error) {
   240  		consulServices, _, err := consulClient.Catalog().Service("canarytest", "", nil)
   241  		if err != nil {
   242  			return false, err
   243  		}
   244  		for _, s := range consulServices {
   245  			if !helper.CompareSliceSetString(expected, s.ServiceTags) {
   246  				return false, fmt.Errorf("expected %#v Consul tags but found %#v",
   247  					expected, s.ServiceTags)
   248  			}
   249  		}
   250  		return true, nil
   251  	}, func(err error) {
   252  		require.NoError(t, err, "error waiting for non-canary tags")
   253  	})
   254  
   255  }