github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/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/envcmd" 17 "github.com/juju/juju/cmd/juju/common" 18 "github.com/juju/juju/juju/osenv" 19 ) 20 21 type StatusHistoryCommand struct { 22 envcmd.EnvCommandBase 23 out cmd.Output 24 outputContent string 25 backlogSize int 26 isoTime bool 27 unitName string 28 } 29 30 var statusHistoryDoc = ` 31 This command will report the history of status changes for 32 a given unit. 33 The statuses for the unit workload and/or agent are available. 34 -type supports: 35 agent: will show statuses for the unit's agent 36 workload: will show statuses for the unit's workload 37 combined: will show agent and workload statuses combined 38 and sorted by time of occurrence. 39 ` 40 41 func (c *StatusHistoryCommand) Info() *cmd.Info { 42 return &cmd.Info{ 43 Name: "status-history", 44 Args: "[-n N] <unit>", 45 Purpose: "output past statuses for a unit", 46 Doc: statusHistoryDoc, 47 } 48 } 49 50 func (c *StatusHistoryCommand) SetFlags(f *gnuflag.FlagSet) { 51 f.StringVar(&c.outputContent, "type", "combined", "type of statuses to be displayed [agent|workload|combined].") 52 f.IntVar(&c.backlogSize, "n", 20, "size of logs backlog.") 53 f.BoolVar(&c.isoTime, "utc", false, "display time as UTC in RFC3339 format") 54 } 55 56 func (c *StatusHistoryCommand) Init(args []string) error { 57 switch { 58 case len(args) > 1: 59 return errors.Errorf("unexpected arguments after unit name.") 60 case len(args) == 0: 61 return errors.Errorf("unit name is missing.") 62 default: 63 c.unitName = args[0] 64 } 65 // If use of ISO time not specified on command line, 66 // check env var. 67 if !c.isoTime { 68 var err error 69 envVarValue := os.Getenv(osenv.JujuStatusIsoTimeEnvKey) 70 if envVarValue != "" { 71 if c.isoTime, err = strconv.ParseBool(envVarValue); err != nil { 72 return errors.Annotatef(err, "invalid %s env var, expected true|false", osenv.JujuStatusIsoTimeEnvKey) 73 } 74 } 75 } 76 kind := params.HistoryKind(c.outputContent) 77 switch kind { 78 case params.KindCombined, params.KindAgent, params.KindWorkload: 79 return nil 80 81 } 82 return errors.Errorf("unexpected status type %q", c.outputContent) 83 } 84 85 func (c *StatusHistoryCommand) Run(ctx *cmd.Context) error { 86 apiclient, err := c.NewAPIClient() 87 if err != nil { 88 return fmt.Errorf(connectionError, c.ConnectionName(), err) 89 } 90 defer apiclient.Close() 91 var statuses *params.UnitStatusHistory 92 kind := params.HistoryKind(c.outputContent) 93 statuses, err = apiclient.UnitStatusHistory(kind, c.unitName, c.backlogSize) 94 if err != nil { 95 if len(statuses.Statuses) == 0 { 96 return errors.Trace(err) 97 } 98 // Display any error, but continue to print status if some was returned 99 fmt.Fprintf(ctx.Stderr, "%v\n", err) 100 } else if len(statuses.Statuses) == 0 { 101 return errors.Errorf("no status history available") 102 } 103 table := [][]string{{"TIME", "TYPE", "STATUS", "MESSAGE"}} 104 lengths := []int{1, 1, 1, 1} 105 for _, v := range statuses.Statuses { 106 fields := []string{common.FormatTime(v.Since, c.isoTime), string(v.Kind), string(v.Status), v.Info} 107 for k, v := range fields { 108 if len(v) > lengths[k] { 109 lengths[k] = len(v) 110 } 111 } 112 table = append(table, fields) 113 } 114 f := fmt.Sprintf("%%-%ds\t%%-%ds\t%%-%ds\t%%-%ds\n", lengths[0], lengths[1], lengths[2], lengths[3]) 115 for _, v := range table { 116 fmt.Printf(f, v[0], v[1], v[2], v[3]) 117 } 118 return nil 119 }