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  }