github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/cmd/juju/status/history.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package status
     5  
     6  import (
     7  	"fmt"
     8  	"os"
     9  	"strconv"
    10  
    11  	"github.com/juju/cmd"
    12  	"github.com/juju/errors"
    13  	"launchpad.net/gnuflag"
    14  
    15  	"github.com/juju/juju/apiserver/params"
    16  	"github.com/juju/juju/cmd/juju/common"
    17  	"github.com/juju/juju/cmd/modelcmd"
    18  	"github.com/juju/juju/juju/osenv"
    19  )
    20  
    21  // NewStatusHistoryCommand returns a command that reports the history
    22  // of status changes for the specified unit.
    23  func NewStatusHistoryCommand() cmd.Command {
    24  	return modelcmd.Wrap(&statusHistoryCommand{})
    25  }
    26  
    27  type statusHistoryCommand struct {
    28  	modelcmd.ModelCommandBase
    29  	out           cmd.Output
    30  	outputContent string
    31  	backlogSize   int
    32  	isoTime       bool
    33  	unitName      string
    34  }
    35  
    36  var statusHistoryDoc = `
    37  This command will report the history of status changes for
    38  a given entity.
    39  The statuses are available for the following types.
    40  -type supports:
    41      juju-unit: will show statuses for the unit's juju agent.
    42      workload: will show statuses for the unit's workload.
    43      unit: will show workload and juju agent combined for the specified unit.
    44      juju-machine: will show statuses for machine's juju agent.
    45      machine: will show statuses for machines.
    46      juju-container: will show statuses for the container's juju agent.
    47      container: will show statuses for containers.
    48   and sorted by time of occurrence.
    49   The default is unit.
    50  `
    51  
    52  func (c *statusHistoryCommand) Info() *cmd.Info {
    53  	return &cmd.Info{
    54  		Name:    "status-history",
    55  		Args:    "[-n N] [--type T] [--utc] <entity name>",
    56  		Purpose: "output past statuses for the passed entity",
    57  		Doc:     statusHistoryDoc,
    58  	}
    59  }
    60  
    61  func (c *statusHistoryCommand) SetFlags(f *gnuflag.FlagSet) {
    62  	f.StringVar(&c.outputContent, "type", "unit", "type of statuses to be displayed [agent|workload|combined|machine|machineInstance|container|containerinstance].")
    63  	f.IntVar(&c.backlogSize, "n", 20, "size of logs backlog.")
    64  	f.BoolVar(&c.isoTime, "utc", false, "display time as UTC in RFC3339 format")
    65  }
    66  
    67  func (c *statusHistoryCommand) Init(args []string) error {
    68  	switch {
    69  	case len(args) > 1:
    70  		return errors.Errorf("unexpected arguments after entity name.")
    71  	case len(args) == 0:
    72  		return errors.Errorf("entity name is missing.")
    73  	default:
    74  		c.unitName = args[0]
    75  	}
    76  	// If use of ISO time not specified on command line,
    77  	// check env var.
    78  	if !c.isoTime {
    79  		var err error
    80  		envVarValue := os.Getenv(osenv.JujuStatusIsoTimeEnvKey)
    81  		if envVarValue != "" {
    82  			if c.isoTime, err = strconv.ParseBool(envVarValue); err != nil {
    83  				return errors.Annotatef(err, "invalid %s env var, expected true|false", osenv.JujuStatusIsoTimeEnvKey)
    84  			}
    85  		}
    86  	}
    87  	kind := params.HistoryKind(c.outputContent)
    88  	switch kind {
    89  	case params.KindUnit, params.KindUnitAgent, params.KindWorkload,
    90  		params.KindMachineInstance, params.KindMachine, params.KindContainer,
    91  		params.KindContainerInstance:
    92  		return nil
    93  	}
    94  	return errors.Errorf("unexpected status type %q", c.outputContent)
    95  }
    96  
    97  func (c *statusHistoryCommand) Run(ctx *cmd.Context) error {
    98  	apiclient, err := c.NewAPIClient()
    99  	if err != nil {
   100  		return errors.Trace(err)
   101  	}
   102  	defer apiclient.Close()
   103  	var statuses *params.StatusHistoryResults
   104  	kind := params.HistoryKind(c.outputContent)
   105  	statuses, err = apiclient.StatusHistory(kind, c.unitName, c.backlogSize)
   106  	if err != nil {
   107  		if len(statuses.Statuses) == 0 {
   108  			return errors.Trace(err)
   109  		}
   110  		// Display any error, but continue to print status if some was returned
   111  		fmt.Fprintf(ctx.Stderr, "%v\n", err)
   112  	} else if len(statuses.Statuses) == 0 {
   113  		return errors.Errorf("no status history available")
   114  	}
   115  	table := [][]string{{"TIME", "TYPE", "STATUS", "MESSAGE"}}
   116  	lengths := []int{1, 1, 1, 1}
   117  	for _, v := range statuses.Statuses {
   118  		fields := []string{common.FormatTime(v.Since, c.isoTime), string(v.Kind), string(v.Status), v.Info}
   119  		for k, v := range fields {
   120  			if len(v) > lengths[k] {
   121  				lengths[k] = len(v)
   122  			}
   123  		}
   124  		table = append(table, fields)
   125  	}
   126  	f := fmt.Sprintf("%%-%ds\t%%-%ds\t%%-%ds\t%%-%ds\n", lengths[0], lengths[1], lengths[2], lengths[3])
   127  	for _, v := range table {
   128  		fmt.Printf(f, v[0], v[1], v[2], v[3])
   129  	}
   130  	return nil
   131  }