github.com/blixtra/nomad@v0.7.2-0.20171221000451-da9a1d7bb050/client/driver/raw_exec_test.go (about) 1 package driver 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "io/ioutil" 8 "path/filepath" 9 "reflect" 10 "testing" 11 "time" 12 13 "github.com/hashicorp/nomad/client/config" 14 "github.com/hashicorp/nomad/client/driver/env" 15 "github.com/hashicorp/nomad/helper/testtask" 16 "github.com/hashicorp/nomad/nomad/structs" 17 "github.com/hashicorp/nomad/testutil" 18 ) 19 20 func TestRawExecDriver_Fingerprint(t *testing.T) { 21 t.Parallel() 22 task := &structs.Task{ 23 Name: "foo", 24 Driver: "raw_exec", 25 Resources: structs.DefaultResources(), 26 } 27 ctx := testDriverContexts(t, task) 28 defer ctx.AllocDir.Destroy() 29 d := NewRawExecDriver(ctx.DriverCtx) 30 node := &structs.Node{ 31 Attributes: make(map[string]string), 32 } 33 34 // Disable raw exec. 35 cfg := &config.Config{Options: map[string]string{rawExecConfigOption: "false"}} 36 37 apply, err := d.Fingerprint(cfg, node) 38 if err != nil { 39 t.Fatalf("err: %v", err) 40 } 41 if apply { 42 t.Fatalf("should not apply") 43 } 44 if node.Attributes["driver.raw_exec"] != "" { 45 t.Fatalf("driver incorrectly enabled") 46 } 47 48 // Enable raw exec. 49 cfg.Options[rawExecConfigOption] = "true" 50 apply, err = d.Fingerprint(cfg, node) 51 if err != nil { 52 t.Fatalf("err: %v", err) 53 } 54 if !apply { 55 t.Fatalf("should apply") 56 } 57 if node.Attributes["driver.raw_exec"] != "1" { 58 t.Fatalf("driver not enabled") 59 } 60 } 61 62 func TestRawExecDriver_StartOpen_Wait(t *testing.T) { 63 t.Parallel() 64 task := &structs.Task{ 65 Name: "sleep", 66 Driver: "raw_exec", 67 Config: map[string]interface{}{ 68 "command": testtask.Path(), 69 "args": []string{"sleep", "1s"}, 70 }, 71 LogConfig: &structs.LogConfig{ 72 MaxFiles: 10, 73 MaxFileSizeMB: 10, 74 }, 75 Resources: basicResources, 76 } 77 testtask.SetTaskEnv(task) 78 ctx := testDriverContexts(t, task) 79 defer ctx.AllocDir.Destroy() 80 d := NewRawExecDriver(ctx.DriverCtx) 81 82 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 83 t.Fatalf("prestart err: %v", err) 84 } 85 resp, err := d.Start(ctx.ExecCtx, task) 86 if err != nil { 87 t.Fatalf("err: %v", err) 88 } 89 90 // Attempt to open 91 handle2, err := d.Open(ctx.ExecCtx, resp.Handle.ID()) 92 if err != nil { 93 t.Fatalf("err: %v", err) 94 } 95 if handle2 == nil { 96 t.Fatalf("missing handle") 97 } 98 99 // Task should terminate quickly 100 select { 101 case <-handle2.WaitCh(): 102 case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second): 103 t.Fatalf("timeout") 104 } 105 resp.Handle.Kill() 106 handle2.Kill() 107 } 108 109 func TestRawExecDriver_Start_Wait(t *testing.T) { 110 t.Parallel() 111 task := &structs.Task{ 112 Name: "sleep", 113 Driver: "raw_exec", 114 Config: map[string]interface{}{ 115 "command": testtask.Path(), 116 "args": []string{"sleep", "1s"}, 117 }, 118 LogConfig: &structs.LogConfig{ 119 MaxFiles: 10, 120 MaxFileSizeMB: 10, 121 }, 122 Resources: basicResources, 123 } 124 testtask.SetTaskEnv(task) 125 ctx := testDriverContexts(t, task) 126 defer ctx.AllocDir.Destroy() 127 d := NewRawExecDriver(ctx.DriverCtx) 128 129 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 130 t.Fatalf("prestart err: %v", err) 131 } 132 resp, err := d.Start(ctx.ExecCtx, task) 133 if err != nil { 134 t.Fatalf("err: %v", err) 135 } 136 137 // Update should be a no-op 138 err = resp.Handle.Update(task) 139 if err != nil { 140 t.Fatalf("err: %v", err) 141 } 142 143 // Task should terminate quickly 144 select { 145 case res := <-resp.Handle.WaitCh(): 146 if !res.Successful() { 147 t.Fatalf("err: %v", res) 148 } 149 case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second): 150 t.Fatalf("timeout") 151 } 152 } 153 154 func TestRawExecDriver_Start_Wait_AllocDir(t *testing.T) { 155 t.Parallel() 156 exp := []byte("win") 157 file := "output.txt" 158 outPath := fmt.Sprintf(`${%s}/%s`, env.AllocDir, file) 159 task := &structs.Task{ 160 Name: "sleep", 161 Driver: "raw_exec", 162 Config: map[string]interface{}{ 163 "command": testtask.Path(), 164 "args": []string{ 165 "sleep", "1s", 166 "write", string(exp), outPath, 167 }, 168 }, 169 LogConfig: &structs.LogConfig{ 170 MaxFiles: 10, 171 MaxFileSizeMB: 10, 172 }, 173 Resources: basicResources, 174 } 175 testtask.SetTaskEnv(task) 176 177 ctx := testDriverContexts(t, task) 178 defer ctx.AllocDir.Destroy() 179 d := NewRawExecDriver(ctx.DriverCtx) 180 181 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 182 t.Fatalf("prestart err: %v", err) 183 } 184 resp, err := d.Start(ctx.ExecCtx, task) 185 if err != nil { 186 t.Fatalf("err: %v", err) 187 } 188 189 // Task should terminate quickly 190 select { 191 case res := <-resp.Handle.WaitCh(): 192 if !res.Successful() { 193 t.Fatalf("err: %v", res) 194 } 195 case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second): 196 t.Fatalf("timeout") 197 } 198 199 // Check that data was written to the shared alloc directory. 200 outputFile := filepath.Join(ctx.AllocDir.SharedDir, file) 201 act, err := ioutil.ReadFile(outputFile) 202 if err != nil { 203 t.Fatalf("Couldn't read expected output: %v", err) 204 } 205 206 if !reflect.DeepEqual(act, exp) { 207 t.Fatalf("Command outputted %v; want %v", act, exp) 208 } 209 } 210 211 func TestRawExecDriver_Start_Kill_Wait(t *testing.T) { 212 t.Parallel() 213 task := &structs.Task{ 214 Name: "sleep", 215 Driver: "raw_exec", 216 Config: map[string]interface{}{ 217 "command": testtask.Path(), 218 "args": []string{"sleep", "45s"}, 219 }, 220 LogConfig: &structs.LogConfig{ 221 MaxFiles: 10, 222 MaxFileSizeMB: 10, 223 }, 224 Resources: basicResources, 225 } 226 testtask.SetTaskEnv(task) 227 228 ctx := testDriverContexts(t, task) 229 defer ctx.AllocDir.Destroy() 230 d := NewRawExecDriver(ctx.DriverCtx) 231 232 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 233 t.Fatalf("prestart err: %v", err) 234 } 235 resp, err := d.Start(ctx.ExecCtx, task) 236 if err != nil { 237 t.Fatalf("err: %v", err) 238 } 239 240 go func() { 241 time.Sleep(1 * time.Second) 242 err := resp.Handle.Kill() 243 244 // Can't rely on the ordering between wait and kill on travis... 245 if !testutil.IsTravis() && err != nil { 246 t.Fatalf("err: %v", err) 247 } 248 }() 249 250 // Task should terminate quickly 251 select { 252 case res := <-resp.Handle.WaitCh(): 253 if res.Successful() { 254 t.Fatal("should err") 255 } 256 case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second): 257 t.Fatalf("timeout") 258 } 259 } 260 261 func TestRawExecDriver_HandlerExec(t *testing.T) { 262 t.Parallel() 263 task := &structs.Task{ 264 Name: "sleep", 265 Driver: "raw_exec", 266 Config: map[string]interface{}{ 267 "command": testtask.Path(), 268 "args": []string{"sleep", "9000s"}, 269 }, 270 LogConfig: &structs.LogConfig{ 271 MaxFiles: 10, 272 MaxFileSizeMB: 10, 273 }, 274 Resources: basicResources, 275 } 276 testtask.SetTaskEnv(task) 277 ctx := testDriverContexts(t, task) 278 defer ctx.AllocDir.Destroy() 279 d := NewRawExecDriver(ctx.DriverCtx) 280 281 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 282 t.Fatalf("prestart err: %v", err) 283 } 284 resp, err := d.Start(ctx.ExecCtx, task) 285 if err != nil { 286 t.Fatalf("err: %v", err) 287 } 288 289 // Exec a command that should work 290 out, code, err := resp.Handle.Exec(context.TODO(), "/usr/bin/stat", []string{"/tmp"}) 291 if err != nil { 292 t.Fatalf("error exec'ing stat: %v", err) 293 } 294 if code != 0 { 295 t.Fatalf("expected `stat /alloc` to succeed but exit code was: %d", code) 296 } 297 if expected := 100; len(out) < expected { 298 t.Fatalf("expected at least %d bytes of output but found %d:\n%s", expected, len(out), out) 299 } 300 301 // Exec a command that should fail 302 out, code, err = resp.Handle.Exec(context.TODO(), "/usr/bin/stat", []string{"lkjhdsaflkjshowaisxmcvnlia"}) 303 if err != nil { 304 t.Fatalf("error exec'ing stat: %v", err) 305 } 306 if code == 0 { 307 t.Fatalf("expected `stat` to fail but exit code was: %d", code) 308 } 309 if expected := "No such file or directory"; !bytes.Contains(out, []byte(expected)) { 310 t.Fatalf("expected output to contain %q but found: %q", expected, out) 311 } 312 313 select { 314 case res := <-resp.Handle.WaitCh(): 315 t.Fatalf("Shouldn't be exited: %v", res.String()) 316 default: 317 } 318 319 if err := resp.Handle.Kill(); err != nil { 320 t.Fatalf("error killing exec handle: %v", err) 321 } 322 }