~juju-qa/ubuntu/xenial/juju/xenial-2.0-beta3

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/core/description/unit.go

  • Committer: Martin Packman
  • Date: 2016-03-30 19:31:08 UTC
  • mfrom: (1.1.41)
  • Revision ID: martin.packman@canonical.com-20160330193108-h9iz3ak334uk0z5r
Merge new upstream source 2.0~beta3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2016 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package description
 
5
 
 
6
import (
 
7
        "github.com/juju/errors"
 
8
        "github.com/juju/names"
 
9
        "github.com/juju/schema"
 
10
)
 
11
 
 
12
type units struct {
 
13
        Version int     `yaml:"version"`
 
14
        Units_  []*unit `yaml:"units"`
 
15
}
 
16
 
 
17
type unit struct {
 
18
        Name_ string `yaml:"name"`
 
19
 
 
20
        Machine_ string `yaml:"machine"`
 
21
 
 
22
        AgentStatus_        *status        `yaml:"agent-status"`
 
23
        AgentStatusHistory_ StatusHistory_ `yaml:"agent-status-history"`
 
24
 
 
25
        WorkloadStatus_        *status        `yaml:"workload-status"`
 
26
        WorkloadStatusHistory_ StatusHistory_ `yaml:"workload-status-history"`
 
27
 
 
28
        Principal_    string   `yaml:"principal,omitempty"`
 
29
        Subordinates_ []string `yaml:"subordinates,omitempty"`
 
30
 
 
31
        // TODO:
 
32
        //  storage constraints
 
33
        //  storage attachment count
 
34
 
 
35
        PasswordHash_ string      `yaml:"password-hash"`
 
36
        Tools_        *agentTools `yaml:"tools"`
 
37
 
 
38
        MeterStatusCode_ string `yaml:"meter-status-code,omitempty"`
 
39
        MeterStatusInfo_ string `yaml:"meter-status-info,omitempty"`
 
40
 
 
41
        Annotations_ `yaml:"annotations,omitempty"`
 
42
 
 
43
        Constraints_ *constraints `yaml:"constraints,omitempty"`
 
44
}
 
45
 
 
46
// UnitArgs is an argument struct used to add a Unit to a Service in the Model.
 
47
type UnitArgs struct {
 
48
        Tag          names.UnitTag
 
49
        Machine      names.MachineTag
 
50
        PasswordHash string
 
51
        Principal    names.UnitTag
 
52
        Subordinates []names.UnitTag
 
53
 
 
54
        MeterStatusCode string
 
55
        MeterStatusInfo string
 
56
 
 
57
        // TODO: storage attachment count
 
58
}
 
59
 
 
60
func newUnit(args UnitArgs) *unit {
 
61
        var subordinates []string
 
62
        for _, s := range args.Subordinates {
 
63
                subordinates = append(subordinates, s.Id())
 
64
        }
 
65
        return &unit{
 
66
                Name_:                  args.Tag.Id(),
 
67
                Machine_:               args.Machine.Id(),
 
68
                PasswordHash_:          args.PasswordHash,
 
69
                Principal_:             args.Principal.Id(),
 
70
                Subordinates_:          subordinates,
 
71
                MeterStatusCode_:       args.MeterStatusCode,
 
72
                MeterStatusInfo_:       args.MeterStatusInfo,
 
73
                WorkloadStatusHistory_: newStatusHistory(),
 
74
                AgentStatusHistory_:    newStatusHistory(),
 
75
        }
 
76
}
 
77
 
 
78
// Tag implements Unit.
 
79
func (u *unit) Tag() names.UnitTag {
 
80
        return names.NewUnitTag(u.Name_)
 
81
}
 
82
 
 
83
// Name implements Unit.
 
84
func (u *unit) Name() string {
 
85
        return u.Name_
 
86
}
 
87
 
 
88
// Machine implements Unit.
 
89
func (u *unit) Machine() names.MachineTag {
 
90
        return names.NewMachineTag(u.Machine_)
 
91
}
 
92
 
 
93
// PasswordHash implements Unit.
 
94
func (u *unit) PasswordHash() string {
 
95
        return u.PasswordHash_
 
96
}
 
97
 
 
98
// Principal implements Unit.
 
99
func (u *unit) Principal() names.UnitTag {
 
100
        if u.Principal_ == "" {
 
101
                return names.UnitTag{}
 
102
        }
 
103
        return names.NewUnitTag(u.Principal_)
 
104
}
 
105
 
 
106
// Subordinates implements Unit.
 
107
func (u *unit) Subordinates() []names.UnitTag {
 
108
        var subordinates []names.UnitTag
 
109
        for _, s := range u.Subordinates_ {
 
110
                subordinates = append(subordinates, names.NewUnitTag(s))
 
111
        }
 
112
        return subordinates
 
113
}
 
114
 
 
115
// MeterStatusCode implements Unit.
 
