Left: | ||
Right: |
OLD | NEW |
---|---|
1 package main | 1 package main |
2 | 2 |
3 import ( | 3 import ( |
4 "encoding/json" | |
4 "fmt" | 5 "fmt" |
5 | |
6 "launchpad.net/gnuflag" | 6 "launchpad.net/gnuflag" |
7 "launchpad.net/juju-core/charm" | |
7 "launchpad.net/juju-core/cmd" | 8 "launchpad.net/juju-core/cmd" |
8 "launchpad.net/juju-core/environs" | 9 "launchpad.net/juju-core/environs" |
9 "launchpad.net/juju-core/juju" | 10 "launchpad.net/juju-core/juju" |
10 "launchpad.net/juju-core/state" | 11 "launchpad.net/juju-core/state" |
11 "launchpad.net/juju-core/state/api/params" | 12 "launchpad.net/juju-core/state/api/params" |
12 "launchpad.net/juju-core/utils/set" | 13 "launchpad.net/juju-core/utils/set" |
14 "strings" | |
13 ) | 15 ) |
14 | 16 |
15 type statusMap map[string]interface{} | |
16 | |
17 type StatusCommand struct { | 17 type StatusCommand struct { |
18 EnvCommandBase | 18 EnvCommandBase |
19 out cmd.Output | 19 out cmd.Output |
20 } | 20 } |
21 | 21 |
22 var statusDoc = "This command will report on the runtime state of various system entities." | 22 var statusDoc = "This command will report on the runtime state of various system entities." |
23 | 23 |
24 func (c *StatusCommand) Info() *cmd.Info { | 24 func (c *StatusCommand) Info() *cmd.Info { |
25 return &cmd.Info{ | 25 return &cmd.Info{ |
26 Name: "status", | 26 Name: "status", |
27 Purpose: "output status information about an environment", | 27 Purpose: "output status information about an environment", |
28 Doc: statusDoc, | 28 Doc: statusDoc, |
29 Aliases: []string{"stat"}, | 29 Aliases: []string{"stat"}, |
30 } | 30 } |
31 } | 31 } |
32 | 32 |
33 func (c *StatusCommand) SetFlags(f *gnuflag.FlagSet) { | 33 func (c *StatusCommand) SetFlags(f *gnuflag.FlagSet) { |
34 c.EnvCommandBase.SetFlags(f) | 34 c.EnvCommandBase.SetFlags(f) |
35 c.out.AddFlags(f, "yaml", map[string]cmd.Formatter{ | 35 c.out.AddFlags(f, "yaml", map[string]cmd.Formatter{ |
36 "yaml": cmd.FormatYaml, | 36 "yaml": cmd.FormatYaml, |
37 "json": cmd.FormatJson, | 37 "json": cmd.FormatJson, |
38 }) | 38 }) |
39 } | 39 } |
40 | 40 |
41 type statusContext struct { | |
42 instances map[state.InstanceId]environs.Instance | |
43 machines map[string]*state.Machine | |
44 services map[string]*state.Service | |
45 units map[string]map[string]*state.Unit | |
46 } | |
47 | |
41 func (c *StatusCommand) Run(ctx *cmd.Context) error { | 48 func (c *StatusCommand) Run(ctx *cmd.Context) error { |
42 conn, err := juju.NewConnFromName(c.EnvName) | 49 conn, err := juju.NewConnFromName(c.EnvName) |
43 if err != nil { | 50 if err != nil { |
44 return err | 51 return err |
45 } | 52 } |
46 defer conn.Close() | 53 defer conn.Close() |
47 | 54 |
48 » instances, err := fetchAllInstances(conn.Environ) | 55 » var ctxt statusContext |
49 » if err != nil { | 56 » if ctxt.instances, err = fetchAllInstances(conn.Environ); err != nil { |
50 return err | 57 return err |
51 } | 58 } |
52 | 59 » if ctxt.machines, err = fetchAllMachines(conn.State); err != nil { |
53 » machines, err := fetchAllMachines(conn.State) | |
54 » if err != nil { | |
55 return err | 60 return err |
56 } | 61 } |
57 | 62 » if ctxt.services, ctxt.units, err = fetchAllServicesAndUnits(conn.State) ; err != nil { |
58 » services, err := fetchAllServices(conn.State) | |
59 » if err != nil { | |
60 return err | 63 return err |
61 } | 64 } |
62 | 65 » result := struct { |
63 » result := map[string]interface{}{ | 66 » » Machines map[string]machineStatus `json:"machines"` |
64 » » "machines": checkError(processMachines(machines, instances)), | 67 » » Services map[string]serviceStatus `json:"services"` |
65 » » "services": checkError(processServices(services)), | 68 » }{ |
69 » » Machines: ctxt.processMachines(), | |
70 » » Services: ctxt.processServices(), | |
66 } | 71 } |
67 | |
68 return c.out.Write(ctx, result) | 72 return c.out.Write(ctx, result) |
69 } | 73 } |
70 | 74 |
71 // fetchAllInstances returns a map[string]environs.Instance representing | 75 // fetchAllInstances returns a map from instance id to instance. |
72 // a mapping of instance ids to their respective instance. | |
73 func fetchAllInstances(env environs.Environ) (map[state.InstanceId]environs.Inst ance, error) { | 76 func fetchAllInstances(env environs.Environ) (map[state.InstanceId]environs.Inst ance, error) { |
74 m := make(map[state.InstanceId]environs.Instance) | 77 m := make(map[state.InstanceId]environs.Instance) |
75 insts, err := env.AllInstances() | 78 insts, err := env.AllInstances() |
fwereade
2013/04/17 22:04:08
Zero instances is "sane" given eventual consistenc
rog
2013/04/17 22:31:45
Done.
| |
76 if err != nil { | 79 if err != nil { |
77 return nil, err | 80 return nil, err |
78 } | 81 } |
79 for _, i := range insts { | 82 for _, i := range insts { |
80 m[i.Id()] = i | 83 m[i.Id()] = i |
81 } | 84 } |
82 return m, nil | 85 return m, nil |
83 } | 86 } |
84 | 87 |
85 // fetchAllMachines returns a map[string]*state.Machine representing | 88 // fetchAllMachines returns a map from machine id to machine. |
86 // a mapping of machine ids to machines. | |
87 func fetchAllMachines(st *state.State) (map[string]*state.Machine, error) { | 89 func fetchAllMachines(st *state.State) (map[string]*state.Machine, error) { |
88 v := make(map[string]*state.Machine) | 90 v := make(map[string]*state.Machine) |
89 machines, err := st.AllMachines() | 91 machines, err := st.AllMachines() |
90 if err != nil { | 92 if err != nil { |
91 return nil, err | 93 return nil, err |
92 } | 94 } |
93 for _, m := range machines { | 95 for _, m := range machines { |
94 v[m.Id()] = m | 96 v[m.Id()] = m |
95 } | 97 } |
96 return v, nil | 98 return v, nil |
97 } | 99 } |
98 | 100 |
99 // fetchAllServices returns a map representing a mapping of service | 101 // fetchAllServicesAndUnits returns a map from service name to service |
100 // names to services. | 102 // and a map from service name to unit name to unit. |
101 func fetchAllServices(st *state.State) (map[string]*state.Service, error) { | 103 func fetchAllServicesAndUnits(st *state.State) (map[string]*state.Service, map[s tring]map[string]*state.Unit, error) { |
102 » v := make(map[string]*state.Service) | 104 » svcMap := make(map[string]*state.Service) |
105 » unitMap := make(map[string]map[string]*state.Unit) | |
103 services, err := st.AllServices() | 106 services, err := st.AllServices() |
104 if err != nil { | 107 if err != nil { |
105 » » return nil, err | 108 » » return nil, nil, err |
106 } | 109 } |
107 for _, s := range services { | 110 for _, s := range services { |
108 » » v[s.Name()] = s | 111 » » svcMap[s.Name()] = s |
109 » } | 112 » » units, err := s.AllUnits() |
110 » return v, nil | 113 » » if err != nil { |
111 } | 114 » » » return nil, nil, err |
112 | 115 » » } |
113 // processMachines gathers information about machines. | 116 » » svcUnitMap := make(map[string]*state.Unit) |
114 func processMachines(machines map[string]*state.Machine, instances map[state.Ins tanceId]environs.Instance) (statusMap, error) { | 117 » » for _, u := range units { |
115 » machinesMap := make(statusMap) | 118 » » » svcUnitMap[u.Name()] = u |
116 » for _, m := range machines { | 119 » » } |
117 » » instid, ok := m.InstanceId() | 120 » » unitMap[s.Name()] = svcUnitMap |
118 » » if !ok { | 121 » } |
119 » » » machinesMap[m.Id()] = statusMap{ | 122 » return svcMap, unitMap, nil |
120 » » » » "instance-id": "pending", | 123 } |
121 » » » } | 124 |
122 » » } else { | 125 func (ctxt *statusContext) processMachines() map[string]machineStatus { |
123 » » » instance, ok := instances[instid] | 126 » machinesMap := make(map[string]machineStatus) |
124 » » » if !ok { | 127 » for _, m := range ctxt.machines { |
125 » » » » // Double plus ungood. There is an instance id r ecorded for this machine in the state, | 128 » » machinesMap[m.Id()] = ctxt.processMachine(m) |
126 » » » » // yet the environ cannot find that id. | 129 » } |
127 » » » » return nil, fmt.Errorf("instance %s for machine %s not found", instid, m.Id()) | 130 » return machinesMap |
128 » » » } | 131 } |
129 » » » machinesMap[m.Id()] = checkError(processMachine(m, insta nce)) | 132 |
130 » » } | 133 func (ctxt *statusContext) processMachine(machine *state.Machine) (status machin eStatus) { |
131 » } | 134 » instid, ok := machine.InstanceId() |
132 » return machinesMap, nil | 135 » if !ok { |
133 } | 136 » » status.InstanceId = "pending" |
134 | 137 » » return |
135 func processStatus(sm statusMap, status params.Status, info string, agentAlive, entityDead bool) { | 138 » } |
136 » if status != params.StatusPending { | 139 » instance, ok := ctxt.instances[instid] |
137 » » if !agentAlive && !entityDead { | 140 » if !ok { |
138 » » » // Add the original status to the info, so it's not lost . | 141 » » // Double plus ungood. There is an |
139 » » » if info != "" { | 142 » » // instance id recorded for this machine |
140 » » » » info = fmt.Sprintf("(%s: %s)", status, info) | 143 » » // in the state, yet the environ cannot |
141 » » » } else { | 144 » » // find that id. |
fwereade
2013/04/17 22:04:08
Not really an error; definitely not one that justi
rog
2013/04/17 22:31:45
Done.
| |
142 » » » » info = fmt.Sprintf("(%s)", status) | 145 » » status.Err = fmt.Errorf("instance %s not found", instid) |
143 » » » } | 146 » » return |
144 » » » // Agent should be running but it's not. | 147 » } |
145 » » » status = params.StatusDown | 148 » status.InstanceId = instance.Id() |
146 » » } | 149 » status.DNSName, _ = instance.DNSName() |
147 » } | 150 » processVersion(&status.AgentVersion, machine) |
148 » sm["agent-state"] = status | 151 » status.Err = processStatus(&status.AgentState, &status.AgentStateInfo, m achine) |
149 » if info != "" { | 152 » return |
150 » » sm["agent-state-info"] = info | 153 } |
151 » } | 154 |
152 } | 155 func (ctxt *statusContext) processServices() map[string]serviceStatus { |
153 | 156 » servicesMap := make(map[string]serviceStatus) |
154 func processMachine(machine *state.Machine, instance environs.Instance) (statusM ap, error) { | 157 » for _, s := range ctxt.services { |
155 » machineMap := make(statusMap) | 158 » » servicesMap[s.Name()] = ctxt.processService(s) |
156 » machineMap["instance-id"] = instance.Id() | 159 » } |
157 | 160 » return servicesMap |
158 » if dnsname, err := instance.DNSName(); err == nil { | 161 } |
159 » » machineMap["dns-name"] = dnsname | 162 |
160 » } | 163 func (ctxt *statusContext) processService(service *state.Service) (status servic eStatus) { |
161 | |
162 » processVersion(machineMap, machine) | |
163 | |
164 » agentAlive, err := machine.AgentAlive() | |
165 » if err != nil { | |
166 » » return nil, err | |
167 » } | |
168 » machineDead := machine.Life() == state.Dead | |
169 » status, info, err := machine.Status() | |
170 » if err != nil { | |
171 » » return nil, err | |
172 » } | |
173 » processStatus(machineMap, status, info, agentAlive, machineDead) | |
174 | |
175 » return machineMap, nil | |
176 } | |
177 | |
178 // processServices gathers information about services. | |
179 func processServices(services map[string]*state.Service) (statusMap, error) { | |
180 » servicesMap := make(statusMap) | |
181 » for _, s := range services { | |
182 » » servicesMap[s.Name()] = checkError(processService(s)) | |
183 » } | |
184 » return servicesMap, nil | |
185 } | |
186 | |
187 func processService(service *state.Service) (statusMap, error) { | |
188 » serviceMap := make(statusMap) | |
189 ch, _, err := service.Charm() | 164 ch, _, err := service.Charm() |
fwereade
2013/04/17 22:04:08
I think you can just get CharmURL here
rog
2013/04/17 22:31:45
much nicer, yes. done (less round-trips, yay!)
| |
190 if err != nil { | 165 if err != nil { |
191 » » return nil, err | 166 » » status.Err = err |
192 » } | 167 » » return |
193 » serviceMap["charm"] = ch.String() | 168 » } |
194 » serviceMap["exposed"] = service.IsExposed() | 169 » status.Charm = ch.String() |
195 | 170 » status.Exposed = service.IsExposed() |
196 » // TODO(dfc) service.IsSubordinate() ? | 171 » status.Relations, status.SubordinateTo, err = ctxt.processRelations(serv ice) |
197 | 172 » if err != nil { |
198 » units, err := service.AllUnits() | 173 » » status.Err = err |
199 » if err != nil { | 174 » » return |
200 » » return nil, err | 175 » } |
201 » } | 176 » if !service.IsSubordinate() { |
202 | 177 » » status.Units = ctxt.processUnits(ctxt.units[service.Name()]) |
203 » if u := checkError(processUnits(units)); len(u) > 0 { | 178 » } |
204 » » serviceMap["units"] = u | 179 » return status |
205 » } | 180 } |
206 | 181 |
207 » if r := checkError(processRelations(service)); len(r) > 0 { | 182 func (ctxt *statusContext) processUnits(units map[string]*state.Unit) map[string ]unitStatus { |
208 » » serviceMap["relations"] = r | 183 » unitsMap := make(map[string]unitStatus) |
209 » } | |
210 | |
211 » return serviceMap, nil | |
212 } | |
213 | |
214 func processUnits(units []*state.Unit) (statusMap, error) { | |
215 » unitsMap := make(statusMap) | |
216 for _, unit := range units { | 184 for _, unit := range units { |
217 » » unitsMap[unit.Name()] = checkError(processUnit(unit)) | 185 » » unitsMap[unit.Name()] = ctxt.processUnit(unit) |
218 » } | 186 » } |
219 » return unitsMap, nil | 187 » return unitsMap |
220 } | 188 } |
221 | 189 |
222 func processUnit(unit *state.Unit) (statusMap, error) { | 190 func (ctxt *statusContext) processUnit(unit *state.Unit) (status unitStatus) { |
223 » unitMap := make(statusMap) | 191 » status.PublicAddress, _ = unit.PublicAddress() |
224 | 192 » if unit.IsPrincipal() { |
225 » if addr, ok := unit.PublicAddress(); ok { | 193 » » status.Machine, _ = unit.AssignedMachineId() |
226 » » unitMap["public-address"] = addr | 194 » } |
227 » } | 195 » processVersion(&status.AgentVersion, unit) |
228 | 196 » if err := processStatus(&status.AgentState, &status.AgentStateInfo, unit ); err != nil { |
229 » if id, err := unit.AssignedMachineId(); err == nil { | 197 » » status.Err = err |
230 » » // TODO(dfc) we could make this nicer, ie machine/0 | 198 » » return |
231 » » unitMap["machine"] = id | 199 » } |
232 » } | 200 » if subUnits := unit.SubordinateNames(); len(subUnits) > 0 { |
233 | 201 » » status.Subordinates = make(map[string]unitStatus) |
234 » processVersion(unitMap, unit) | 202 » » for _, name := range subUnits { |
235 | 203 » » » subUnit := ctxt.unitByName(name) |
236 » agentAlive, err := unit.AgentAlive() | 204 » » » status.Subordinates[name] = ctxt.processUnit(subUnit) |
237 » if err != nil { | 205 » » } |
238 » » return nil, err | 206 » } |
239 » } | 207 » return |
240 » unitDead := unit.Life() == state.Dead | 208 } |
241 » status, info, err := unit.Status() | 209 |
242 » if err != nil { | 210 func (ctxt *statusContext) unitByName(name string) *state.Unit { |
243 » » return nil, err | 211 » serviceName := strings.Split(name, "/")[0] |
244 » } | 212 » return ctxt.units[serviceName][name] |
245 » processStatus(unitMap, status, info, agentAlive, unitDead) | 213 } |
246 | 214 |
247 » return unitMap, nil | 215 func (*statusContext) processRelations(service *state.Service) (related map[stri ng][]string, subord []string, err error) { |
248 } | |
249 | |
250 func processRelations(service *state.Service) (statusMap, error) { | |
251 // TODO(mue) This way the same relation is read twice (for each service) . | 216 // TODO(mue) This way the same relation is read twice (for each service) . |
252 // Maybe add Relations() to state, read them only once and pass them to each | 217 // Maybe add Relations() to state, read them only once and pass them to each |
253 » // call of this function. | 218 » // call of this function. |
254 relations, err := service.Relations() | 219 relations, err := service.Relations() |
255 if err != nil { | 220 if err != nil { |
256 » » return nil, err | 221 » » return nil, nil, err |
257 » } | 222 » } |
258 » relationMap := make(statusMap) | 223 » var subordSet set.Strings |
224 » related = make(map[string][]string) | |
259 for _, relation := range relations { | 225 for _, relation := range relations { |
260 ep, err := relation.Endpoint(service.Name()) | 226 ep, err := relation.Endpoint(service.Name()) |
261 if err != nil { | 227 if err != nil { |
262 » » » return nil, err | 228 » » » return nil, nil, err |
263 } | 229 } |
264 relationName := ep.Relation.Name | 230 relationName := ep.Relation.Name |
265 eps, err := relation.RelatedEndpoints(service.Name()) | 231 eps, err := relation.RelatedEndpoints(service.Name()) |
266 if err != nil { | 232 if err != nil { |
267 » » » return nil, err | 233 » » » return nil, nil, err |
268 » » } | |
269 » » serviceNames := []string{} | |
270 » » if relationMap[relationName] != nil { | |
271 » » » serviceNames = relationMap[relationName].([]string) | |
272 } | 234 } |
273 for _, ep := range eps { | 235 for _, ep := range eps { |
274 » » » serviceNames = append(serviceNames, ep.ServiceName) | 236 » » » if ep.Scope == charm.ScopeContainer && service.IsSubordi nate() { |
275 » » } | 237 » » » » subordSet.Add(ep.ServiceName) |
276 » » relationMap[relationName] = serviceNames | 238 » » » } |
277 » } | 239 » » » related[relationName] = append(related[relationName], ep .ServiceName) |
278 » // Normalize service names by removing duplicates and sorting them. | 240 » » } |
279 » // TODO(mue) Check if and why duplicates can happen and what this means. | 241 » } |
280 » for relationName, serviceNames := range relationMap { | 242 » for relationName, serviceNames := range related { |
281 » » sn := set.NewStrings(serviceNames.([]string)...) | 243 » » sn := set.NewStrings(serviceNames...) |
282 » » relationMap[relationName] = sn.SortedValues() | 244 » » related[relationName] = sn.SortedValues() |
283 » } | 245 » } |
284 » return relationMap, nil | 246 » return related, subordSet.SortedValues(), nil |
285 } | 247 } |
286 | 248 |
287 type versioned interface { | 249 type versioned interface { |
288 AgentTools() (*state.Tools, error) | 250 AgentTools() (*state.Tools, error) |
289 } | 251 } |
290 | 252 |
291 func processVersion(sm statusMap, v versioned) { | 253 // processVersion stores the agent version in status. |
254 func processVersion(version *string, v versioned) { | |
292 if t, err := v.AgentTools(); err == nil { | 255 if t, err := v.AgentTools(); err == nil { |
293 » » sm["agent-version"] = t.Binary.Number.String() | 256 » » *version = t.Binary.Number.String() |
294 » } | 257 » } |
295 } | 258 } |
296 | 259 |
297 func checkError(sm statusMap, err error) statusMap { | 260 type statuser interface { |
298 » if err != nil { | 261 » Life() state.Life |
299 » » return map[string]interface{}{"status-error": err.Error()} | 262 » AgentAlive() (bool, error) |
300 » } | 263 » Status() (params.Status, string, error) |
301 » return sm | 264 } |
302 } | 265 |
266 // processStatus retrieves the status from the given entity | |
267 // and sets the destination status and info values accordingly. | |
268 func processStatus(dstStatus *params.Status, dstInfo *string, entity statuser) e rror { | |
269 » agentAlive, err := entity.AgentAlive() | |
270 » if err != nil { | |
271 » » return err | |
272 » } | |
273 » entityDead := entity.Life() == state.Dead | |
274 » status, info, err := entity.Status() | |
275 » if err != nil { | |
276 » » return err | |
277 » } | |
278 » if status != params.StatusPending && !agentAlive && !entityDead { | |
279 » » // Add the original status to the info, so it's not lost. | |
280 » » if info != "" { | |
281 » » » info = fmt.Sprintf("(%s: %s)", status, info) | |
282 » » } else { | |
283 » » » info = fmt.Sprintf("(%s)", status) | |
284 » » } | |
285 » » // Agent should be running but it's not. | |
286 » » status = params.StatusDown | |
287 » } | |
288 » *dstStatus = status | |
289 » *dstInfo = info | |
290 » return nil | |
291 } | |
292 | |
293 type machineStatus struct { | |
294 » Err error `json:"-" yaml:",omitempty"` | |
295 » InstanceId state.InstanceId `json:"instance-id" yaml:"instance-id"` | |
296 » DNSName string `json:"dns-name,omitempty" yaml:"dns-nam e,omitempty"` | |
297 » AgentVersion string `json:"agent-version,omitempty" yaml:"ag ent-version,omitempty"` | |
298 » AgentState params.Status `json:"agent-state,omitempty" yaml:"agen t-state,omitempty"` | |
299 » AgentStateInfo string `json:"agent-state-info,omitempty" yaml: "agent-state-info,omitempty"` | |
300 } | |
301 | |
302 // A goyaml bug means we can't declare these types | |
303 // locally to the GetYAML methods. | |
304 type machineStatusNoMarshal machineStatus | |
fwereade
2013/04/17 22:04:08
I have a great love for bug tests, which fail when
rog
2013/04/17 22:31:45
upstream bugs *are* in fact fixed - but i don't wa
| |
305 | |
306 type errorStatus struct { | |
307 » StatusError string `json:"status-error" yaml:"status-error"` | |
308 } | |
309 | |
310 func (s machineStatus) MarshalJSON() ([]byte, error) { | |
311 » if s.Err != nil { | |
312 » » return json.Marshal(errorStatus{s.Err.Error()}) | |
313 » } | |
314 » return json.Marshal(machineStatusNoMarshal(s)) | |
315 } | |
316 | |
317 func (s machineStatus) GetYAML() (tag string, value interface{}) { | |
318 » if s.Err != nil { | |
319 » » return "", errorStatus{s.Err.Error()} | |
320 » } | |
321 » // TODO(rog) rename mNoMethods to noMethods (and also in | |
322 » // the other GetYAML methods) when people are using the non-buggy | |
323 » // goyaml version. | |
324 » type mNoMethods machineStatus | |
325 » return "", mNoMethods(s) | |
326 } | |
327 | |
328 type serviceStatus struct { | |
329 » Err error `json:"-" yaml:",omitempty"` | |
330 » Charm string `json:"charm" yaml:"charm"` | |
331 » Exposed bool `json:"exposed" yaml:"exposed"` | |
332 » Units map[string]unitStatus `json:"units,omitempty" yaml:"units, omitempty"` | |
333 » Relations map[string][]string `json:"relations,omitempty" yaml:"re lations,omitempty"` | |
334 » SubordinateTo []string `json:"subordinate-to,omitempty" yam l:"subordinate-to,omitempty"` | |
335 } | |
336 type serviceStatusNoMarshal serviceStatus | |
337 | |
338 func (s serviceStatus) MarshalJSON() ([]byte, error) { | |
339 » if s.Err != nil { | |
340 » » return json.Marshal(errorStatus{s.Err.Error()}) | |
341 » } | |
342 » type sNoMethods serviceStatus | |
343 » return json.Marshal(sNoMethods(s)) | |
344 } | |
345 | |
346 func (s serviceStatus) GetYAML() (tag string, value interface{}) { | |
347 » if s.Err != nil { | |
348 » » return "", errorStatus{s.Err.Error()} | |
349 » } | |
350 » type sNoMethods serviceStatus | |
351 » return "", sNoMethods(s) | |
352 } | |
353 | |
354 type unitStatus struct { | |
355 » Err error `json:"-" yaml:",omitempty"` | |
356 » PublicAddress string `json:"public-address,omitempty" ya ml:"public-address,omitempty"` | |
357 » Machine string `json:"machine,omitempty" yaml:"mac hine,omitempty"` | |
358 » AgentVersion string `json:"agent-version,omitempty" yam l:"agent-version,omitempty"` | |
359 » AgentState params.Status `json:"agent-state,omitempty" yaml: "agent-state,omitempty"` | |
360 » AgentStateInfo string `json:"agent-state-info,omitempty" yaml:"agent-state-info,omitempty"` | |
361 » Subordinates map[string]unitStatus `json:"subordinates,omitempty" yaml :"subordinates,omitempty"` | |
362 } | |
363 | |
364 type unitStatusNoMarshal unitStatus | |
365 | |
366 func (s unitStatus) MarshalJSON() ([]byte, error) { | |
367 » if s.Err != nil { | |
368 » » return json.Marshal(errorStatus{s.Err.Error()}) | |
369 » } | |
370 » return json.Marshal(unitStatusNoMarshal(s)) | |
371 } | |
372 | |
373 func (s unitStatus) GetYAML() (tag string, value interface{}) { | |
374 » if s.Err != nil { | |
375 » » return "", errorStatus{s.Err.Error()} | |
376 » } | |
377 » type uNoMethods unitStatus | |
378 » return "", unitStatusNoMarshal(s) | |
379 } | |
OLD | NEW |