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  }