github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/status/formatted.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  	"encoding/json"
     8  	"fmt"
     9  
    10  	"gopkg.in/juju/names.v2"
    11  
    12  	"github.com/juju/juju/cmd/juju/storage"
    13  	"github.com/juju/juju/core/instance"
    14  	"github.com/juju/juju/core/status"
    15  )
    16  
    17  type formattedStatus struct {
    18  	Model              modelStatus                        `json:"model"`
    19  	Machines           map[string]machineStatus           `json:"machines"`
    20  	Applications       map[string]applicationStatus       `json:"applications"`
    21  	RemoteApplications map[string]remoteApplicationStatus `json:"application-endpoints,omitempty" yaml:"application-endpoints,omitempty"`
    22  	Offers             map[string]offerStatus             `json:"offers,omitempty" yaml:"offers,omitempty"`
    23  	Relations          []relationStatus                   `json:"-" yaml:"-"`
    24  	Storage            *storage.CombinedStorage           `json:"storage,omitempty" yaml:"storage,omitempty"`
    25  	Controller         *controllerStatus                  `json:"controller,omitempty" yaml:"controller,omitempty"`
    26  }
    27  
    28  type formattedMachineStatus struct {
    29  	Model    string                   `json:"model"`
    30  	Machines map[string]machineStatus `json:"machines"`
    31  }
    32  
    33  type errorStatus struct {
    34  	StatusError string `json:"status-error" yaml:"status-error"`
    35  }
    36  
    37  type modelStatus struct {
    38  	Name             string             `json:"name" yaml:"name"`
    39  	Type             string             `json:"type" yaml:"type"`
    40  	Controller       string             `json:"controller" yaml:"controller"`
    41  	Cloud            string             `json:"cloud" yaml:"cloud"`
    42  	CloudRegion      string             `json:"region,omitempty" yaml:"region,omitempty"`
    43  	Version          string             `json:"version" yaml:"version"`
    44  	AvailableVersion string             `json:"upgrade-available,omitempty" yaml:"upgrade-available,omitempty"`
    45  	Status           statusInfoContents `json:"model-status,omitempty" yaml:"model-status,omitempty"`
    46  	MeterStatus      *meterStatus       `json:"meter-status,omitempty" yaml:"meter-status,omitempty"`
    47  	SLA              string             `json:"sla,omitempty" yaml:"sla,omitempty"`
    48  }
    49  
    50  type controllerStatus struct {
    51  	Timestamp string `json:"timestamp,omitempty" yaml:"timestamp,omitempty"`
    52  }
    53  
    54  type networkInterface struct {
    55  	IPAddresses    []string `json:"ip-addresses" yaml:"ip-addresses"`
    56  	MACAddress     string   `json:"mac-address" yaml:"mac-address"`
    57  	Gateway        string   `json:"gateway,omitempty" yaml:"gateway,omitempty"`
    58  	DNSNameservers []string `json:"dns-nameservers,omitempty" yaml:"dns-nameservers,omitempty"`
    59  	Space          string   `json:"space,omitempty" yaml:"space,omitempty"`
    60  	IsUp           bool     `json:"is-up" yaml:"is-up"`
    61  }
    62  
    63  type machineStatus struct {
    64  	Err               error                         `json:"-" yaml:",omitempty"`
    65  	JujuStatus        statusInfoContents            `json:"juju-status,omitempty" yaml:"juju-status,omitempty"`
    66  	DNSName           string                        `json:"dns-name,omitempty" yaml:"dns-name,omitempty"`
    67  	IPAddresses       []string                      `json:"ip-addresses,omitempty" yaml:"ip-addresses,omitempty"`
    68  	InstanceId        instance.Id                   `json:"instance-id,omitempty" yaml:"instance-id,omitempty"`
    69  	DisplayName       string                        `json:"display-name,omitempty" yaml:"display-name,omitempty"`
    70  	MachineStatus     statusInfoContents            `json:"machine-status,omitempty" yaml:"machine-status,omitempty"`
    71  	Series            string                        `json:"series,omitempty" yaml:"series,omitempty"`
    72  	Id                string                        `json:"-" yaml:"-"`
    73  	NetworkInterfaces map[string]networkInterface   `json:"network-interfaces,omitempty" yaml:"network-interfaces,omitempty"`
    74  	Containers        map[string]machineStatus      `json:"containers,omitempty" yaml:"containers,omitempty"`
    75  	Constraints       string                        `json:"constraints,omitempty" yaml:"constraints,omitempty"`
    76  	Hardware          string                        `json:"hardware,omitempty" yaml:"hardware,omitempty"`
    77  	HAStatus          string                        `json:"controller-member-status,omitempty" yaml:"controller-member-status,omitempty"`
    78  	LXDProfiles       map[string]lxdProfileContents `json:"lxd-profiles,omitempty" yaml:"lxd-profiles,omitempty"`
    79  }
    80  
    81  // A goyaml bug means we can't declare these types
    82  // locally to the GetYAML methods.
    83  type machineStatusNoMarshal machineStatus
    84  
    85  func (s machineStatus) MarshalJSON() ([]byte, error) {
    86  	if s.Err != nil {
    87  		return json.Marshal(errorStatus{s.Err.Error()})
    88  	}
    89  	return json.Marshal(machineStatusNoMarshal(s))
    90  }
    91  
    92  func (s machineStatus) MarshalYAML() (interface{}, error) {
    93  	if s.Err != nil {
    94  		return errorStatus{s.Err.Error()}, nil
    95  	}
    96  	return machineStatusNoMarshal(s), nil
    97  }
    98  
    99  // machineName returns the InstanceId, unless DisplayName is set.
   100  func (s machineStatus) machineName() string {
   101  	if s.DisplayName == "" {
   102  		return string(s.InstanceId)
   103  	}
   104  	return s.DisplayName
   105  }
   106  
   107  // LXDProfile holds status info about a LXDProfile
   108  type lxdProfileContents struct {
   109  	Config      map[string]string            `json:"config" yaml:"config"`
   110  	Description string                       `json:"description" yaml:"description"`
   111  	Devices     map[string]map[string]string `json:"devices" yaml:"devices"`
   112  }
   113  
   114  type applicationStatus struct {
   115  	Err              error                 `json:"-" yaml:",omitempty"`
   116  	Charm            string                `json:"charm" yaml:"charm"`
   117  	Series           string                `json:"series"`
   118  	OS               string                `json:"os"`
   119  	CharmOrigin      string                `json:"charm-origin" yaml:"charm-origin"`
   120  	CharmName        string                `json:"charm-name" yaml:"charm-name"`
   121  	CharmRev         int                   `json:"charm-rev" yaml:"charm-rev"`
   122  	CharmVersion     string                `json:"charm-version,omitempty" yaml:"charm-version,omitempty"`
   123  	CanUpgradeTo     string                `json:"can-upgrade-to,omitempty" yaml:"can-upgrade-to,omitempty"`
   124  	Scale            int                   `json:"scale,omitempty" yaml:"scale,omitempty"`
   125  	Placement        string                `json:"placement,omitempty" yaml:"placement,omitempty"`
   126  	ProviderId       string                `json:"provider-id,omitempty" yaml:"provider-id,omitempty"`
   127  	Address          string                `json:"address,omitempty" yaml:"address,omitempty"`
   128  	Exposed          bool                  `json:"exposed" yaml:"exposed"`
   129  	Life             string                `json:"life,omitempty" yaml:"life,omitempty"`
   130  	StatusInfo       statusInfoContents    `json:"application-status,omitempty" yaml:"application-status"`
   131  	Relations        map[string][]string   `json:"relations,omitempty" yaml:"relations,omitempty"`
   132  	SubordinateTo    []string              `json:"subordinate-to,omitempty" yaml:"subordinate-to,omitempty"`
   133  	Units            map[string]unitStatus `json:"units,omitempty" yaml:"units,omitempty"`
   134  	Version          string                `json:"version,omitempty" yaml:"version,omitempty"`
   135  	EndpointBindings map[string]string     `json:"endpoint-bindings,omitempty" yaml:"endpoint-bindings,omitempty"`
   136  }
   137  
   138  type applicationStatusNoMarshal applicationStatus
   139  
   140  func (s applicationStatus) MarshalJSON() ([]byte, error) {
   141  	if s.Err != nil {
   142  		return json.Marshal(errorStatus{s.Err.Error()})
   143  	}
   144  	return json.Marshal(applicationStatusNoMarshal(s))
   145  }
   146  
   147  func (s applicationStatus) MarshalYAML() (interface{}, error) {
   148  	if s.Err != nil {
   149  		return errorStatus{s.Err.Error()}, nil
   150  	}
   151  	return applicationStatusNoMarshal(s), nil
   152  }
   153  
   154  type remoteEndpoint struct {
   155  	Name      string `json:"-" yaml:"-"`
   156  	Interface string `json:"interface" yaml:"interface"`
   157  	Role      string `json:"role" yaml:"role"`
   158  }
   159  
   160  type remoteApplicationStatus struct {
   161  	Err        error                     `json:"-" yaml:",omitempty"`
   162  	OfferURL   string                    `json:"url" yaml:"url"`
   163  	Endpoints  map[string]remoteEndpoint `json:"endpoints,omitempty" yaml:"endpoints,omitempty"`
   164  	Life       string                    `json:"life,omitempty" yaml:"life,omitempty"`
   165  	StatusInfo statusInfoContents        `json:"application-status,omitempty" yaml:"application-status"`
   166  	Relations  map[string][]string       `json:"relations,omitempty" yaml:"relations,omitempty"`
   167  }
   168  
   169  type remoteApplicationStatusNoMarshal remoteApplicationStatus
   170  
   171  func (s remoteApplicationStatus) MarshalJSON() ([]byte, error) {
   172  	if s.Err != nil {
   173  		return json.Marshal(errorStatus{s.Err.Error()})
   174  	}
   175  	return json.Marshal(remoteApplicationStatusNoMarshal(s))
   176  }
   177  
   178  func (s remoteApplicationStatus) MarshalYAML() (interface{}, error) {
   179  	if s.Err != nil {
   180  		return errorStatus{s.Err.Error()}, nil
   181  	}
   182  	return remoteApplicationStatusNoMarshal(s), nil
   183  }
   184  
   185  type offerStatusNoMarshal offerStatus
   186  
   187  type offerStatus struct {
   188  	Err                  error                     `json:"-" yaml:",omitempty"`
   189  	OfferName            string                    `json:"-" yaml:",omitempty"`
   190  	ApplicationName      string                    `json:"application" yaml:"application"`
   191  	CharmURL             string                    `json:"charm,omitempty" yaml:"charm,omitempty"`
   192  	TotalConnectedCount  int                       `json:"total-connected-count,omitempty" yaml:"total-connected-count,omitempty"`
   193  	ActiveConnectedCount int                       `json:"active-connected-count,omitempty" yaml:"active-connected-count,omitempty"`
   194  	Endpoints            map[string]remoteEndpoint `json:"endpoints" yaml:"endpoints"`
   195  }
   196  
   197  func (s offerStatus) MarshalJSON() ([]byte, error) {
   198  	if s.Err != nil {
   199  		return json.Marshal(errorStatus{s.Err.Error()})
   200  	}
   201  	return json.Marshal(offerStatusNoMarshal(s))
   202  }
   203  
   204  func (s offerStatus) MarshalYAML() (interface{}, error) {
   205  	if s.Err != nil {
   206  		return errorStatus{s.Err.Error()}, nil
   207  	}
   208  	return offerStatusNoMarshal(s), nil
   209  }
   210  
   211  type meterStatus struct {
   212  	Color   string `json:"color,omitempty" yaml:"color,omitempty"`
   213  	Message string `json:"message,omitempty" yaml:"message,omitempty"`
   214  }
   215  
   216  type unitStatus struct {
   217  	// New Juju Health Status fields.
   218  	WorkloadStatusInfo statusInfoContents `json:"workload-status,omitempty" yaml:"workload-status,omitempty"`
   219  	JujuStatusInfo     statusInfoContents `json:"juju-status,omitempty" yaml:"juju-status,omitempty"`
   220  	MeterStatus        *meterStatus       `json:"meter-status,omitempty" yaml:"meter-status,omitempty"`
   221  
   222  	Leader        bool                  `json:"leader,omitempty" yaml:"leader,omitempty"`
   223  	Charm         string                `json:"upgrading-from,omitempty" yaml:"upgrading-from,omitempty"`
   224  	Machine       string                `json:"machine,omitempty" yaml:"machine,omitempty"`
   225  	OpenedPorts   []string              `json:"open-ports,omitempty" yaml:"open-ports,omitempty"`
   226  	PublicAddress string                `json:"public-address,omitempty" yaml:"public-address,omitempty"`
   227  	Address       string                `json:"address,omitempty" yaml:"address,omitempty"`
   228  	ProviderId    string                `json:"provider-id,omitempty" yaml:"provider-id,omitempty"`
   229  	Subordinates  map[string]unitStatus `json:"subordinates,omitempty" yaml:"subordinates,omitempty"`
   230  }
   231  
   232  func (s *formattedStatus) applicationScale(name string) (string, bool) {
   233  	// The current unit count are units that are either in Idle or Executing status.
   234  	// In other words, units that are active and available.
   235  	currentUnitCount := 0
   236  	desiredUnitCount := 0
   237  
   238  	app := s.Applications[name]
   239  	match := func(u unitStatus) {
   240  		desiredUnitCount++
   241  		switch u.JujuStatusInfo.Current {
   242  		case status.Executing, status.Idle, status.Running:
   243  			currentUnitCount++
   244  		}
   245  	}
   246  	// If the app is subordinate to other units, then this is a subordinate charm.
   247  	if len(app.SubordinateTo) > 0 {
   248  		for _, a := range s.Applications {
   249  			for _, u := range a.Units {
   250  				for sub, subStatus := range u.Subordinates {
   251  					if subAppName, _ := names.UnitApplication(sub); subAppName == name {
   252  						match(subStatus)
   253  					}
   254  				}
   255  			}
   256  		}
   257  	} else {
   258  		for _, u := range app.Units {
   259  			match(u)
   260  		}
   261  	}
   262  	if s.Model.Type == "caas" {
   263  		desiredUnitCount = app.Scale
   264  	}
   265  	if currentUnitCount == desiredUnitCount {
   266  		return fmt.Sprint(currentUnitCount), false
   267  	}
   268  	return fmt.Sprintf("%d/%d", currentUnitCount, desiredUnitCount), true
   269  }
   270  
   271  type statusInfoContents struct {
   272  	Err     error         `json:"-" yaml:",omitempty"`
   273  	Current status.Status `json:"current,omitempty" yaml:"current,omitempty"`
   274  	Message string        `json:"message,omitempty" yaml:"message,omitempty"`
   275  	Since   string        `json:"since,omitempty" yaml:"since,omitempty"`
   276  	Version string        `json:"version,omitempty" yaml:"version,omitempty"`
   277  	Life    string        `json:"life,omitempty" yaml:"life,omitempty"`
   278  }
   279  
   280  type statusInfoContentsNoMarshal statusInfoContents
   281  
   282  func (s statusInfoContents) MarshalJSON() ([]byte, error) {
   283  	if s.Err != nil {
   284  		return json.Marshal(errorStatus{s.Err.Error()})
   285  	}
   286  	return json.Marshal(statusInfoContentsNoMarshal(s))
   287  }
   288  
   289  func (s statusInfoContents) MarshalYAML() (interface{}, error) {
   290  	if s.Err != nil {
   291  		return errorStatus{s.Err.Error()}, nil
   292  	}
   293  	return statusInfoContentsNoMarshal(s), nil
   294  }
   295  
   296  type unitStatusNoMarshal unitStatus
   297  
   298  func (s unitStatus) MarshalJSON() ([]byte, error) {
   299  	if s.WorkloadStatusInfo.Err != nil {
   300  		return json.Marshal(errorStatus{s.WorkloadStatusInfo.Err.Error()})
   301  	}
   302  	return json.Marshal(unitStatusNoMarshal(s))
   303  }
   304  
   305  func (s unitStatus) MarshalYAML() (interface{}, error) {
   306  	if s.WorkloadStatusInfo.Err != nil {
   307  		return errorStatus{s.WorkloadStatusInfo.Err.Error()}, nil
   308  	}
   309  	return unitStatusNoMarshal(s), nil
   310  }
   311  
   312  type relationStatus struct {
   313  	Provider  string
   314  	Requirer  string
   315  	Interface string
   316  	Type      string
   317  	Status    string
   318  	Message   string
   319  }