blob: e38a61a150eff6262318d29a694eda1b4ec22119 [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 fabric struct {
13 // Add the controller in when we need to do things with the fabric.
14 // controller Controller
15
16 resourceURI string
17
18 id int
19 name string
20 classType string
21
22 vlans []*vlan
23}
24
25// ID implements Fabric.
26func (f *fabric) ID() int {
27 return f.id
28}
29
30// Name implements Fabric.
31func (f *fabric) Name() string {
32 return f.name
33}
34
35// ClassType implements Fabric.
36func (f *fabric) ClassType() string {
37 return f.classType
38}
39
40// VLANs implements Fabric.
41func (f *fabric) VLANs() []VLAN {
42 var result []VLAN
43 for _, v := range f.vlans {
44 result = append(result, v)
45 }
46 return result
47}
48
49func readFabrics(controllerVersion version.Number, source interface{}) ([]*fabric, error) {
50 checker := schema.List(schema.StringMap(schema.Any()))
51 coerced, err := checker.Coerce(source, nil)
52 if err != nil {
53 return nil, errors.Annotatef(err, "fabric base schema check failed")
54 }
55 valid := coerced.([]interface{})
56
57 var deserialisationVersion version.Number
58 for v := range fabricDeserializationFuncs {
59 if v.Compare(deserialisationVersion) > 0 && v.Compare(controllerVersion) <= 0 {
60 deserialisationVersion = v
61 }
62 }
63 if deserialisationVersion == version.Zero {
64 return nil, errors.Errorf("no fabric read func for version %s", controllerVersion)
65 }
66 readFunc := fabricDeserializationFuncs[deserialisationVersion]
67 return readFabricList(valid, readFunc)
68}
69
70// readFabricList expects the values of the sourceList to be string maps.
71func readFabricList(sourceList []interface{}, readFunc fabricDeserializationFunc) ([]*fabric, error) {
72 result := make([]*fabric, 0, len(sourceList))
73 for i, value := range sourceList {
74 source, ok := value.(map[string]interface{})
75 if !ok {
76 return nil, errors.Errorf("unexpected value for fabric %d, %T", i, value)
77 }
78 fabric, err := readFunc(source)
79 if err != nil {
80 return nil, errors.Annotatef(err, "fabric %d", i)
81 }
82 result = append(result, fabric)
83 }
84 return result, nil
85}
86
87type fabricDeserializationFunc func(map[string]interface{}) (*fabric, error)
88
89var fabricDeserializationFuncs = map[version.Number]fabricDeserializationFunc{
90 twoDotOh: fabric_2_0,
91}
92
93func fabric_2_0(source map[string]interface{}) (*fabric, error) {
94 fields := schema.Fields{
95 "resource_uri": schema.String(),
96 "id": schema.ForceInt(),
97 "name": schema.String(),
98 "class_type": schema.OneOf(schema.Nil(""), schema.String()),
99 "vlans": schema.List(schema.StringMap(schema.Any())),
100 }
101 checker := schema.FieldMap(fields, nil) // no defaults
102 coerced, err := checker.Coerce(source, nil)
103 if err != nil {
104 return nil, errors.Annotatef(err, "fabric 2.0 schema check failed")
105 }
106 valid := coerced.(map[string]interface{})
107 // From here we know that the map returned from the schema coercion
108 // contains fields of the right type.
109
110 vlans, err := readVLANList(valid["vlans"].([]interface{}), vlan_2_0)
111 if err != nil {
112 return nil, errors.Trace(err)
113 }
114
115 // Since the class_type is optional, we use the two part cast assignment. If
116 // the cast fails, then we get the default value we care about, which is the
117 // empty string.
118 classType, _ := valid["class_type"].(string)
119
120 result := &fabric{
121 resourceURI: valid["resource_uri"].(string),
122 id: valid["id"].(int),
123 name: valid["name"].(string),
124 classType: classType,
125 vlans: vlans,
126 }
127 return result, nil
128}