github.com/ranjib/nomad@v0.1.1-0.20160225204057-97751b02f70b/client/driver/exec_test.go (about) 1 package driver 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 "reflect" 10 "syscall" 11 "testing" 12 "time" 13 14 "github.com/hashicorp/nomad/client/config" 15 "github.com/hashicorp/nomad/client/driver/env" 16 "github.com/hashicorp/nomad/nomad/structs" 17 "github.com/hashicorp/nomad/testutil" 18 19 ctestutils "github.com/hashicorp/nomad/client/testutil" 20 ) 21 22 func TestExecDriver_Fingerprint(t *testing.T) { 23 t.Parallel() 24 ctestutils.ExecCompatible(t) 25 driverCtx, _ := testDriverContexts(&structs.Task{Name: "foo"}) 26 d := NewExecDriver(driverCtx) 27 node := &structs.Node{ 28 Attributes: map[string]string{ 29 "unique.cgroup.mountpoint": "/sys/fs/cgroup", 30 }, 31 } 32 apply, err := d.Fingerprint(&config.Config{}, node) 33 if err != nil { 34 t.Fatalf("err: %v", err) 35 } 36 if !apply { 37 t.Fatalf("should apply") 38 } 39 if node.Attributes["driver.exec"] == "" { 40 t.Fatalf("missing driver") 41 } 42 } 43 44 func TestExecDriver_StartOpen_Wait(t *testing.T) { 45 t.Parallel() 46 ctestutils.ExecCompatible(t) 47 task := &structs.Task{ 48 Name: "sleep", 49 Config: map[string]interface{}{ 50 "command": "/bin/sleep", 51 "args": []string{"5"}, 52 }, 53 LogConfig: &structs.LogConfig{ 54 MaxFiles: 10, 55 MaxFileSizeMB: 10, 56 }, 57 Resources: basicResources, 58 } 59 60 driverCtx, execCtx := testDriverContexts(task) 61 defer execCtx.AllocDir.Destroy() 62 d := NewExecDriver(driverCtx) 63 64 handle, err := d.Start(execCtx, task) 65 if err != nil { 66 t.Fatalf("err: %v", err) 67 } 68 if handle == nil { 69 t.Fatalf("missing handle") 70 } 71 72 // Attempt to open 73 handle2, err := d.Open(execCtx, handle.ID()) 74 if err != nil { 75 t.Fatalf("err: %v", err) 76 } 77 if handle2 == nil { 78 t.Fatalf("missing handle") 79 } 80 81 handle.Kill() 82 handle2.Kill() 83 } 84 85 func TestExecDriver_KillUserPid_OnPluginReconnectFailure(t *testing.T) { 86 t.Parallel() 87 ctestutils.ExecCompatible(t) 88 task := &structs.Task{ 89 Name: "sleep", 90 Config: map[string]interface{}{ 91 "command": "/bin/sleep", 92 "args": []string{"1000000"}, 93 }, 94 LogConfig: &structs.LogConfig{ 95 MaxFiles: 10, 96 MaxFileSizeMB: 10, 97 }, 98 Resources: basicResources, 99 } 100 101 driverCtx, execCtx := testDriverContexts(task) 102 defer execCtx.AllocDir.Destroy() 103 d := NewExecDriver(driverCtx) 104 105 handle, err := d.Start(execCtx, task) 106 if err != nil { 107 t.Fatalf("err: %v", err) 108 } 109 if handle == nil { 110 t.Fatalf("missing handle") 111 } 112 defer handle.Kill() 113 114 id := &execId{} 115 if err := json.Unmarshal([]byte(handle.ID()), id); err != nil { 116 t.Fatalf("Failed to parse handle '%s': %v", handle.ID(), err) 117 } 118 pluginPid := id.PluginConfig.Pid 119 proc, err := os.FindProcess(pluginPid) 120 if err != nil { 121 t.Fatalf("can't find plugin pid: %v", pluginPid) 122 } 123 if err := proc.Kill(); err != nil { 124 t.Fatalf("can't kill plugin pid: %v", err) 125 } 126 127 // Attempt to open 128 handle2, err := d.Open(execCtx, handle.ID()) 129 if err == nil { 130 t.Fatalf("expected error") 131 } 132 if handle2 != nil { 133 handle2.Kill() 134 t.Fatalf("expected handle2 to be nil") 135 } 136 // Test if the userpid is still present 137 userProc, err := os.FindProcess(id.UserPid) 138 139 err = userProc.Signal(syscall.Signal(0)) 140 141 if err == nil { 142 t.Fatalf("expected user process to die") 143 } 144 } 145 146 func TestExecDriver_Start_Wait(t *testing.T) { 147 t.Parallel() 148 ctestutils.ExecCompatible(t) 149 task := &structs.Task{ 150 Name: "sleep", 151 Config: map[string]interface{}{ 152 "command": "/bin/sleep", 153 "args": []string{"2"}, 154 }, 155 LogConfig: &structs.LogConfig{ 156 MaxFiles: 10, 157 MaxFileSizeMB: 10, 158 }, 159 Resources: basicResources, 160 } 161 162 driverCtx, execCtx := testDriverContexts(task) 163 defer execCtx.AllocDir.Destroy() 164 d := NewExecDriver(driverCtx) 165 166 handle, err := d.Start(execCtx, task) 167 if err != nil { 168 t.Fatalf("err: %v", err) 169 } 170 if handle == nil { 171 t.Fatalf("missing handle") 172 } 173 174 // Update should be a no-op 175 err = handle.Update(task) 176 if err != nil { 177 t.Fatalf("err: %v", err) 178 } 179 180 // Task should terminate quickly 181 select { 182 case res := <-handle.WaitCh(): 183 if !res.Successful() { 184 t.Fatalf("err: %v", res) 185 } 186 case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second): 187 t.Fatalf("timeout") 188 } 189 } 190 191 func TestExecDriver_Start_Artifact_basic(t *testing.T) { 192 t.Parallel() 193 ctestutils.ExecCompatible(t) 194 file := "hi_linux_amd64" 195 checksum := "sha256:6f99b4c5184726e601ecb062500aeb9537862434dfe1898dbe5c68d9f50c179c" 196 197 task := &structs.Task{ 198 Name: "sleep", 199 Config: map[string]interface{}{ 200 "artifact_source": fmt.Sprintf("https://dl.dropboxusercontent.com/u/47675/jar_thing/%s?checksum=%s", file, checksum), 201 "command": file, 202 }, 203 LogConfig: &structs.LogConfig{ 204 MaxFiles: 10, 205 MaxFileSizeMB: 10, 206 }, 207 Resources: basicResources, 208 } 209 210 driverCtx, execCtx := testDriverContexts(task) 211 defer execCtx.AllocDir.Destroy() 212 d := NewExecDriver(driverCtx) 213 214 handle, err := d.Start(execCtx, task) 215 if err != nil { 216 t.Fatalf("err: %v", err) 217 } 218 if handle == nil { 219 t.Fatalf("missing handle") 220 } 221 222 // Update should be a no-op 223 err = handle.Update(task) 224 if err != nil { 225 t.Fatalf("err: %v", err) 226 } 227 228 // Task should terminate quickly 229 select { 230 case res := <-handle.WaitCh(): 231 if !res.Successful() { 232 t.Fatalf("err: %v", res) 233 } 234 case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second): 235 t.Fatalf("timeout") 236 } 237 } 238 239 func TestExecDriver_Start_Wait_AllocDir(t *testing.T) { 240 t.Parallel() 241 ctestutils.ExecCompatible(t) 242 243 exp := []byte{'w', 'i', 'n'} 244 file := "output.txt" 245 task := &structs.Task{ 246 Name: "sleep", 247 Config: map[string]interface{}{ 248 "command": "/bin/bash", 249 "args": []string{ 250 "-c", 251 fmt.Sprintf(`sleep 1; echo -n %s > ${%s}/%s`, string(exp), env.AllocDir, file), 252 }, 253 }, 254 LogConfig: &structs.LogConfig{ 255 MaxFiles: 10, 256 MaxFileSizeMB: 10, 257 }, 258 Resources: basicResources, 259 } 260 261 driverCtx, execCtx := testDriverContexts(task) 262 defer execCtx.AllocDir.Destroy() 263 d := NewExecDriver(driverCtx) 264 265 handle, err := d.Start(execCtx, task) 266 if err != nil { 267 t.Fatalf("err: %v", err) 268 } 269 if handle == nil { 270 t.Fatalf("missing handle") 271 } 272 273 // Task should terminate quickly 274 select { 275 case res := <-handle.WaitCh(): 276 if !res.Successful() { 277 t.Fatalf("err: %v", res) 278 } 279 case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second): 280 t.Fatalf("timeout") 281 } 282 283 // Check that data was written to the shared alloc directory. 284 outputFile := filepath.Join(execCtx.AllocDir.SharedDir, file) 285 act, err := ioutil.ReadFile(outputFile) 286 if err != nil { 287 t.Fatalf("Couldn't read expected output: %v", err) 288 } 289 290 if !reflect.DeepEqual(act, exp) { 291 t.Fatalf("Command outputted %v; want %v", act, exp) 292 } 293 } 294 295 func TestExecDriver_Start_Kill_Wait(t *testing.T) { 296 t.Parallel() 297 ctestutils.ExecCompatible(t) 298 task := &structs.Task{ 299 Name: "sleep", 300 Config: map[string]interface{}{ 301 "command": "/bin/sleep", 302 "args": []string{"100"}, 303 }, 304 LogConfig: &structs.LogConfig{ 305 MaxFiles: 10, 306 MaxFileSizeMB: 10, 307 }, 308 Resources: basicResources, 309 KillTimeout: 10 * time.Second, 310 } 311 312 driverCtx, execCtx := testDriverContexts(task) 313 defer execCtx.AllocDir.Destroy() 314 d := NewExecDriver(driverCtx) 315 316 handle, err := d.Start(execCtx, task) 317 if err != nil { 318 t.Fatalf("err: %v", err) 319 } 320 if handle == nil { 321 t.Fatalf("missing handle") 322 } 323 324 go func() { 325 time.Sleep(100 * time.Millisecond) 326 err := handle.Kill() 327 if err != nil { 328 t.Fatalf("err: %v", err) 329 } 330 }() 331 332 // Task should terminate quickly 333 select { 334 case res := <-handle.WaitCh(): 335 if res.Successful() { 336 t.Fatal("should err") 337 } 338 case <-time.After(time.Duration(testutil.TestMultiplier()*10) * time.Second): 339 t.Fatalf("timeout") 340 } 341 }