116
func (u *unit) MeterStatusCode() string {
 
117
        return u.MeterStatusCode_
 
118
}
 
119
 
 
120
// MeterStatusInfo implements Unit.
 
121
func (u *unit) MeterStatusInfo() string {
 
122
        return u.MeterStatusInfo_
 
123
}
 
124
 
 
125
// Tools implements Unit.
 
126
func (u *unit) Tools() AgentTools {
 
127
        // To avoid a typed nil, check before returning.
 
128
        if u.Tools_ == nil {
 
129
                return nil
 
130
        }
 
131
        return u.Tools_
 
132
}
 
133
 
 
134
// SetTools implements Unit.
 
135
func (u *unit) SetTools(args AgentToolsArgs) {
 
136
        u.Tools_ = newAgentTools(args)
 
137
}
 
138
 
 
139
// WorkloadStatus implements Unit.
 
140
func (u *unit) WorkloadStatus() Status {
 
141
        // To avoid typed nils check nil here.
 
142
        if u.WorkloadStatus_ == nil {
 
143
                return nil
 
144
        }
 
145
        return u.WorkloadStatus_
 
146
}
 
147
 
 
148
// SetWorkloadStatus implements Unit.
 
149
func (u *unit) SetWorkloadStatus(args StatusArgs) {
 
150
        u.WorkloadStatus_ = newStatus(args)
 
151
}
 
152
 
 
153
// WorkloadStatusHistory implements Unit.
 
154
func (u *unit) WorkloadStatusHistory() []Status {
 
155
        return u.WorkloadStatusHistory_.StatusHistory()
 
156
}
 
157
 
 
158
// SetWorkloadStatusHistory implements Unit.
 
159
func (u *unit) SetWorkloadStatusHistory(args []StatusArgs) {
 
160
        u.WorkloadStatusHistory_.SetStatusHistory(args)
 
161
}
 
162
 
 
163
// AgentStatus implements Unit.
 
164
func (u *unit) AgentStatus() Status {
 
165
        // To avoid typed nils check nil here.
 
166
        if u.AgentStatus_ == nil {
 
167
                return nil
 
168
        }
 
169
        return u.AgentStatus_
 
170
}
 
171
 
 
172
// SetAgentStatus implements Unit.
 
173
func (u *unit) SetAgentStatus(args StatusArgs) {
 
174
        u.AgentStatus_ = newStatus(args)
 
175
}
 
176
 
 
177
// AgentStatusHistory implements Unit.
 
178
func (u *unit) AgentStatusHistory() []Status {
 
179
        return u.AgentStatusHistory_.StatusHistory()
 
180
}
 
181
 
 
182
// SetAgentStatusHistory implements Unit.
 
183
func (u *unit) SetAgentStatusHistory(args []StatusArgs) {
 
184
        u.AgentStatusHistory_.SetStatusHistory(args)
 
185
}
 
186
 
 
187
// Constraints implements HasConstraints.
 
188
func (u *unit) Constraints() Constraints {
 
189
        if u.Constraints_ == nil {
 
190
                return nil
 
191
        }
 
192
        return u.Constraints_
 
193
}
 
194
 
 
195
// SetConstraints implements HasConstraints.
 
196
func (u *unit) SetConstraints(args ConstraintsArgs) {
 
197
        u.Constraints_ = newConstraints(args)
 
198
}
 
199
 
 
200
// Validate impelements Unit.
 
201
func (u *unit) Validate() error {
 
202
        if u.Name_ == "" {
 
203
                return errors.NotValidf("missing name")
 
204
        }
 
205
        if u.AgentStatus_ == nil {
 
206
                return errors.NotValidf("unit %q missing agent status", u.Name_)
 
207
        }
 
208
        if u.WorkloadStatus_ == nil {
 
209
                return errors.NotValidf("unit %q missing workload status", u.Name_)
 
210
        }
 
211
        if u.Tools_ == nil {
 
212
                return errors.NotValidf("unit %q missing tools", u.Name_)
 
213
        }
 
214
        return nil
 
215
}
 
216
 
 
217
func importUnits(source map[string]interface{}) ([]*unit, error) {
 
218
        checker := versionedChecker("units")
 
219
        coerced, err := checker.Coerce(source, nil)
 
220
        if err != nil {
 
221
                return nil, errors.Annotatef(err, "units version schema check failed")
 
222
        }
 
223
        valid := coerced.(map[string]interface{})
 
224
 
 
225
        version := int(valid["version"].(int64))
 
226
        importFunc, ok := unitDeserializationFuncs[version]
 
227
        if !ok {
 
228
                return nil, errors.NotValidf("version %d", version)
 
229
        }
 
230
        sourceList := valid["units"].([]interface{})
 
231
        return importUnitList(sourceList, importFunc)
 
232
}
 
