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