github.com/iqoqo/nomad@v0.11.3-0.20200911112621-d7021c74d101/client/allocrunner/groupservice_hook_test.go (about)

     1  package allocrunner
     2  
     3  import (
     4  	"io/ioutil"
     5  	"testing"
     6  	"time"
     7  
     8  	consulapi "github.com/hashicorp/consul/api"
     9  	ctestutil "github.com/hashicorp/consul/sdk/testutil"
    10  	"github.com/hashicorp/nomad/client/allocrunner/interfaces"
    11  	"github.com/hashicorp/nomad/client/consul"
    12  	"github.com/hashicorp/nomad/client/taskenv"
    13  	agentconsul "github.com/hashicorp/nomad/command/agent/consul"
    14  	"github.com/hashicorp/nomad/helper"
    15  	"github.com/hashicorp/nomad/helper/testlog"
    16  	"github.com/hashicorp/nomad/nomad/mock"
    17  	"github.com/hashicorp/nomad/nomad/structs"
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  var _ interfaces.RunnerPrerunHook = (*groupServiceHook)(nil)
    22  var _ interfaces.RunnerUpdateHook = (*groupServiceHook)(nil)
    23  var _ interfaces.RunnerPostrunHook = (*groupServiceHook)(nil)
    24  var _ interfaces.RunnerPreKillHook = (*groupServiceHook)(nil)
    25  
    26  // TestGroupServiceHook_NoGroupServices asserts calling group service hooks
    27  // without group services does not error.
    28  func TestGroupServiceHook_NoGroupServices(t *testing.T) {
    29  	t.Parallel()
    30  
    31  	alloc := mock.Alloc()
    32  	alloc.Job.TaskGroups[0].Services = []*structs.Service{{
    33  		Name:      "foo",
    34  		PortLabel: "9999",
    35  	}}
    36  	logger := testlog.HCLogger(t)
    37  	consulClient := consul.NewMockConsulServiceClient(t, logger)
    38  
    39  	h := newGroupServiceHook(groupServiceHookConfig{
    40  		alloc:          alloc,
    41  		consul:         consulClient,
    42  		restarter:      agentconsul.NoopRestarter(),
    43  		taskEnvBuilder: taskenv.NewBuilder(mock.Node(), alloc, nil, alloc.Job.Region),
    44  		logger:         logger,
    45  	})
    46  	require.NoError(t, h.Prerun())
    47  
    48  	req := &interfaces.RunnerUpdateRequest{Alloc: alloc}
    49  	require.NoError(t, h.Update(req))
    50  
    51  	require.NoError(t, h.Postrun())
    52  
    53  	ops := consulClient.GetOps()
    54  	require.Len(t, ops, 4)
    55  	require.Equal(t, "add", ops[0].Op)
    56  	require.Equal(t, "update", ops[1].Op)
    57  	require.Equal(t, "remove", ops[2].Op)
    58  }
    59  
    60  // TestGroupServiceHook_ShutdownDelayUpdate asserts calling group service hooks
    61  // update updates the hooks delay value.
    62  func TestGroupServiceHook_ShutdownDelayUpdate(t *testing.T) {
    63  	t.Parallel()
    64  
    65  	alloc := mock.Alloc()
    66  	alloc.Job.TaskGroups[0].ShutdownDelay = helper.TimeToPtr(10 * time.Second)
    67  
    68  	logger := testlog.HCLogger(t)
    69  	consulClient := consul.NewMockConsulServiceClient(t, logger)
    70  
    71  	h := newGroupServiceHook(groupServiceHookConfig{
    72  		alloc:          alloc,
    73  		consul:         consulClient,
    74  		restarter:      agentconsul.NoopRestarter(),
    75  		taskEnvBuilder: taskenv.NewBuilder(mock.Node(), alloc, nil, alloc.Job.Region),
    76  		logger:         logger,
    77  	})
    78  	require.NoError(t, h.Prerun())
    79  
    80  	// Incease shutdown Delay
    81  	alloc.Job.TaskGroups[0].ShutdownDelay = helper.TimeToPtr(15 * time.Second)
    82  	req := &interfaces.RunnerUpdateRequest{Alloc: alloc}
    83  	require.NoError(t, h.Update(req))
    84  
    85  	// Assert that update updated the delay value
    86  	require.Equal(t, h.delay, 15*time.Second)
    87  
    88  	// Remove shutdown delay
    89  	alloc.Job.TaskGroups[0].ShutdownDelay = nil
    90  	req = &interfaces.RunnerUpdateRequest{Alloc: alloc}
    91  	require.NoError(t, h.Update(req))
    92  
    93  	// Assert that update updated the delay value
    94  	require.Equal(t, h.delay, 0*time.Second)
    95  }
    96  
    97  // TestGroupServiceHook_GroupServices asserts group service hooks with group
    98  // services does not error.
    99  func TestGroupServiceHook_GroupServices(t *testing.T) {
   100  	t.Parallel()
   101  
   102  	alloc := mock.ConnectAlloc()
   103  	logger := testlog.HCLogger(t)
   104  	consulClient := consul.NewMockConsulServiceClient(t, logger)
   105  
   106  	h := newGroupServiceHook(groupServiceHookConfig{
   107  		alloc:          alloc,
   108  		consul:         consulClient,
   109  		restarter:      agentconsul.NoopRestarter(),
   110  		taskEnvBuilder: taskenv.NewBuilder(mock.Node(), alloc, nil, alloc.Job.Region),
   111  		logger:         logger,
   112  	})
   113  	require.NoError(t, h.Prerun())
   114  
   115  	req := &interfaces.RunnerUpdateRequest{Alloc: alloc}
   116  	require.NoError(t, h.Update(req))
   117  
   118  	require.NoError(t, h.Postrun())
   119  
   120  	ops := consulClient.GetOps()
   121  	require.Len(t, ops, 4)
   122  	require.Equal(t, "add", ops[0].Op)
   123  	require.Equal(t, "update", ops[1].Op)
   124  	require.Equal(t, "remove", ops[2].Op)
   125  }
   126  
   127  // TestGroupServiceHook_Error asserts group service hooks with group
   128  // services but no group network returns an error.
   129  func TestGroupServiceHook_NoNetwork(t *testing.T) {
   130  	t.Parallel()
   131  
   132  	alloc := mock.Alloc()
   133  	alloc.Job.TaskGroups[0].Networks = []*structs.NetworkResource{}
   134  	tg := alloc.Job.LookupTaskGroup(alloc.TaskGroup)
   135  	tg.Services = []*structs.Service{
   136  		{
   137  			Name:      "testconnect",
   138  			PortLabel: "9999",
   139  			Connect: &structs.ConsulConnect{
   140  				SidecarService: &structs.ConsulSidecarService{},
   141  			},
   142  		},
   143  	}
   144  	logger := testlog.HCLogger(t)
   145  
   146  	consulClient := consul.NewMockConsulServiceClient(t, logger)
   147  
   148  	h := newGroupServiceHook(groupServiceHookConfig{
   149  		alloc:          alloc,
   150  		consul:         consulClient,
   151  		restarter:      agentconsul.NoopRestarter(),
   152  		taskEnvBuilder: taskenv.NewBuilder(mock.Node(), alloc, nil, alloc.Job.Region),
   153  		logger:         logger,
   154  	})
   155  	require.NoError(t, h.Prerun())
   156  
   157  	req := &interfaces.RunnerUpdateRequest{Alloc: alloc}
   158  	require.NoError(t, h.Update(req))
   159  
   160  	require.NoError(t, h.Postrun())
   161  
   162  	ops := consulClient.GetOps()
   163  	require.Len(t, ops, 4)
   164  	require.Equal(t, "add", ops[0].Op)
   165  	require.Equal(t, "update", ops[1].Op)
   166  	require.Equal(t, "remove", ops[2].Op)
   167  }
   168  
   169  func TestGroupServiceHook_getWorkloadServices(t *testing.T) {
   170  	t.Parallel()
   171  
   172  	alloc := mock.Alloc()
   173  	alloc.Job.TaskGroups[0].Networks = []*structs.NetworkResource{}
   174  	tg := alloc.Job.LookupTaskGroup(alloc.TaskGroup)
   175  	tg.Services = []*structs.Service{
   176  		{
   177  			Name:      "testconnect",
   178  			PortLabel: "9999",
   179  			Connect: &structs.ConsulConnect{
   180  				SidecarService: &structs.ConsulSidecarService{},
   181  			},
   182  		},
   183  	}
   184  	logger := testlog.HCLogger(t)
   185  
   186  	consulClient := consul.NewMockConsulServiceClient(t, logger)
   187  
   188  	h := newGroupServiceHook(groupServiceHookConfig{
   189  		alloc:          alloc,
   190  		consul:         consulClient,
   191  		restarter:      agentconsul.NoopRestarter(),
   192  		taskEnvBuilder: taskenv.NewBuilder(mock.Node(), alloc, nil, alloc.Job.Region),
   193  		logger:         logger,
   194  	})
   195  
   196  	services := h.getWorkloadServices()
   197  	require.Len(t, services.Services, 1)
   198  }
   199  
   200  // TestGroupServiceHook_Update08Alloc asserts that adding group services to a previously
   201  // 0.8 alloc works.
   202  //
   203  // COMPAT(0.11) Only valid for upgrades from 0.8.
   204  func TestGroupServiceHook_Update08Alloc(t *testing.T) {
   205  	// Create an embedded Consul server
   206  	testconsul, err := ctestutil.NewTestServerConfig(func(c *ctestutil.TestServerConfig) {
   207  		// If -v wasn't specified squelch consul logging
   208  		if !testing.Verbose() {
   209  			c.Stdout = ioutil.Discard
   210  			c.Stderr = ioutil.Discard
   211  		}
   212  	})
   213  	if err != nil {
   214  		t.Fatalf("error starting test consul server: %v", err)
   215  	}
   216  	defer testconsul.Stop()
   217  
   218  	consulConfig := consulapi.DefaultConfig()
   219  	consulConfig.Address = testconsul.HTTPAddr
   220  	consulClient, err := consulapi.NewClient(consulConfig)
   221  	require.NoError(t, err)
   222  	serviceClient := agentconsul.NewServiceClient(consulClient.Agent(), testlog.HCLogger(t), true)
   223  
   224  	// Lower periodicInterval to ensure periodic syncing doesn't improperly
   225  	// remove Connect services.
   226  	//const interval = 50 * time.Millisecond
   227  	//serviceClient.periodicInterval = interval
   228  
   229  	// Disable deregistration probation to test syncing
   230  	//serviceClient.deregisterProbationExpiry = time.Time{}
   231  
   232  	go serviceClient.Run()
   233  	defer serviceClient.Shutdown()
   234  
   235  	// Create new 0.10-style alloc
   236  	alloc := mock.Alloc()
   237  	alloc.AllocatedResources.Shared.Networks = []*structs.NetworkResource{
   238  		{
   239  			Mode: "bridge",
   240  			IP:   "10.0.0.1",
   241  			DynamicPorts: []structs.Port{
   242  				{
   243  					Label: "connect-proxy-testconnect",
   244  					Value: 9999,
   245  					To:    9998,
   246  				},
   247  			},
   248  		},
   249  	}
   250  	tg := alloc.Job.LookupTaskGroup(alloc.TaskGroup)
   251  	tg.Services = []*structs.Service{
   252  		{
   253  			Name:      "testconnect",
   254  			PortLabel: "9999",
   255  			Connect: &structs.ConsulConnect{
   256  				SidecarService: &structs.ConsulSidecarService{
   257  					Proxy: &structs.ConsulProxy{
   258  						LocalServicePort: 9000,
   259  					},
   260  				},
   261  			},
   262  		},
   263  	}
   264  
   265  	// Create old 0.8-style alloc from new alloc
   266  	oldAlloc := alloc.Copy()
   267  	oldAlloc.AllocatedResources = nil
   268  	oldAlloc.Job.LookupTaskGroup(alloc.TaskGroup).Services = nil
   269  
   270  	// Create the group service hook
   271  	h := newGroupServiceHook(groupServiceHookConfig{
   272  		alloc:          oldAlloc,
   273  		consul:         serviceClient,
   274  		restarter:      agentconsul.NoopRestarter(),
   275  		taskEnvBuilder: taskenv.NewBuilder(mock.Node(), oldAlloc, nil, oldAlloc.Job.Region),
   276  		logger:         testlog.HCLogger(t),
   277  	})
   278  
   279  	require.NoError(t, h.Prerun())
   280  	require.NoError(t, h.Update(&interfaces.RunnerUpdateRequest{Alloc: alloc}))
   281  
   282  	// Assert the group and sidecar services are registered
   283  	require.Eventually(t, func() bool {
   284  		services, err := consulClient.Agent().Services()
   285  		require.NoError(t, err)
   286  		return len(services) == 2
   287  	}, 3*time.Second, 100*time.Millisecond)
   288  
   289  }