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