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