~nskaggs/+junk/xenial-test

« back to all changes in this revision

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

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

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/schema"
 
9
        "gopkg.in/juju/names.v2"
 
10
)
 
11
 
 
12
type filesystems struct {
 
13
        Version      int           `yaml:"version"`
 
14
        Filesystems_ []*filesystem `yaml:"filesystems"`
 
15
}
 
16
 
 
17
type filesystem struct {
 
18
        ID_        string `yaml:"id"`
 
19
        StorageID_ string `yaml:"storage-id,omitempty"`
 
20
        VolumeID_  string `yaml:"volume-id,omitempty"`
 
21
        Binding_   string `yaml:"binding,omitempty"`
 
22
 
 
23
        Provisioned_  bool   `yaml:"provisioned"`
 
24
        Size_         uint64 `yaml:"size"`
 
25
        Pool_         string `yaml:"pool,omitempty"`
 
26
        FilesystemID_ string `yaml:"filesystem-id,omitempty"`
 
27
 
 
28
        Status_        *status `yaml:"status"`
 
29
        StatusHistory_ `yaml:"status-history"`
 
30
 
 
31
        Attachments_ filesystemAttachments `yaml:"attachments"`
 
32
}
 
33
 
 
34
type filesystemAttachments struct {
 
35
        Version      int                     `yaml:"version"`
 
36
        Attachments_ []*filesystemAttachment `yaml:"attachments"`
 
37
}
 
38
 
 
39
type filesystemAttachment struct {
 
40
        MachineID_   string `yaml:"machine-id"`
 
41
        Provisioned_ bool   `yaml:"provisioned"`
 
42
        MountPoint_  string `yaml:"mount-point,omitempty"`
 
43
        ReadOnly_    bool   `yaml:"read-only"`
 
44
}
 
45
 
 
46
// FilesystemArgs is an argument struct used to add a filesystem to the Model.
 
47
type FilesystemArgs struct {
 
48
        Tag          names.FilesystemTag
 
49
        Storage      names.StorageTag
 
50
        Volume       names.VolumeTag
 
51
        Binding      names.Tag
 
52
        Provisioned  bool
 
53
        Size         uint64
 
54
        Pool         string
 
55
        FilesystemID string
 
56
}
 
57
 
 
58
func newFilesystem(args FilesystemArgs) *filesystem {
 
59
        f := &filesystem{
 
60
                ID_:            args.Tag.Id(),
 
61
                StorageID_:     args.Storage.Id(),
 
62
                VolumeID_:      args.Volume.Id(),
 
63
                Provisioned_:   args.Provisioned,
 
64
                Size_:          args.Size,
 
65
                Pool_:          args.Pool,
 
66
                FilesystemID_:  args.FilesystemID,
 
67
                StatusHistory_: newStatusHistory(),
 
68
        }
 
69
        if args.Binding != nil {
 
70
                f.Binding_ = args.Binding.String()
 
71
        }
 
72
        f.setAttachments(nil)
 
73
        return f
 
74
}
 
75
 
 
76
// Tag implements Filesystem.
 
77
func (f *filesystem) Tag() names.FilesystemTag {
 
78
        return names.NewFilesystemTag(f.ID_)
 
79
}
 
80
 
 
81
// Volume implements Filesystem.
 
82
func (f *filesystem) Volume() names.VolumeTag {
 
83
        if f.VolumeID_ == "" {
 
84
                return names.VolumeTag{}
 
85
        }
 
86
        return names.NewVolumeTag(f.VolumeID_)
 
87
}
 
88
 
 
89
// Storage implements Filesystem.
 
90
func (f *filesystem) Storage() names.StorageTag {
 
91
        if f.StorageID_ == "" {
 
92
                return names.StorageTag{}
 
93
        }
 
94
        return names.NewStorageTag(f.StorageID_)
 
95
}
 
96
 
 
97
// Binding implements Filesystem.
 
98
func (f *filesystem) Binding() (names.Tag, error) {
 
99
        if f.Binding_ == "" {
 
100
                return nil, nil
 
101
        }
 
102
        tag, err := names.ParseTag(f.Binding_)
 
103
        if err != nil {
 
104
                return nil, errors.Trace(err)
 
105
        }
 
106
        return tag, nil
 
107
}
 
