github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/builder/lxc/step_wait_init.go (about) 1 package lxc 2 3 import ( 4 "errors" 5 "fmt" 6 "github.com/hashicorp/packer/packer" 7 "github.com/mitchellh/multistep" 8 "log" 9 "strings" 10 "time" 11 ) 12 13 type StepWaitInit struct { 14 WaitTimeout time.Duration 15 } 16 17 func (s *StepWaitInit) Run(state multistep.StateBag) multistep.StepAction { 18 ui := state.Get("ui").(packer.Ui) 19 20 var err error 21 22 cancel := make(chan struct{}) 23 waitDone := make(chan bool, 1) 24 go func() { 25 ui.Say("Waiting for container to finish init...") 26 err = s.waitForInit(state, cancel) 27 waitDone <- true 28 }() 29 30 log.Printf("Waiting for container to finish init, up to timeout: %s", s.WaitTimeout) 31 timeout := time.After(s.WaitTimeout) 32 WaitLoop: 33 for { 34 select { 35 case <-waitDone: 36 if err != nil { 37 ui.Error(fmt.Sprintf("Error waiting for container to finish init: %s", err)) 38 return multistep.ActionHalt 39 } 40 41 ui.Say("Container finished init!") 42 break WaitLoop 43 case <-timeout: 44 err := fmt.Errorf("Timeout waiting for container to finish init.") 45 state.Put("error", err) 46 ui.Error(err.Error()) 47 close(cancel) 48 return multistep.ActionHalt 49 case <-time.After(1 * time.Second): 50 if _, ok := state.GetOk(multistep.StateCancelled); ok { 51 close(cancel) 52 log.Println("Interrupt detected, quitting waiting for container to finish init.") 53 return multistep.ActionHalt 54 } 55 } 56 } 57 58 return multistep.ActionContinue 59 } 60 61 func (s *StepWaitInit) Cleanup(multistep.StateBag) { 62 } 63 64 func (s *StepWaitInit) waitForInit(state multistep.StateBag, cancel <-chan struct{}) error { 65 config := state.Get("config").(*Config) 66 mountPath := state.Get("mount_path").(string) 67 wrappedCommand := state.Get("wrappedCommand").(CommandWrapper) 68 69 for { 70 select { 71 case <-cancel: 72 log.Println("Cancelled. Exiting loop.") 73 return errors.New("Wait cancelled") 74 case <-time.After(1 * time.Second): 75 } 76 77 comm := &LxcAttachCommunicator{ 78 ContainerName: config.ContainerName, 79 RootFs: mountPath, 80 CmdWrapper: wrappedCommand, 81 } 82 83 runlevel, _ := comm.CheckInit() 84 currentRunlevel := "unknown" 85 if arr := strings.Split(runlevel, " "); len(arr) >= 2 { 86 currentRunlevel = arr[1] 87 } 88 89 log.Printf("Current runlevel in container: '%s'", runlevel) 90 91 targetRunlevel := fmt.Sprintf("%d", config.TargetRunlevel) 92 if currentRunlevel == targetRunlevel { 93 log.Printf("Container finished init.") 94 break 95 } else if currentRunlevel > targetRunlevel { 96 log.Printf("Expected Runlevel %s, Got Runlevel %s, continuing", targetRunlevel, currentRunlevel) 97 break 98 } 99 } 100 101 return nil 102 }