233
 
 
234
func importUnitList(sourceList []interface{}, importFunc unitDeserializationFunc) ([]*unit, error) {
 
235
        result := make([]*unit, 0, len(sourceList))
 
236
        for i, value := range sourceList {
 
237
                source, ok := value.(map[string]interface{})
 
238
                if !ok {
 
239
                        return nil, errors.Errorf("unexpected value for unit %d, %T", i, value)
 
240
                }
 
241
                unit, err := importFunc(source)
 
242
                if err != nil {
 
243
                        return nil, errors.Annotatef(err, "unit %d", i)
 
244
                }
 
245
                result = append(result, unit)
 
246
        }
 
247
        return result, nil
 
248
}
 
249
 
 
250
type unitDeserializationFunc func(map[string]interface{}) (*unit, error)
 
251
 
 
252
var unitDeserializationFuncs = map[int]unitDeserializationFunc{
 
253
        1: importUnitV1,
 
254
}
 
255
 
 
256
func importUnitV1(source map[string]interface{}) (*unit, error) {
 
257
        fields := schema.Fields{
 
258
                "name":    schema.String(),
 
259
                "machine": schema.String(),
 
260
 
 
261
                "agent-status":            schema.StringMap(schema.Any()),
 
262
                "agent-status-history":    schema.StringMap(schema.Any()),
 
263
                "workload-status":         schema.StringMap(schema.Any()),
 
264
                "workload-status-history": schema.StringMap(schema.Any()),
 
265
 
 
266
                "principal":    schema.String(),
 
267
                "subordinates": schema.List(schema.String()),
 
268
 
 
269
                "password-hash": schema.String(),
 
270
                "tools":         schema.StringMap(schema.Any()),
 
271
 
 
272
                "meter-status-code": schema.String(),
 
273
                "meter-status-info": schema.String(),
 
274
        }
 
275
        defaults := schema.Defaults{
 
276
                "principal":         "",
 
277
                "subordinates":      schema.Omit,
 
278
                "meter-status-code": "",
 
279
                "meter-status-info": "",
 
280
        }
 
281
        addAnnotationSchema(fields, defaults)
 
282
        addConstraintsSchema(fields, defaults)
 
283
        checker := schema.FieldMap(fields, defaults)
 
284
 
 
285
        coerced, err := checker.Coerce(source, nil)
 
286
        if err != nil {
 
287
                return nil, errors.Annotatef(err, "unit v1 schema check failed")
 
288
        }
 
289
        valid := coerced.(map[string]interface{})
 
290
        // From here we know that the map returned from the schema coercion
 
291
        // contains fields of the right type.
 
292
 
 
293
        result := &unit{
 
294
                Name_:                  valid["name"].(string),
 
295
                Machine_:               valid["machine"].(string),
 
296
                Principal_:             valid["principal"].(string),
 
297
                PasswordHash_:          valid["password-hash"].(string),
 
298
                MeterStatusCode_:       valid["meter-status-code"].(string),
 
299
                MeterStatusInfo_:       valid["meter-status-info"].(string),
 
300
                WorkloadStatusHistory_: newStatusHistory(),
 
301
                AgentStatusHistory_:    newStatusHistory(),
 
302
        }
 
303
        result.importAnnotations(valid)
 
304
 
 
305
        workloadHistory := valid["workload-status-history"].(map[string]interface{})
 
306
        if err := importStatusHistory(&result.WorkloadStatusHistory_, workloadHistory); err != nil {
 
307
                return nil, errors.Trace(err)
 
308
        }
 
309
        agentHistory := valid["agent-status-history"].(map[string]interface{})
 
310
        if err := importStatusHistory(&result.AgentStatusHistory_, agentHistory); err != nil {
 
311
                return nil, errors.Trace(err)
 
312
        }
 
313
 
 
314
        if constraintsMap, ok := valid["constraints"]; ok {
 
315
                constraints, err := importConstraints(constraintsMap.(map[string]interface{}))
 
316
                if err != nil {
 
317
                        return nil, errors.Trace(err)
 
318
                }
 
319
                result.Constraints_ = constraints
 
320
        }
 
321
 
 
322
        result.Subordinates_ = convertToStringSlice(valid["subordinates"])
 
323
 
 
324
        // Tools and status are required, so we expect them to be there.
 
325
        tools, err := importAgentTools(valid["tools"].(map[string]interface{}))
 
326
        if err != nil {
 
327
                return nil, errors.Trace(err)
 
328
        }
 
329
        result.Tools_ = tools
 
330
 
 
331
        agentStatus, err := importStatus(valid["agent-status"].(map[string]interface{}))
 
332
        if err != nil {
 
333
                return nil, errors.Trace(err)
 
334
        }
 
335
        result.AgentStatus_ = agentStatus
 
336
 
 
337
        workloadStatus, err := importStatus(valid["workload-status"].(map[string]interface{}))
 
338
        if err != nil {
 
339
                return nil, errors.Trace(err)
 
340
        }
 
341
        result.WorkloadStatus_ = workloadStatus
 
342
 
 
343
        return result, nil
 
344
}