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 }