David K. Bainbridge | 528b318 | 2017-01-23 08:51:59 -0800 | [diff] [blame] | 1 | // Copyright 2016 Canonical Ltd. |
| 2 | // Licensed under the LGPLv3, see LICENCE file for details. |
| 3 | |
| 4 | package gomaasapi |
| 5 | |
| 6 | import ( |
| 7 | "github.com/juju/errors" |
| 8 | "github.com/juju/schema" |
| 9 | "github.com/juju/version" |
| 10 | ) |
| 11 | |
| 12 | type partition struct { |
| 13 | resourceURI string |
| 14 | |
| 15 | id int |
| 16 | path string |
| 17 | uuid string |
| 18 | |
| 19 | usedFor string |
| 20 | size uint64 |
| 21 | |
| 22 | filesystem *filesystem |
| 23 | } |
| 24 | |
| 25 | // ID implements Partition. |
| 26 | func (p *partition) ID() int { |
| 27 | return p.id |
| 28 | } |
| 29 | |
| 30 | // Path implements Partition. |
| 31 | func (p *partition) Path() string { |
| 32 | return p.path |
| 33 | } |
| 34 | |
| 35 | // FileSystem implements Partition. |
| 36 | func (p *partition) FileSystem() FileSystem { |
| 37 | if p.filesystem == nil { |
| 38 | return nil |
| 39 | } |
| 40 | return p.filesystem |
| 41 | } |
| 42 | |
| 43 | // UUID implements Partition. |
| 44 | func (p *partition) UUID() string { |
| 45 | return p.uuid |
| 46 | } |
| 47 | |
| 48 | // UsedFor implements Partition. |
| 49 | func (p *partition) UsedFor() string { |
| 50 | return p.usedFor |
| 51 | } |
| 52 | |
| 53 | // Size implements Partition. |
| 54 | func (p *partition) Size() uint64 { |
| 55 | return p.size |
| 56 | } |
| 57 | |
| 58 | func readPartitions(controllerVersion version.Number, source interface{}) ([]*partition, error) { |
| 59 | checker := schema.List(schema.StringMap(schema.Any())) |
| 60 | coerced, err := checker.Coerce(source, nil) |
| 61 | if err != nil { |
| 62 | return nil, WrapWithDeserializationError(err, "partition base schema check failed") |
| 63 | } |
| 64 | valid := coerced.([]interface{}) |
| 65 | |
| 66 | var deserialisationVersion version.Number |
| 67 | for v := range partitionDeserializationFuncs { |
| 68 | if v.Compare(deserialisationVersion) > 0 && v.Compare(controllerVersion) <= 0 { |
| 69 | deserialisationVersion = v |
| 70 | } |
| 71 | } |
| 72 | if deserialisationVersion == version.Zero { |
| 73 | return nil, NewUnsupportedVersionError("no partition read func for version %s", controllerVersion) |
| 74 | } |
| 75 | readFunc := partitionDeserializationFuncs[deserialisationVersion] |
| 76 | return readPartitionList(valid, readFunc) |
| 77 | } |
| 78 | |
| 79 | // readPartitionList expects the values of the sourceList to be string maps. |
| 80 | func readPartitionList(sourceList []interface{}, readFunc partitionDeserializationFunc) ([]*partition, error) { |
| 81 | result := make([]*partition, 0, len(sourceList)) |
| 82 | for i, value := range sourceList { |
| 83 | source, ok := value.(map[string]interface{}) |
| 84 | if !ok { |
| 85 | return nil, NewDeserializationError("unexpected value for partition %d, %T", i, value) |
| 86 | } |
| 87 | partition, err := readFunc(source) |
| 88 | if err != nil { |
| 89 | return nil, errors.Annotatef(err, "partition %d", i) |
| 90 | } |
| 91 | result = append(result, partition) |
| 92 | } |
| 93 | return result, nil |
| 94 | } |
| 95 | |
| 96 | type partitionDeserializationFunc func(map[string]interface{}) (*partition, error) |
| 97 | |
| 98 | var partitionDeserializationFuncs = map[version.Number]partitionDeserializationFunc{ |
| 99 | twoDotOh: partition_2_0, |
| 100 | } |
| 101 | |
| 102 | func partition_2_0(source map[string]interface{}) (*partition, error) { |
| 103 | fields := schema.Fields{ |
| 104 | "resource_uri": schema.String(), |
| 105 | |
| 106 | "id": schema.ForceInt(), |
| 107 | "path": schema.String(), |
| 108 | "uuid": schema.OneOf(schema.Nil(""), schema.String()), |
| 109 | |
| 110 | "used_for": schema.String(), |
| 111 | "size": schema.ForceUint(), |
| 112 | |
| 113 | "filesystem": schema.OneOf(schema.Nil(""), schema.StringMap(schema.Any())), |
| 114 | } |
| 115 | defaults := schema.Defaults{ |
| 116 | "uuid": "", |
| 117 | } |
| 118 | checker := schema.FieldMap(fields, defaults) |
| 119 | coerced, err := checker.Coerce(source, nil) |
| 120 | if err != nil { |
| 121 | return nil, WrapWithDeserializationError(err, "partition 2.0 schema check failed") |
| 122 | } |
| 123 | valid := coerced.(map[string]interface{}) |
| 124 | // From here we know that the map returned from the schema coercion |
| 125 | // contains fields of the right type. |
| 126 | |
| 127 | var filesystem *filesystem |
| 128 | if fsSource := valid["filesystem"]; fsSource != nil { |
| 129 | filesystem, err = filesystem2_0(fsSource.(map[string]interface{})) |
| 130 | if err != nil { |
| 131 | return nil, errors.Trace(err) |
| 132 | } |
| 133 | } |
| 134 | uuid, _ := valid["uuid"].(string) |
| 135 | result := &partition{ |
| 136 | resourceURI: valid["resource_uri"].(string), |
| 137 | id: valid["id"].(int), |
| 138 | path: valid["path"].(string), |
| 139 | uuid: uuid, |
| 140 | usedFor: valid["used_for"].(string), |
| 141 | size: valid["size"].(uint64), |
| 142 | filesystem: filesystem, |
| 143 | } |
| 144 | return result, nil |
| 145 | } |