github.com/iqoqo/nomad@v0.11.3-0.20200911112621-d7021c74d101/e2e/connect/connect.go (about)

     1  package connect
     2  
     3  import (
     4  	"os"
     5  	"strings"
     6  	"time"
     7  
     8  	consulapi "github.com/hashicorp/consul/api"
     9  	"github.com/hashicorp/nomad/api"
    10  	"github.com/hashicorp/nomad/e2e/e2eutil"
    11  	"github.com/hashicorp/nomad/e2e/framework"
    12  	"github.com/hashicorp/nomad/helper/uuid"
    13  	"github.com/hashicorp/nomad/jobspec"
    14  	"github.com/kr/pretty"
    15  	"github.com/stretchr/testify/require"
    16  )
    17  
    18  type ConnectE2ETest struct {
    19  	framework.TC
    20  	jobIds []string
    21  }
    22  
    23  func init() {
    24  	// connect tests without Consul ACLs enabled
    25  	framework.AddSuites(&framework.TestSuite{
    26  		Component:   "Connect",
    27  		CanRunLocal: true,
    28  		Consul:      true,
    29  		Cases: []framework.TestCase{
    30  			new(ConnectE2ETest),
    31  			new(ConnectClientStateE2ETest),
    32  		},
    33  	})
    34  
    35  	// connect tests with Consul ACLs enabled
    36  	framework.AddSuites(&framework.TestSuite{
    37  		Component:   "ConnectACLs",
    38  		CanRunLocal: false,
    39  		Consul:      true,
    40  		Parallel:    false,
    41  		Cases: []framework.TestCase{
    42  			new(ConnectACLsE2ETest),
    43  		},
    44  	})
    45  }
    46  
    47  func (tc *ConnectE2ETest) BeforeAll(f *framework.F) {
    48  	e2eutil.WaitForLeader(f.T(), tc.Nomad())
    49  	e2eutil.WaitForNodesReady(f.T(), tc.Nomad(), 2)
    50  }
    51  
    52  func (tc *ConnectE2ETest) AfterEach(f *framework.F) {
    53  	if os.Getenv("NOMAD_TEST_SKIPCLEANUP") == "1" {
    54  		return
    55  	}
    56  
    57  	for _, id := range tc.jobIds {
    58  		tc.Nomad().Jobs().Deregister(id, true, nil)
    59  	}
    60  	tc.jobIds = []string{}
    61  	tc.Nomad().System().GarbageCollect()
    62  }
    63  
    64  // TestConnectDemo tests the demo job file from the Consul Connect Technology
    65  // Preview.
    66  //
    67  // https://github.com/hashicorp/nomad/blob/v0.9.5/website/source/guides/integrations/consul-connect/index.html.md#run-the-connect-enabled-services
    68  //
    69  func (tc *ConnectE2ETest) TestConnectDemo(f *framework.F) {
    70  	t := f.T()
    71  	uuid := uuid.Generate()
    72  	jobID := "connect" + uuid[0:8]
    73  	tc.jobIds = append(tc.jobIds, jobID)
    74  	jobapi := tc.Nomad().Jobs()
    75  
    76  	job, err := jobspec.ParseFile("connect/input/demo.nomad")
    77  	require.NoError(t, err)
    78  	job.ID = &jobID
    79  
    80  	resp, _, err := jobapi.Register(job, nil)
    81  	require.NoError(t, err)
    82  	require.NotNil(t, resp)
    83  	require.Zero(t, resp.Warnings)
    84  
    85  EVAL:
    86  	qopts := &api.QueryOptions{
    87  		WaitIndex: resp.EvalCreateIndex,
    88  	}
    89  	evalapi := tc.Nomad().Evaluations()
    90  	eval, qmeta, err := evalapi.Info(resp.EvalID, qopts)
    91  	require.NoError(t, err)
    92  	qopts.WaitIndex = qmeta.LastIndex
    93  
    94  	switch eval.Status {
    95  	case "pending":
    96  		goto EVAL
    97  	case "complete":
    98  		// Ok!
    99  	case "failed", "canceled", "blocked":
   100  		t.Fatalf("eval %s\n%s\n", eval.Status, pretty.Sprint(eval))
   101  	default:
   102  		t.Fatalf("unknown eval status: %s\n%s\n", eval.Status, pretty.Sprint(eval))
   103  	}
   104  
   105  	// Assert there were 0 placement failures
   106  	require.Zero(t, eval.FailedTGAllocs, pretty.Sprint(eval.FailedTGAllocs))
   107  	require.Len(t, eval.QueuedAllocations, 2, pretty.Sprint(eval.QueuedAllocations))
   108  
   109  	// Assert allocs are running
   110  	for i := 0; i < 20; i++ {
   111  		allocs, qmeta, err := evalapi.Allocations(eval.ID, qopts)
   112  		require.NoError(t, err)
   113  		require.Len(t, allocs, 2)
   114  		qopts.WaitIndex = qmeta.LastIndex
   115  
   116  		running := 0
   117  		for _, alloc := range allocs {
   118  			switch alloc.ClientStatus {
   119  			case "running":
   120  				running++
   121  			case "pending":
   122  				// keep trying
   123  			default:
   124  				t.Fatalf("alloc failed: %s", pretty.Sprint(alloc))
   125  			}
   126  		}
   127  
   128  		if running == len(allocs) {
   129  			break
   130  		}
   131  
   132  		time.Sleep(500 * time.Millisecond)
   133  	}
   134  
   135  	allocs, _, err := evalapi.Allocations(eval.ID, qopts)
   136  	require.NoError(t, err)
   137  	allocIDs := make(map[string]bool, 2)
   138  	for _, a := range allocs {
   139  		if a.ClientStatus != "running" || a.DesiredStatus != "run" {
   140  			t.Fatalf("alloc %s (%s) terminal; client=%s desired=%s", a.TaskGroup, a.ID, a.ClientStatus, a.DesiredStatus)
   141  		}
   142  		allocIDs[a.ID] = true
   143  	}
   144  
   145  	// Check Consul service health
   146  	agentapi := tc.Consul().Agent()
   147  
   148  	failing := map[string]*consulapi.AgentCheck{}
   149  	for i := 0; i < 60; i++ {
   150  		checks, err := agentapi.Checks()
   151  		require.NoError(t, err)
   152  
   153  		// Filter out checks for other services
   154  		for cid, check := range checks {
   155  			found := false
   156  			for allocID := range allocIDs {
   157  				if strings.Contains(check.ServiceID, allocID) {
   158  					found = true
   159  					break
   160  				}
   161  			}
   162  
   163  			if !found {
   164  				delete(checks, cid)
   165  			}
   166  		}
   167  
   168  		// Ensure checks are all passing
   169  		failing = map[string]*consulapi.AgentCheck{}
   170  		for _, check := range checks {
   171  			if check.Status != "passing" {
   172  				failing[check.CheckID] = check
   173  				break
   174  			}
   175  		}
   176  
   177  		if len(failing) == 0 {
   178  			break
   179  		}
   180  
   181  		t.Logf("still %d checks not passing", len(failing))
   182  
   183  		time.Sleep(time.Second)
   184  	}
   185  
   186  	require.Len(t, failing, 0, pretty.Sprint(failing))
   187  }