108
 
 
109
// Provisioned implements Filesystem.
 
110
func (f *filesystem) Provisioned() bool {
 
111
        return f.Provisioned_
 
112
}
 
113
 
 
114
// Size implements Filesystem.
 
115
func (f *filesystem) Size() uint64 {
 
116
        return f.Size_
 
117
}
 
118
 
 
119
// Pool implements Filesystem.
 
120
func (f *filesystem) Pool() string {
 
121
        return f.Pool_
 
122
}
 
123
 
 
124
// FilesystemID implements Filesystem.
 
125
func (f *filesystem) FilesystemID() string {
 
126
        return f.FilesystemID_
 
127
}
 
128
 
 
129
// Status implements Filesystem.
 
130
func (f *filesystem) Status() Status {
 
131
        // To avoid typed nils check nil here.
 
132
        if f.Status_ == nil {
 
133
                return nil
 
134
        }
 
135
        return f.Status_
 
136
}
 
137
 
 
138
// SetStatus implements Filesystem.
 
139
func (f *filesystem) SetStatus(args StatusArgs) {
 
140
        f.Status_ = newStatus(args)
 
141
}
 
142
 
 
143
func (f *filesystem) setAttachments(attachments []*filesystemAttachment) {
 
144
        f.Attachments_ = filesystemAttachments{
 
145
                Version:      1,
 
146
                Attachments_: attachments,
 
147
        }
 
148
}
 
149
 
 
150
// Attachments implements Filesystem.
 
151
func (f *filesystem) Attachments() []FilesystemAttachment {
 
152
        var result []FilesystemAttachment
 
153
        for _, attachment := range f.Attachments_.Attachments_ {
 
154
                result = append(result, attachment)
 
155
        }
 
156
        return result
 
157
}
 
158
 
 
159
// AddAttachment implements Filesystem.
 
160
func (f *filesystem) AddAttachment(args FilesystemAttachmentArgs) FilesystemAttachment {
 
161
        a := newFilesystemAttachment(args)
 
162
        f.Attachments_.Attachments_ = append(f.Attachments_.Attachments_, a)
 
163
        return a
 
164
}
 
165
 
 
166
// Validate implements Filesystem.
 
167
func (f *filesystem) Validate() error {
 
168
        if f.ID_ == "" {
 
169
                return errors.NotValidf("filesystem missing id")
 
170
        }
 
171
        if f.Size_ == 0 {
 
172
                return errors.NotValidf("filesystem %q missing size", f.ID_)
 
173
        }
 
174
        if f.Status_ == nil {
 
175
                return errors.NotValidf("filesystem %q missing status", f.ID_)
 
176
        }
 
177
        return nil
 
178
}
 
179
 
 
180
func importFilesystems(source map[string]interface{}) ([]*filesystem, error) {
 
181
        checker := versionedChecker("filesystems")
 
182
        coerced, err := checker.Coerce(source, nil)
 
183
        if err != nil {
 
184
                return nil, errors.Annotatef(err, "filesystems version schema check failed")
 
185
        }
 
186
        valid := coerced.(map[string]interface{})
 
187
 
 
188
        version := int(valid["version"].(int64))
 
189
        importFunc, ok := filesystemDeserializationFuncs[version]
 
190
        if !ok {
 
191
                return nil, errors.NotValidf("version %d", version)
 
192
        }
 
193
        sourceList := valid["filesystems"].([]interface{})
 
194
        return importFilesystemList(sourceList, importFunc)
 
195
}
 
196
 
 
197
func importFilesystemList(sourceList []interface{}, importFunc filesystemDeserializationFunc) ([]*filesystem, error) {
 
198
        result := make([]*filesystem, 0, len(sourceList))
 
199
        for i, value := range sourceList {
 
200
                source, ok := value.(map[string]interface{})
 
201
                if !ok {
 
202
                        return nil, errors.Errorf("unexpected value for filesystem %d, %T", i, value)
 
203
                }
 
204
                filesystem, err := importFunc(source)
 
205
                if err != nil {
 
206
                        return nil, errors.Annotatef(err, "filesystem %d", i)
 
207
                }
 
208
                result = append(result, filesystem)
 
209
        }
 
210
        return result, nil
 
211
}
 
