forked from juju/juju
/
status.go
381 lines (322 loc) · 10.6 KB
/
status.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
package status
import (
"time"
)
// Status used to represent the status of an entity, but has recently become
// and applies to "workloads" as well, which we don't currently model, for no
// very clear reason.
//
// Status values currently apply to machine (agents), unit (agents), unit
// (workloads), application (workloads), volumes, filesystems, and models.
type Status string
// String returns a string representation of the Status.
func (s Status) String() string {
return string(s)
}
// StatusInfo holds a Status and associated information.
type StatusInfo struct {
Status Status
Message string
Data map[string]interface{}
Since *time.Time
}
// StatusSetter represents a type whose status can be set.
type StatusSetter interface {
SetStatus(StatusInfo) error
}
// StatusGetter represents a type whose status can be read.
type StatusGetter interface {
Status() (StatusInfo, error)
}
// ModificationStatusGetter represents a type whose modification status can be
// read.
type ModificationStatusGetter interface {
ModificationStatus() (StatusInfo, error)
}
const (
// Status values common to machine and unit agents.
// Error means the entity requires human intervention
// in order to operate correctly.
Error Status = "error"
// Started is set when:
// The entity is actively participating in the model.
// For unit agents, this is a state we preserve for backwards
// compatibility with scripts during the life of Juju 1.x.
// In Juju 2.x, the agent-state will remain “active” and scripts
// will watch the unit-state instead for signals of application readiness.
Started Status = "started"
)
const (
// Status values specific to machine agents.
// Pending is set when:
// The machine is not yet participating in the model.
Pending Status = "pending"
// Stopped is set when:
// The machine's agent will perform no further action, other than
// to set the unit to Dead at a suitable moment.
Stopped Status = "stopped"
// Down is set when:
// The machine ought to be signalling activity, but it cannot be
// detected.
Down Status = "down"
)
const (
// Status values specific to unit agents.
// Allocating is set when:
// The machine on which a unit is to be hosted is still being
// spun up in the cloud.
Allocating Status = "allocating"
// Rebooting is set when:
// The machine on which this agent is running is being rebooted.
// The juju-agent should move from rebooting to idle when the reboot is complete.
Rebooting Status = "rebooting"
// Executing is set when:
// The agent is running a hook or action. The human-readable message should reflect
// which hook or action is being run.
Executing Status = "executing"
// Idle is set when:
// Once the agent is installed and running it will notify the Juju server and its state
// becomes "idle". It will stay "idle" until some action (e.g. it needs to run a hook) or
// error (e.g it loses contact with the Juju server) moves it to a different state.
Idle Status = "idle"
// Failed is set when:
// The unit agent has failed in some way,eg the agent ought to be signalling
// activity, but it cannot be detected. It might also be that the unit agent
// detected an unrecoverable condition and managed to tell the Juju server about it.
Failed Status = "failed"
// Lost is set when:
// The juju agent has has not communicated with the juju server for an unexpectedly long time;
// the unit agent ought to be signalling activity, but none has been detected.
Lost Status = "lost"
)
const (
// Status values specific to applications and units, reflecting the
// state of the software itself.
// Unset is only for applications, and is a placeholder status.
// The core/cache package deals with aggregating the unit status
// to the application level.
Unset Status = "unset"
// Maintenance is set when:
// The unit is not yet providing services, but is actively doing stuff
// in preparation for providing those services.
// This is a "spinning" state, not an error state.
// It reflects activity on the unit itself, not on peers or related units.
Maintenance Status = "maintenance"
// Terminated is set when:
// This unit used to exist, we have a record of it (perhaps because of storage
// allocated for it that was flagged to survive it). Nonetheless, it is now gone.
Terminated Status = "terminated"
// Unknown is set when:
// A unit-agent has finished calling install, config-changed, and start,
// but the charm has not called status-set yet.
Unknown Status = "unknown"
// Waiting is set when:
// The unit is unable to progress to an active state because an application to
// which it is related is not running.
Waiting Status = "waiting"
// Blocked is set when:
// The unit needs manual intervention to get back to the Running state.
Blocked Status = "blocked"
// Active is set when:
// The unit believes it is correctly offering all the services it has
// been asked to offer.
Active Status = "active"
)
const (
// Status values specific to storage.
// Attaching indicates that the storage is being attached
// to a machine.
Attaching Status = "attaching"
// Attached indicates that the storage is attached to a
// machine.
Attached Status = "attached"
// Detaching indicates that the storage is being detached
// from a machine.
Detaching Status = "detaching"
// Detached indicates that the storage is not attached to
// any machine.
Detached Status = "detached"
)
const (
// Status values specific to models.
// Available indicates that the model is available for use.
Available Status = "available"
// Busy indicates that the model is not available for use because it is
// running a process that must take the model offline, such as a migration,
// upgrade, or backup. This is a spinning state, it is not an error state,
// and it should be expected that the model will eventually go back to
// available.
Busy Status = "busy"
)
const (
// Status values specific to relations.
// Joining is used to signify that a relation should become joined soon.
Joining Status = "joining"
// Joined is the normal status for a healthy, alive relation.
Joined Status = "joined"
// Broken is the status for when a relation life goes to Dead.
Broken Status = "broken"
// Suspending is used to signify that a relation will be temporarily broken
// pending action to resume it.
Suspending Status = "suspending"
// Suspended is used to signify that a relation is temporarily broken pending
// action to resume it.
Suspended Status = "suspended"
)
const (
// Status values that are common to several entities.
// Destroying indicates that the entity is being destroyed.
//
// This is valid for volumes, filesystems, and models.
Destroying Status = "destroying"
)
// InstanceStatus
const (
Empty Status = ""
Provisioning Status = "allocating"
Running Status = "running"
ProvisioningError Status = "provisioning error"
)
// ModificationStatus
const (
Applied Status = "applied"
)
const (
MessageWaitForMachine = "waiting for machine"
MessageWaitForContainer = "waiting for container"
MessageInstallingAgent = "installing agent"
MessageInitializingAgent = "agent initializing"
MessageInstallingCharm = "installing charm software"
)
// KnownModificationStatus returns true if the status has a known value for
// a modification of an instance.
func (status Status) KnownModificationStatus() bool {
switch status {
case
Idle,
Applied,
Error,
Unknown:
return true
}
return false
}
func (status Status) KnownInstanceStatus() bool {
switch status {
case
Pending,
ProvisioningError,
Allocating,
Running,
Error,
Unknown:
return true
}
return false
}
// KnownAgentStatus returns true if status has a known value for an agent.
// It includes every status that has ever been valid for a unit or machine agent.
// This is used by the apiserver client facade to filter out unknown values.
func (status Status) KnownAgentStatus() bool {
switch status {
case
Allocating,
Error,
Failed,
Rebooting,
Executing,
Idle:
return true
}
return false
}
// KnownWorkloadStatus returns true if status has a known value for a workload.
// It includes every status that has ever been valid for a unit agent.
// This is used by the apiserver client facade to filter out unknown values.
func (status Status) KnownWorkloadStatus() bool {
if ValidWorkloadStatus(status) {
return true
}
switch status {
case Error: // include error so that we can filter on what the spec says is valid
return true
default:
return false
}
}
// ValidWorkloadStatus returns true if status has a valid value (that is to say,
// a value that it's OK to set) for units or applications.
func ValidWorkloadStatus(status Status) bool {
switch status {
case
Blocked,
Maintenance,
Waiting,
Active,
Unknown,
Terminated:
return true
default:
return false
}
}
// WorkloadMatches returns true if the candidate matches status,
// taking into account that the candidate may be a legacy
// status value which has been deprecated.
func (status Status) WorkloadMatches(candidate Status) bool {
return status == candidate
}
// ValidModelStatus returns true if status has a valid value (that is to say,
// a value that it's OK to set) for models.
func ValidModelStatus(status Status) bool {
switch status {
case
Available,
Busy,
Destroying,
Suspended, // For model, this means that its cloud credential is invalid and model will not be doing any cloud calls.
Error:
return true
default:
return false
}
}
// Matches returns true if the candidate matches status,
// taking into account that the candidate may be a legacy
// status value which has been deprecated.
func (status Status) Matches(candidate Status) bool {
return status == candidate
}
// DeriveStatus is used to determine the application
// status from a set of unit status values.
func DeriveStatus(statuses []StatusInfo) StatusInfo {
// By providing an unknown default, we get a reasonable answer
// even if there are no units.
result := StatusInfo{
Status: Unknown,
}
for _, unitStatus := range statuses {
currentSeverity := statusServerities[result.Status]
unitSeverity := statusServerities[unitStatus.Status]
if unitSeverity > currentSeverity {
result.Status = unitStatus.Status
result.Message = unitStatus.Message
result.Data = unitStatus.Data
result.Since = unitStatus.Since
}
}
return result
}
// statusSeverities holds status values with a severity measure.
// Status values with higher severity are used in preference to others.
var statusServerities = map[Status]int{
Error: 100,
Blocked: 90,
Waiting: 80,
Maintenance: 70,
Active: 60,
Terminated: 50,
Unknown: 40,
}