/
context.go
341 lines (281 loc) · 10 KB
/
context.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
// Copyright 2012, 2013, 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
package jujuc
import (
"fmt"
"strconv"
"strings"
"time"
"github.com/juju/errors"
"github.com/juju/names"
"gopkg.in/juju/charm.v5"
"github.com/juju/juju/apiserver/params"
"github.com/juju/juju/network"
"github.com/juju/juju/storage"
)
// RebootPriority is the type used for reboot requests.
type RebootPriority int
const (
// RebootSkip is a noop.
RebootSkip RebootPriority = iota
// RebootAfterHook means wait for current hook to finish before
// rebooting.
RebootAfterHook
// RebootNow means reboot immediately, killing and requeueing the
// calling hook
RebootNow
)
// Context is the interface that all hook helper commands
// depend on to interact with the rest of the system.
type Context interface {
HookContext
relationHookContext
actionHookContext
}
// HookContext represents the information and functionality that is
// common to all charm hooks.
type HookContext interface {
ContextUnit
ContextStatus
ContextInstance
ContextNetworking
ContextLeadership
ContextMetrics
ContextStorage
ContextRelations
}
// UnitHookContext is the context for a unit hook.
type UnitHookContext interface {
HookContext
}
// RelationHookContext is the context for a relation hook.
type RelationHookContext interface {
HookContext
relationHookContext
}
type relationHookContext interface {
// HookRelation returns the ContextRelation associated with the executing
// hook if it was found, and whether it was found.
HookRelation() (ContextRelation, bool)
// RemoteUnitName returns the name of the remote unit the hook execution
// is associated with if it was found, and whether it was found.
RemoteUnitName() (string, bool)
}
// ActionHookContext is the context for an action hook.
type ActionHookContext interface {
HookContext
actionHookContext
}
type actionHookContext interface {
// ActionParams returns the map of params passed with an Action.
ActionParams() (map[string]interface{}, error)
// UpdateActionResults inserts new values for use with action-set.
// The results struct will be delivered to the state server upon
// completion of the Action.
UpdateActionResults(keys []string, value string) error
// SetActionMessage sets a message for the Action.
SetActionMessage(string) error
// SetActionFailed sets a failure state for the Action.
SetActionFailed() error
}
// ContextUnit is the part of a hook context related to the unit.
type ContextUnit interface {
// UnitName returns the executing unit's name.
UnitName() string
// OwnerTag returns the user tag of the service the executing
// units belongs to.
OwnerTag() string
// Config returns the current service configuration of the executing unit.
ConfigSettings() (charm.Settings, error)
}
// ContextStatus is the part of a hook context related to the unit's status.
type ContextStatus interface {
// UnitStatus returns the executing unit's current status.
UnitStatus() (*StatusInfo, error)
// SetUnitStatus updates the unit's status.
SetUnitStatus(StatusInfo) error
// ServiceStatus returns the executing unit's service status
// (including all units).
ServiceStatus() (ServiceStatusInfo, error)
// SetServiceStatus updates the status for the unit's service.
SetServiceStatus(StatusInfo) error
}
// ContextInstance is the part of a hook context related to the unit's intance.
type ContextInstance interface {
// AvailabilityZone returns the executing unit's availablilty zone.
AvailabilityZone() (string, bool)
// RequestReboot will set the reboot flag to true on the machine agent
RequestReboot(prio RebootPriority) error
}
// ContextNetworking is the part of a hook context related to network
// interface of the unit's instance.
type ContextNetworking interface {
// PublicAddress returns the executing unit's public address.
PublicAddress() (string, bool)
// PrivateAddress returns the executing unit's private address.
PrivateAddress() (string, bool)
// OpenPorts marks the supplied port range for opening when the
// executing unit's service is exposed.
OpenPorts(protocol string, fromPort, toPort int) error
// ClosePorts ensures the supplied port range is closed even when
// the executing unit's service is exposed (unless it is opened
// separately by a co- located unit).
ClosePorts(protocol string, fromPort, toPort int) error
// OpenedPorts returns all port ranges currently opened by this
// unit on its assigned machine. The result is sorted first by
// protocol, then by number.
OpenedPorts() []network.PortRange
}
// ContextLeadership is the part of a hook context related to the
// unit leadership.
type ContextLeadership interface {
// IsLeader returns true if the local unit is known to be leader for at
// least the next 30s.
IsLeader() (bool, error)
// LeaderSettings returns the current leader settings. Once leader settings
// have been read in a given context, they will not be updated other than
// via successful calls to WriteLeaderSettings.
LeaderSettings() (map[string]string, error)
// WriteLeaderSettings writes the supplied settings directly to state, or
// fails if the local unit is not the service's leader.
WriteLeaderSettings(map[string]string) error
}
// ContextMetrics is the part of a hook context related to metrics.
type ContextMetrics interface {
// AddMetric records a metric to return after hook execution.
AddMetric(string, string, time.Time) error
}
// ContextStorage is the part of a hook context related to storage
// resources associated with the unit.
type ContextStorage interface {
// Storage returns the ContextStorageAttachment with the supplied
// tag if it was found, and whether it was found.
Storage(names.StorageTag) (ContextStorageAttachment, bool)
// HookStorage returns the storage attachment associated
// the executing hook if it was found, and whether it was found.
HookStorage() (ContextStorageAttachment, bool)
// AddUnitStorage saves storage constraints in the context.
AddUnitStorage(map[string]params.StorageConstraints)
}
// ContextRelations exposes the relations associated with the unit.
type ContextRelations interface {
// Relation returns the relation with the supplied id if it was found, and
// whether it was found.
Relation(id int) (ContextRelation, bool)
// RelationIds returns the ids of all relations the executing unit is
// currently participating in.
RelationIds() []int
}
// ContextRelation expresses the capabilities of a hook with respect to a relation.
type ContextRelation interface {
// Id returns an integer which uniquely identifies the relation.
Id() int
// Name returns the name the locally executing charm assigned to this relation.
Name() string
// FakeId returns a string of the form "relation-name:123", which uniquely
// identifies the relation to the hook. In reality, the identification
// of the relation is the integer following the colon, but the composed
// name is useful to humans observing it.
FakeId() string
// Settings allows read/write access to the local unit's settings in
// this relation.
Settings() (Settings, error)
// UnitNames returns a list of the remote units in the relation.
UnitNames() []string
// ReadSettings returns the settings of any remote unit in the relation.
ReadSettings(unit string) (params.Settings, error)
}
// ContextStorageAttachment expresses the capabilities of a hook with
// respect to a storage attachment.
type ContextStorageAttachment interface {
// Tag returns a tag which uniquely identifies the storage attachment
// in the context of the unit.
Tag() names.StorageTag
// Kind returns the kind of the storage.
Kind() storage.StorageKind
// Location returns the location of the storage: the mount point for
// filesystem-kind stores, and the device path for block-kind stores.
Location() string
}
// Settings is implemented by types that manipulate unit settings.
type Settings interface {
Map() params.Settings
Set(string, string)
Delete(string)
}
// newRelationIdValue returns a gnuflag.Value for convenient parsing of relation
// ids in ctx.
func newRelationIdValue(ctx Context, result *int) *relationIdValue {
v := &relationIdValue{result: result, ctx: ctx}
id := -1
if r, found := ctx.HookRelation(); found {
id = r.Id()
v.value = r.FakeId()
}
*result = id
return v
}
// relationIdValue implements gnuflag.Value for use in relation commands.
type relationIdValue struct {
result *int
ctx Context
value string
}
// String returns the current value.
func (v *relationIdValue) String() string {
return v.value
}
// Set interprets value as a relation id, if possible, and returns an error
// if it is not known to the system. The parsed relation id will be written
// to v.result.
func (v *relationIdValue) Set(value string) error {
trim := value
if idx := strings.LastIndex(trim, ":"); idx != -1 {
trim = trim[idx+1:]
}
id, err := strconv.Atoi(trim)
if err != nil {
return fmt.Errorf("invalid relation id")
}
if _, found := v.ctx.Relation(id); !found {
return fmt.Errorf("unknown relation id")
}
*v.result = id
v.value = value
return nil
}
// newStorageIdValue returns a gnuflag.Value for convenient parsing of storage
// ids in ctx.
func newStorageIdValue(ctx Context, result *names.StorageTag) *storageIdValue {
v := &storageIdValue{result: result, ctx: ctx}
if s, found := ctx.HookStorage(); found {
*v.result = s.Tag()
}
return v
}
// storageIdValue implements gnuflag.Value for use in storage commands.
type storageIdValue struct {
result *names.StorageTag
ctx Context
}
// String returns the current value.
func (v *storageIdValue) String() string {
if *v.result == (names.StorageTag{}) {
return ""
}
return v.result.Id()
}
// Set interprets value as a storage id, if possible, and returns an error
// if it is not known to the system. The parsed storage id will be written
// to v.result.
func (v *storageIdValue) Set(value string) error {
if !names.IsValidStorage(value) {
return errors.Errorf("invalid storage ID %q", value)
}
tag := names.NewStorageTag(value)
if _, found := v.ctx.Storage(tag); !found {
return fmt.Errorf("unknown storage ID")
}
*v.result = tag
return nil
}