212
 
 
213
type filesystemDeserializationFunc func(map[string]interface{}) (*filesystem, error)
 
214
 
 
215
var filesystemDeserializationFuncs = map[int]filesystemDeserializationFunc{
 
216
        1: importFilesystemV1,
 
217
}
 
218
 
 
219
func importFilesystemV1(source map[string]interface{}) (*filesystem, error) {
 
220
        fields := schema.Fields{
 
221
                "id":            schema.String(),
 
222
                "storage-id":    schema.String(),
 
223
                "volume-id":     schema.String(),
 
224
                "binding":       schema.String(),
 
225
                "provisioned":   schema.Bool(),
 
226
                "size":          schema.ForceUint(),
 
227
                "pool":          schema.String(),
 
228
                "filesystem-id": schema.String(),
 
229
                "status":        schema.StringMap(schema.Any()),
 
230
                "attachments":   schema.StringMap(schema.Any()),
 
231
        }
 
232
 
 
233
        defaults := schema.Defaults{
 
234
                "storage-id":    "",
 
235
                "volume-id":     "",
 
236
                "binding":       "",
 
237
                "pool":          "",
 
238
                "filesystem-id": "",
 
239
                "attachments":   schema.Omit,
 
240
        }
 
241
        addStatusHistorySchema(fields)
 
242
        checker := schema.FieldMap(fields, defaults)
 
243
 
 
244
        coerced, err := checker.Coerce(source, nil)
 
245
        if err != nil {
 
246
                return nil, errors.Annotatef(err, "filesystem v1 schema check failed")
 
247
        }
 
248
        valid := coerced.(map[string]interface{})
 
249
        // From here we know that the map returned from the schema coercion
 
250
        // contains fields of the right type.
 
251
        result := &filesystem{
 
252
                ID_:            valid["id"].(string),
 
253
                StorageID_:     valid["storage-id"].(string),
 
254
                VolumeID_:      valid["volume-id"].(string),
 
255
                Binding_:       valid["binding"].(string),
 
256
                Provisioned_:   valid["provisioned"].(bool),
 
257
                Size_:          valid["size"].(uint64),
 
258
                Pool_:          valid["pool"].(string),
 
259
                FilesystemID_:  valid["filesystem-id"].(string),
 
260
                StatusHistory_: newStatusHistory(),
 
261
        }
 
262
        if err := result.importStatusHistory(valid); err != nil {
 
263
                return nil, errors.Trace(err)
 
264
        }
 
265
 
 
266
        status, err := importStatus(valid["status"].(map[string]interface{}))
 
267
        if err != nil {
 
268
                return nil, errors.Trace(err)
 
269
        }
 
270
        result.Status_ = status
 
271
 
 
272
        attachments, err := importFilesystemAttachments(valid["attachments"].(map[string]interface{}))
 
273
        if err != nil {
 
274
                return nil, errors.Trace(err)
 
275
        }
 
276
        result.setAttachments(attachments)
 
277
 
 
278
        return result, nil
 
279
}
 
280
 
 
281
// FilesystemAttachmentArgs is an argument struct used to add information about the
 
282
// cloud instance to a Filesystem.
 
283
type FilesystemAttachmentArgs struct {
 
284
        Machine     names.MachineTag
 
285
        Provisioned bool
 
286
        ReadOnly    bool
 
287
        MountPoint  string
 
288
}
 
289
 
 
290
func newFilesystemAttachment(args FilesystemAttachmentArgs) *filesystemAttachment {
 
291
        return &filesystemAttachment{
 
292
                MachineID_:   args.Machine.Id(),
 
293
                Provisioned_: args.Provisioned,
 
294
                ReadOnly_:    args.ReadOnly,
 
295
                MountPoint_:  args.MountPoint,
 
296
        }
 
297
}
 
