blob: 619a2a9b2e6c2bec97d6287bb50ae617ae76bff1 [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 "strings"
8
9 "github.com/juju/errors"
10 "github.com/juju/schema"
11 "github.com/juju/utils/set"
12 "github.com/juju/version"
13)
14
15type bootResource struct {
16 // Add the controller in when we need to do things with the bootResource.
17 // controller Controller
18
19 resourceURI string
20
21 id int
22 name string
23 type_ string
24 architecture string
25 subArches string
26 kernelFlavor string
27}
28
29// ID implements BootResource.
30func (b *bootResource) ID() int {
31 return b.id
32}
33
34// Name implements BootResource.
35func (b *bootResource) Name() string {
36 return b.name
37}
38
39// Name implements BootResource.
40func (b *bootResource) Type() string {
41 return b.type_
42}
43
44// Name implements BootResource.
45func (b *bootResource) Architecture() string {
46 return b.architecture
47}
48
49// SubArchitectures implements BootResource.
50func (b *bootResource) SubArchitectures() set.Strings {
51 return set.NewStrings(strings.Split(b.subArches, ",")...)
52}
53
54// KernelFlavor implements BootResource.
55func (b *bootResource) KernelFlavor() string {
56 return b.kernelFlavor
57}
58
59func readBootResources(controllerVersion version.Number, source interface{}) ([]*bootResource, error) {
60 checker := schema.List(schema.StringMap(schema.Any()))
61 coerced, err := checker.Coerce(source, nil)
62 if err != nil {
63 return nil, WrapWithDeserializationError(err, "boot resource base schema check failed")
64 }
65 valid := coerced.([]interface{})
66
67 var deserialisationVersion version.Number
68 for v := range bootResourceDeserializationFuncs {
69 if v.Compare(deserialisationVersion) > 0 && v.Compare(controllerVersion) <= 0 {
70 deserialisationVersion = v
71 }
72 }
73 if deserialisationVersion == version.Zero {
74 return nil, NewUnsupportedVersionError("no boot resource read func for version %s", controllerVersion)
75 }
76 readFunc := bootResourceDeserializationFuncs[deserialisationVersion]
77 return readBootResourceList(valid, readFunc)
78}
79
80// readBootResourceList expects the values of the sourceList to be string maps.
81func readBootResourceList(sourceList []interface{}, readFunc bootResourceDeserializationFunc) ([]*bootResource, error) {
82 result := make([]*bootResource, 0, len(sourceList))
83 for i, value := range sourceList {
84 source, ok := value.(map[string]interface{})
85 if !ok {
86 return nil, NewDeserializationError("unexpected value for boot resource %d, %T", i, value)
87 }
88 bootResource, err := readFunc(source)
89 if err != nil {
90 return nil, errors.Annotatef(err, "boot resource %d", i)
91 }
92 result = append(result, bootResource)
93 }
94 return result, nil
95}
96
97type bootResourceDeserializationFunc func(map[string]interface{}) (*bootResource, error)
98
99var bootResourceDeserializationFuncs = map[version.Number]bootResourceDeserializationFunc{
100 twoDotOh: bootResource_2_0,
101}
102
103func bootResource_2_0(source map[string]interface{}) (*bootResource, error) {
104 fields := schema.Fields{
105 "resource_uri": schema.String(),
106 "id": schema.ForceInt(),
107 "name": schema.String(),
108 "type": schema.String(),
109 "architecture": schema.String(),
110 "subarches": schema.String(),
111 "kflavor": schema.String(),
112 }
113 defaults := schema.Defaults{
114 "subarches": "",
115 "kflavor": "",
116 }
117 checker := schema.FieldMap(fields, defaults)
118 coerced, err := checker.Coerce(source, nil)
119 if err != nil {
120 return nil, WrapWithDeserializationError(err, "boot resource 2.0 schema check failed")
121 }
122 valid := coerced.(map[string]interface{})
123 // From here we know that the map returned from the schema coercion
124 // contains fields of the right type.
125
126 result := &bootResource{
127 resourceURI: valid["resource_uri"].(string),
128 id: valid["id"].(int),
129 name: valid["name"].(string),
130 type_: valid["type"].(string),
131 architecture: valid["architecture"].(string),
132 subArches: valid["subarches"].(string),
133 kernelFlavor: valid["kflavor"].(string),
134 }
135 return result, nil
136}