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