298
 
 
299
// Machine implements FilesystemAttachment
 
300
func (a *filesystemAttachment) Machine() names.MachineTag {
 
301
        return names.NewMachineTag(a.MachineID_)
 
302
}
 
303
 
 
304
// Provisioned implements FilesystemAttachment
 
305
func (a *filesystemAttachment) Provisioned() bool {
 
306
        return a.Provisioned_
 
307
}
 
308
 
 
309
// ReadOnly implements FilesystemAttachment
 
310
func (a *filesystemAttachment) ReadOnly() bool {
 
311
        return a.ReadOnly_
 
312
}
 
313
 
 
314
// MountPoint implements FilesystemAttachment
 
315
func (a *filesystemAttachment) MountPoint() string {
 
316
        return a.MountPoint_
 
317
}
 
318
 
 
319
func importFilesystemAttachments(source map[string]interface{}) ([]*filesystemAttachment, error) {
 
320
        checker := versionedChecker("attachments")
 
321
        coerced, err := checker.Coerce(source, nil)
 
322
        if err != nil {
 
323
                return nil, errors.Annotatef(err, "filesystem attachments version schema check failed")
 
324
        }
 
325
        valid := coerced.(map[string]interface{})
 
326
 
 
327
        version := int(valid["version"].(int64))
 
328
        importFunc, ok := filesystemAttachmentDeserializationFuncs[version]
 
329
        if !ok {
 
330
                return nil, errors.NotValidf("version %d", version)
 
331
        }
 
332
        sourceList := valid["attachments"].([]interface{})
 
333
        return importFilesystemAttachmentList(sourceList, importFunc)
 
334
}
 
335
 
 
336
func importFilesystemAttachmentList(sourceList []interface{}, importFunc filesystemAttachmentDeserializationFunc) ([]*filesystemAttachment, error) {
 
337
        result := make([]*filesystemAttachment, 0, len(sourceList))
 
338
        for i, value := range sourceList {
 
339
                source, ok := value.(map[string]interface{})
 
340
                if !ok {
 
341
                        return nil, errors.Errorf("unexpected value for filesystemAttachment %d, %T", i, value)
 
342
                }
 
343
                filesystemAttachment, err := importFunc(source)
 
344
                if err != nil {
 
345
                        return nil, errors.Annotatef(err, "filesystemAttachment %d", i)
 
346
                }
 
347
                result = append(result, filesystemAttachment)
 
348
        }
 
349
        return result, nil
 
350
}
 
351
 
 
352
type filesystemAttachmentDeserializationFunc func(map[string]interface{}) (*filesystemAttachment, error)
 
353
 
 
354
var filesystemAttachmentDeserializationFuncs = map[int]filesystemAttachmentDeserializationFunc{
 
355
        1: importFilesystemAttachmentV1,
 
356
}
 
357
 
 
358
func importFilesystemAttachmentV1(source map[string]interface{}) (*filesystemAttachment, error) {
 
359
        fields := schema.Fields{
 
360
                "machine-id":  schema.String(),
 
361
                "provisioned": schema.Bool(),
 
362
                "read-only":   schema.Bool(),
 
363
                "mount-point": schema.String(),
 
364
        }
 
365
        defaults := schema.Defaults{
 
366
                "mount-point": "",
 
367
        }
 
368
        checker := schema.FieldMap(fields, defaults)
 
369
 
 
370
        coerced, err := checker.Coerce(source, nil)
 
371
        if err != nil {
 
372
                return nil, errors.Annotatef(err, "filesystemAttachment v1 schema check failed")
 
373
        }
 
374
        valid := coerced.(map[string]interface{})
 
375
        // From here we know that the map returned from the schema coercion
 
376
        // contains fields of the right type.
 
377
 
 
378
        result := &filesystemAttachment{
 
379
                MachineID_:   valid["machine-id"].(string),
 
380
                Provisioned_: valid["provisioned"].(bool),
 
381
                ReadOnly_:    valid["read-only"].(bool),
 
382
                MountPoint_:  valid["mount-point"].(string),
 
383
        }
 
384
        return result, nil
 
385
}