blob: ad04f9debe1c0087f4523a21603b6a709b85816b [file] [log] [blame]
David K. Bainbridge528b3182017-01-23 08:51:59 -08001// Copyright 2016 Canonical Ltd.
2// Licensed under the LGPLv3, see LICENCE file for details.
3
4package gomaasapi
5
6import (
7 "github.com/juju/errors"
8 "github.com/juju/schema"
9 "github.com/juju/version"
10)
11
12type blockdevice struct {
13 resourceURI string
14
15 id int
16 name string
17 model string
18 path string
19 usedFor string
20 tags []string
21
22 blockSize uint64
23 usedSize uint64
24 size uint64
25
26 partitions []*partition
27}
28
29// ID implements BlockDevice.
30func (b *blockdevice) ID() int {
31 return b.id
32}
33
34// Name implements BlockDevice.
35func (b *blockdevice) Name() string {
36 return b.name
37}
38
39// Model implements BlockDevice.
40func (b *blockdevice) Model() string {
41 return b.model
42}
43
44// Path implements BlockDevice.
45func (b *blockdevice) Path() string {
46 return b.path
47}
48
49// UsedFor implements BlockDevice.
50func (b *blockdevice) UsedFor() string {
51 return b.usedFor
52}
53
54// Tags implements BlockDevice.
55func (b *blockdevice) Tags() []string {
56 return b.tags
57}
58
59// BlockSize implements BlockDevice.
60func (b *blockdevice) BlockSize() uint64 {
61 return b.blockSize
62}
63
64// UsedSize implements BlockDevice.
65func (b *blockdevice) UsedSize() uint64 {
66 return b.usedSize
67}
68
69// Size implements BlockDevice.
70func (b *blockdevice) Size() uint64 {
71 return b.size
72}
73
74// Partitions implements BlockDevice.
75func (b *blockdevice) Partitions() []Partition {
76 result := make([]Partition, len(b.partitions))
77 for i, v := range b.partitions {
78 result[i] = v
79 }
80 return result
81}
82
83func readBlockDevices(controllerVersion version.Number, source interface{}) ([]*blockdevice, error) {
84 checker := schema.List(schema.StringMap(schema.Any()))
85 coerced, err := checker.Coerce(source, nil)
86 if err != nil {
87 return nil, WrapWithDeserializationError(err, "blockdevice base schema check failed")
88 }
89 valid := coerced.([]interface{})
90
91 var deserialisationVersion version.Number
92 for v := range blockdeviceDeserializationFuncs {
93 if v.Compare(deserialisationVersion) > 0 && v.Compare(controllerVersion) <= 0 {
94 deserialisationVersion = v
95 }
96 }
97 if deserialisationVersion == version.Zero {
98 return nil, NewUnsupportedVersionError("no blockdevice read func for version %s", controllerVersion)
99 }
100 readFunc := blockdeviceDeserializationFuncs[deserialisationVersion]
101 return readBlockDeviceList(valid, readFunc)
102}
103
104// readBlockDeviceList expects the values of the sourceList to be string maps.
105func readBlockDeviceList(sourceList []interface{}, readFunc blockdeviceDeserializationFunc) ([]*blockdevice, error) {
106 result := make([]*blockdevice, 0, len(sourceList))
107 for i, value := range sourceList {
108 source, ok := value.(map[string]interface{})
109 if !ok {
110 return nil, NewDeserializationError("unexpected value for blockdevice %d, %T", i, value)
111 }
112 blockdevice, err := readFunc(source)
113 if err != nil {
114 return nil, errors.Annotatef(err, "blockdevice %d", i)
115 }
116 result = append(result, blockdevice)
117 }
118 return result, nil
119}
120
121type blockdeviceDeserializationFunc func(map[string]interface{}) (*blockdevice, error)
122
123var blockdeviceDeserializationFuncs = map[version.Number]blockdeviceDeserializationFunc{
124 twoDotOh: blockdevice_2_0,
125}
126
127func blockdevice_2_0(source map[string]interface{}) (*blockdevice, error) {
128 fields := schema.Fields{
129 "resource_uri": schema.String(),
130
131 "id": schema.ForceInt(),
132 "name": schema.String(),
133 "model": schema.OneOf(schema.Nil(""), schema.String()),
134 "path": schema.String(),
135 "used_for": schema.String(),
136 "tags": schema.List(schema.String()),
137
138 "block_size": schema.ForceUint(),
139 "used_size": schema.ForceUint(),
140 "size": schema.ForceUint(),
141
142 "partitions": schema.List(schema.StringMap(schema.Any())),
143 }
144 checker := schema.FieldMap(fields, nil)
145 coerced, err := checker.Coerce(source, nil)
146 if err != nil {
147 return nil, WrapWithDeserializationError(err, "blockdevice 2.0 schema check failed")
148 }
149 valid := coerced.(map[string]interface{})
150 // From here we know that the map returned from the schema coercion
151 // contains fields of the right type.
152
153 partitions, err := readPartitionList(valid["partitions"].([]interface{}), partition_2_0)
154 if err != nil {
155 return nil, errors.Trace(err)
156 }
157
158 model, _ := valid["model"].(string)
159 result := &blockdevice{
160 resourceURI: valid["resource_uri"].(string),
161
162 id: valid["id"].(int),
163 name: valid["name"].(string),
164 model: model,
165 path: valid["path"].(string),
166 usedFor: valid["used_for"].(string),
167 tags: convertToStringSlice(valid["tags"]),
168
169 blockSize: valid["block_size"].(uint64),
170 usedSize: valid["used_size"].(uint64),
171 size: valid["size"].(uint64),
172
173 partitions: partitions,
174 }
175 return result, nil
176}