1
// Copyright 2016 Canonical Ltd.
2
// Licensed under the LGPLv3, see LICENCE file for details.
7
"github.com/juju/errors"
8
"github.com/juju/schema"
9
"github.com/juju/version"
19
// NOTE: not using lowercase L as the receiver as it is a horrible idea.
22
// ID implements Link.
23
func (k *link) ID() int {
27
// Mode implements Link.
28
func (k *link) Mode() string {
32
// Subnet implements Link.
33
func (k *link) Subnet() Subnet {
40
// IPAddress implements Link.
41
func (k *link) IPAddress() string {
45
func readLinks(controllerVersion version.Number, source interface{}) ([]*link, error) {
46
checker := schema.List(schema.StringMap(schema.Any()))
47
coerced, err := checker.Coerce(source, nil)
49
return nil, WrapWithDeserializationError(err, "link base schema check failed")
51
valid := coerced.([]interface{})
53
var deserialisationVersion version.Number
54
for v := range linkDeserializationFuncs {
55
if v.Compare(deserialisationVersion) > 0 && v.Compare(controllerVersion) <= 0 {
56
deserialisationVersion = v
59
if deserialisationVersion == version.Zero {
60
return nil, NewUnsupportedVersionError("no link read func for version %s", controllerVersion)
62
readFunc := linkDeserializationFuncs[deserialisationVersion]
63
return readLinkList(valid, readFunc)
66
// readLinkList expects the values of the sourceList to be string maps.
67
func readLinkList(sourceList []interface{}, readFunc linkDeserializationFunc) ([]*link, error) {
68
result := make([]*link, 0, len(sourceList))
69
for i, value := range sourceList {
70
source, ok := value.(map[string]interface{})
72
return nil, NewDeserializationError("unexpected value for link %d, %T", i, value)
74
link, err := readFunc(source)
76
return nil, errors.Annotatef(err, "link %d", i)
78
result = append(result, link)
83
type linkDeserializationFunc func(map[string]interface{}) (*link, error)
85
var linkDeserializationFuncs = map[version.Number]linkDeserializationFunc{
89
func link_2_0(source map[string]interface{}) (*link, error) {
90
fields := schema.Fields{
91
"id": schema.ForceInt(),
92
"mode": schema.String(),
93
"subnet": schema.StringMap(schema.Any()),
94
"ip_address": schema.String(),
96
defaults := schema.Defaults{
98
"subnet": schema.Omit,
100
checker := schema.FieldMap(fields, defaults)
101
coerced, err := checker.Coerce(source, nil)
103
return nil, WrapWithDeserializationError(err, "link 2.0 schema check failed")
105
valid := coerced.(map[string]interface{})
106
// From here we know that the map returned from the schema coercion
107
// contains fields of the right type.
110
if value, ok := valid["subnet"]; ok {
111
subnet, err = subnet_2_0(value.(map[string]interface{}))
113
return nil, errors.Trace(err)
118
id: valid["id"].(int),
119
mode: valid["mode"].(string),
121
ipAddress: valid["ip_address"].(string),