github.com/technosophos/deis@v1.7.1-0.20150915173815-f9005256004b/deisctl/backend/fleet/start.go (about)

     1  package fleet
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"sync"
     7  	"time"
     8  
     9  	"github.com/coreos/fleet/schema"
    10  	"github.com/deis/deis/pkg/prettyprint"
    11  )
    12  
    13  // Start units and wait for their desiredState
    14  func (c *FleetClient) Start(targets []string, wg *sync.WaitGroup, out, ew io.Writer) {
    15  	// expand @* targets
    16  	expandedTargets, err := c.expandTargets(targets)
    17  	if err != nil {
    18  		io.WriteString(ew, err.Error())
    19  		return
    20  	}
    21  
    22  	for _, target := range expandedTargets {
    23  		wg.Add(1)
    24  		go doStart(c, target, wg, out, ew)
    25  	}
    26  	return
    27  }
    28  
    29  func doStart(c *FleetClient, target string, wg *sync.WaitGroup, out, ew io.Writer) {
    30  	defer wg.Done()
    31  
    32  	// prepare string representation
    33  	component, num, err := splitTarget(target)
    34  	if err != nil {
    35  		io.WriteString(ew, err.Error())
    36  		return
    37  	}
    38  	name, err := formatUnitName(component, num)
    39  	if err != nil {
    40  		io.WriteString(ew, err.Error())
    41  		return
    42  	}
    43  
    44  	requestState := "launched"
    45  	desiredState := "running"
    46  
    47  	if err := c.Fleet.SetUnitTargetState(name, requestState); err != nil {
    48  		io.WriteString(ew, err.Error())
    49  		return
    50  	}
    51  
    52  	// start with the likely subState to avoid sending it across the channel
    53  	lastSubState := "dead"
    54  
    55  	for {
    56  		// poll for unit states
    57  		states, err := c.Fleet.UnitStates()
    58  		if err != nil {
    59  			io.WriteString(ew, err.Error())
    60  			return
    61  		}
    62  
    63  		// FIXME: fleet UnitStates API forces us to iterate for now
    64  		var currentState *schema.UnitState
    65  		for _, s := range states {
    66  			if name == s.Name {
    67  				currentState = s
    68  				break
    69  			}
    70  		}
    71  		if currentState == nil {
    72  			fmt.Fprintf(ew, "Could not find unit: %v\n", name)
    73  			return
    74  		}
    75  
    76  		// if subState changed, send it across the output channel
    77  		if lastSubState != currentState.SystemdSubState {
    78  			l := prettyprint.Overwritef(stateFmt, name, currentState.SystemdActiveState, currentState.SystemdSubState)
    79  			fmt.Fprintf(out, l)
    80  		}
    81  
    82  		// break when desired state is reached
    83  		if currentState.SystemdSubState == desiredState {
    84  			fmt.Fprintln(out)
    85  			return
    86  		}
    87  
    88  		lastSubState = currentState.SystemdSubState
    89  
    90  		if lastSubState == "failed" {
    91  			o := prettyprint.Colorize("{{.Red}}The service '%s' failed while starting.{{.Default}}\n")
    92  			fmt.Fprintf(ew, o, target)
    93  			return
    94  		}
    95  		time.Sleep(250 * time.Millisecond)
    96  	}
    97  }