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