github.com/masahide/goansible@v0.0.0-20160116054156-01eac649e9f2/runner.go (about) 1 package goansible 2 3 import ( 4 "fmt" 5 "sync" 6 "time" 7 ) 8 9 type RunResult struct { 10 Task *Task 11 Result *Result 12 Runtime time.Duration 13 } 14 15 type Runner struct { 16 env *Environment 17 plays []*Play 18 wait sync.WaitGroup 19 to_notify map[string]struct{} 20 //async chan *AsyncAction 21 report Reporter 22 23 Results []RunResult 24 Start time.Time 25 Runtime time.Duration 26 } 27 28 func NewRunner(env *Environment, plays []*Play) *Runner { 29 r := &Runner{ 30 env: env, 31 plays: plays, 32 to_notify: make(map[string]struct{}), 33 //async: make(chan *AsyncAction), 34 report: env.report, 35 } 36 37 //go r.handleAsync() 38 39 return r 40 } 41 42 func (r *Runner) SetReport(rep Reporter) { 43 r.report = rep 44 } 45 46 func (r *Runner) AddNotify(n string) { 47 r.to_notify[n] = struct{}{} 48 } 49 50 func (r *Runner) ShouldRunHandler(name string) bool { 51 _, ok := r.to_notify[name] 52 53 return ok 54 } 55 56 /* 57 func (r *Runner) AsyncChannel() chan *AsyncAction { 58 return r.async 59 } 60 */ 61 62 func (r *Runner) Run(env *Environment) error { 63 start := time.Now() 64 r.Start = start 65 var err error 66 67 defer func() { 68 r.Runtime = time.Since(start) 69 }() 70 71 r.report.StartTasks(r) 72 73 defer r.report.EndReporter(r, err) 74 75 for _, play := range r.plays { 76 fs := NewFutureScope(play.Vars) 77 78 for _, task := range play.Tasks { 79 err = r.runTask(env, play, task, fs, fs) 80 if err != nil { 81 return err 82 } 83 } 84 85 r.Results = append(r.Results, fs.Results()...) 86 } 87 88 r.report.FinishTasks(r) 89 90 r.wait.Wait() 91 92 StartHandlers := false 93 94 for _, play := range r.plays { 95 fs := NewFutureScope(play.Vars) 96 97 for _, task := range play.Handlers { 98 if r.ShouldRunHandler(task.Name()) { 99 if !StartHandlers { 100 r.report.StartHandlers(r) 101 StartHandlers = true 102 } 103 err := r.runTask(env, play, task, fs, fs) 104 105 if err != nil { 106 return err 107 } 108 } 109 } 110 111 fs.Wait() 112 } 113 114 if StartHandlers { 115 r.report.FinishHandlers(r) 116 } 117 r.report.FinishAll(r) 118 119 return nil 120 } 121 122 func RunAdhocTask(cmd, args string) (*Result, error) { 123 env := NewEnv(NewNestedScope(nil), &Config{}) 124 defer env.Cleanup() 125 126 task := AdhocTask(cmd, args) 127 128 str, err := ExpandTemplates(env.Vars, task.Args()) 129 if err != nil { 130 return nil, err 131 } 132 133 obj, _, err := MakeCommand(env.Vars, task, str) 134 if err != nil { 135 return nil, err 136 } 137 138 //ar := &AdhocProgress{out: os.Stdout, Start: time.Now()} 139 140 ce := &CommandEnv{Env: env, Paths: env.Paths /*progress: ar*/} 141 142 return obj.Run(ce) 143 } 144 145 func RunAdhocTaskVars(td TaskData) (*Result, error) { 146 env := NewEnv(NewNestedScope(nil), &Config{}) 147 defer env.Cleanup() 148 149 task := &Task{data: td} 150 task.Init(env) 151 152 obj, _, err := MakeCommand(env.Vars, task, "") 153 if err != nil { 154 return nil, err 155 } 156 157 //ar := &AdhocProgress{out: os.Stdout, Start: time.Now()} 158 159 ce := &CommandEnv{Env: env, Paths: env.Paths /*progress: ar*/} 160 161 return obj.Run(ce) 162 } 163 164 func RunAdhocCommand(cmd Command, debug, output bool, args string) (*Result, error) { 165 env := NewEnv(NewNestedScope(nil), &Config{ShowCommandOutput: output, Debug: debug}) 166 defer env.Cleanup() 167 168 //ar := &AdhocProgress{out: os.Stdout, Start: time.Now()} 169 170 ce := &CommandEnv{Env: env, Paths: env.Paths /*progress: ar*/} 171 172 return cmd.Run(ce) 173 } 174 175 type PriorityScope struct { 176 task Vars 177 rest Scope 178 } 179 180 func (p *PriorityScope) Get(key string) (Value, bool) { 181 if p.task != nil { 182 if v, ok := p.task[key]; ok { 183 return Any(v), true 184 } 185 } 186 187 return p.rest.Get(key) 188 } 189 190 func (p *PriorityScope) Set(key string, val interface{}) { 191 p.rest.Set(key, val) 192 } 193 194 func boolify(str string) bool { 195 switch str { 196 case "", "false", "no": 197 return false 198 default: 199 return true 200 } 201 } 202 203 type ModuleRun struct { 204 Play *Play 205 Task *Task 206 Module *Module 207 Runner *Runner 208 Scope Scope 209 FutureScope *FutureScope 210 Vars Vars 211 } 212 213 func (m *ModuleRun) Run(env *CommandEnv) (*Result, error) { 214 for _, task := range m.Module.ModTasks { 215 ns := NewNestedScope(m.Scope) 216 217 for k, v := range m.Vars { 218 ns.Set(k, v) 219 } 220 221 err := m.Runner.runTask(env.Env, m.Play, task, ns, m.FutureScope) 222 if err != nil { 223 return nil, err 224 } 225 } 226 227 return NewResult(true), nil 228 } 229 230 func (r *Runner) runTaskItems(env *Environment, play *Play, task *Task, s Scope, fs *FutureScope, start time.Time) error { 231 232 for _, item := range task.Items() { 233 ns := NewNestedScope(s) 234 ns.Set("item", item) 235 236 var res *Result 237 238 name, err := ExpandTemplates(ns, task.Name()) 239 if err != nil { 240 res = FailureResult(err) 241 r.report.StartTask(task, task.Name(), "", nil) 242 r.report.FinishTask(task, res) 243 return err 244 } 245 246 str, err := ExpandTemplates(ns, task.Args()) 247 if err != nil { 248 res = FailureResult(err) 249 r.report.StartTask(task, name, "", nil) 250 r.report.FinishTask(task, res) 251 return err 252 } 253 254 cmd, sm, err := MakeCommand(ns, task, str) 255 if err != nil { 256 res = FailureResult(err) 257 r.report.StartTask(task, name, str, nil) 258 r.report.FinishTask(task, res) 259 return err 260 } 261 262 r.report.StartTask(task, name, str, sm) 263 264 ce := NewCommandEnv(env, task) 265 266 res, err = cmd.Run(ce) 267 if err != nil && res == nil { 268 res = FailureResult(err) 269 } 270 271 if name := task.Register(); name != "" { 272 res.Data.Set("Changed", res.Changed) 273 res.Data.Set("Failed", res.Failed) 274 fs.Set(name, res) 275 } 276 277 runtime := time.Since(start) 278 279 r.Results = append(r.Results, RunResult{task, res, runtime}) 280 281 r.report.FinishTask(task, res) 282 283 if err == nil { 284 for _, x := range task.Notify() { 285 r.AddNotify(x) 286 } 287 } else { 288 return err 289 } 290 } 291 292 return nil 293 } 294 295 func (r *Runner) runTask(env *Environment, play *Play, task *Task, s Scope, fs *FutureScope) error { 296 ps := &PriorityScope{task.IncludeVars, s} 297 298 start := time.Now() 299 300 if when := task.When(); when != "" { 301 when, err := ExpandVars(ps, when) 302 303 if err != nil { 304 return err 305 } 306 307 if !boolify(when) { 308 return nil 309 } 310 } 311 312 env.Vars = s 313 if items := task.Items(); items != nil { 314 return r.runTaskItems(env, play, task, s, fs, start) 315 } 316 317 name, err := ExpandTemplates(ps, task.Name()) 318 if err != nil { 319 return err 320 } 321 322 str, err := ExpandTemplates(ps, task.Args()) 323 if err != nil { 324 return err 325 } 326 327 var cmd Command 328 329 var argVars Vars 330 331 if mod, ok := play.Modules[task.Command()]; ok { 332 sm, err := ParseSimpleMap(s, str) 333 if err != nil { 334 return err 335 } 336 337 for ik, iv := range task.Vars { 338 if str, ok := iv.Read().(string); ok { 339 exp, err := ExpandTemplates(s, str) 340 if err != nil { 341 return err 342 } 343 344 sm[ik] = Any(exp) 345 } else { 346 sm[ik] = iv 347 } 348 } 349 350 cmd = &ModuleRun{ 351 Play: play, 352 Task: task, 353 Module: mod, 354 Runner: r, 355 Scope: s, 356 FutureScope: NewFutureScope(s), 357 Vars: sm, 358 } 359 360 argVars = sm 361 } else { 362 cmd, argVars, err = MakeCommand(ps, task, str) 363 364 if err != nil { 365 return err 366 } 367 } 368 369 r.report.StartTask(task, name, str, argVars) 370 371 ce := NewCommandEnv(env, task) 372 373 if name := task.Future(); name != "" { 374 future := NewFuture(start, task, func() (*Result, error) { 375 return cmd.Run(ce) 376 }) 377 378 fs.AddFuture(name, future) 379 380 return nil 381 } 382 383 /* 384 if task.Async() { 385 asyncAction := &AsyncAction{Task: task} 386 asyncAction.Init(r) 387 388 go func() { 389 asyncAction.Finish(cmd.Run(ce)) 390 }() 391 } else { */ 392 res, err := cmd.Run(ce) 393 if err != nil && res == nil { 394 res = FailureResult(err) 395 } 396 397 if name := task.Register(); name != "" { 398 res.Data.Set("changed", fmt.Sprintf("%v", res.Changed)) 399 res.Data.Set("failed", fmt.Sprintf("%v", res.Failed)) 400 fs.Set(name, res) 401 } 402 403 runtime := time.Since(start) 404 405 r.Results = append(r.Results, RunResult{task, res, runtime}) 406 407 r.report.FinishTask(task, res) 408 409 if err == nil && res.Changed { 410 for _, x := range task.Notify() { 411 r.AddNotify(x) 412 } 413 } else { 414 return err 415 } 416 //} 417 418 return err 419 }