~juju-qa/ubuntu/xenial/juju/xenial-2.0-beta3

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/core/description/relation.go

  • Committer: Martin Packman
  • Date: 2016-03-30 19:31:08 UTC
  • mfrom: (1.1.41)
  • Revision ID: martin.packman@canonical.com-20160330193108-h9iz3ak334uk0z5r
Merge new upstream source 2.0~beta3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2016 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package description
 
5
 
 
6
import (
 
7
        "github.com/juju/errors"
 
8
        "github.com/juju/schema"
 
9
        "github.com/juju/utils/set"
 
10
)
 
11
 
 
12
type relations struct {
 
13
        Version    int         `yaml:"version"`
 
14
        Relations_ []*relation `yaml:"relations"`
 
15
}
 
16
 
 
17
type relation struct {
 
18
        Id_        int        `yaml:"id"`
 
19
        Key_       string     `yaml:"key"`
 
20
        Endpoints_ *endpoints `yaml:"endpoints"`
 
21
}
 
22
 
 
23
// RelationArgs is an argument struct used to specify a relation.
 
24
type RelationArgs struct {
 
25
        Id  int
 
26
        Key string
 
27
}
 
28
 
 
29
func newRelation(args RelationArgs) *relation {
 
30
        relation := &relation{
 
31
                Id_:  args.Id,
 
32
                Key_: args.Key,
 
33
        }
 
34
        relation.setEndpoints(nil)
 
35
        return relation
 
36
}
 
37
 
 
38
// Id implements Relation.
 
39
func (r *relation) Id() int {
 
40
        return r.Id_
 
41
}
 
42
 
 
43
// Key implements Relation.
 
44
func (r *relation) Key() string {
 
45
        return r.Key_
 
46
}
 
47
 
 
48
// Endpoints implements Relation.
 
49
func (r *relation) Endpoints() []Endpoint {
 
50
        result := make([]Endpoint, len(r.Endpoints_.Endpoints_))
 
51
        for i, ep := range r.Endpoints_.Endpoints_ {
 
52
                result[i] = ep
 
53
        }
 
54
        return result
 
55
}
 
56
 
 
57
// AddEndpoint implements Relation.
 
58
func (r *relation) AddEndpoint(args EndpointArgs) Endpoint {
 
59
        ep := newEndpoint(args)
 
60
        r.Endpoints_.Endpoints_ = append(r.Endpoints_.Endpoints_, ep)
 
61
        return ep
 
62
}
 
63
 
 
64
func (r *relation) setEndpoints(endpointList []*endpoint) {
 
65
        r.Endpoints_ = &endpoints{
 
66
                Version:    1,
 
67
                Endpoints_: endpointList,
 
68
        }
 
69
}
 
70
 
 
71
func importRelations(source map[string]interface{}) ([]*relation, error) {
 
72
        checker := versionedChecker("relations")
 
73
        coerced, err := checker.Coerce(source, nil)
 
74
        if err != nil {
 
75
                return nil, errors.Annotatef(err, "relations version schema check failed")
 
76
        }
 
77
        valid := coerced.(map[string]interface{})
 
78
 
 
79
        version := int(valid["version"].(int64))
 
80
        importFunc, ok := relationDeserializationFuncs[version]
 
81
        if !ok {
 
82
                return nil, errors.NotValidf("version %d", version)
 
83
        }
 
84
        relationList := valid["relations"].([]interface{})
 
85
        return importRelationList(relationList, importFunc)
 
86
}
 
87
 
 
88
func importRelationList(sourceList []interface{}, importFunc relationDeserializationFunc) ([]*relation, error) {
 
89
        result := make([]*relation, 0, len(sourceList))
 
90
        for i, value := range sourceList {
 
91
                source, ok := value.(map[string]interface{})
 
92
                if !ok {
 
93
                        return nil, errors.Errorf("unexpected value for relation %d, %T", i, value)
 
94
                }
 
95
                relation, err := importFunc(source)
 
96
                if err != nil {
 
97
                        return nil, errors.Annotatef(err, "relation %d", i)
 
98
                }
 
99
                result = append(result, relation)
 
100
        }
 
101
        return result, nil
 
102
}
 
103
 
 
104
type relationDeserializationFunc func(map[string]interface{}) (*relation, error)
 
105
 
 
106
var relationDeserializationFuncs = map[int]relationDeserializationFunc{
 
107
        1: importRelationV1,
 
108
}
 
109
 
 
110
func importRelationV1(source map[string]interface{}) (*relation, error) {
 
111
        fields := schema.Fields{
 
112
                "id":        schema.Int(),
 
113
                "key":       schema.String(),
 
114
                "endpoints": schema.StringMap(schema.Any()),
 
115
        }
 
116
 
 
117
        checker := schema.FieldMap(fields, nil) // no defaults
 
118
 
 
119
        coerced, err := checker.Coerce(source, nil)
 
120
        if err != nil {
 
121
                return nil, errors.Annotatef(err, "relation v1 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
        result := &relation{
 
127
                Id_:  int(valid["id"].(int64)),
 
128
                Key_: valid["key"].(string),
 
129
        }
 
130
 
 
131
        endpoints, err := importEndpoints(valid["endpoints"].(map[string]interface{}))
 
132
        if err != nil {
 
133
                return nil, errors.Trace(err)
 
134
        }
 
135
        result.setEndpoints(endpoints)
 
136
 
 
137
        return result, nil
 
138
}
 
139
 
 
140
type endpoints struct {
 
141
        Version    int         `yaml:"version"`
 
142
        Endpoints_ []*endpoint `yaml:"endpoints"`
 
143
}
 
144
 
 
145
type endpoint struct {
 
146
        ServiceName_ string `yaml:"service-name"`
 
147
        Name_        string `yaml:"name"`
 
148
        Role_        string `yaml:"role"`
 
149
        Interface_   string `yaml:"interface"`
 
150
        Optional_    bool   `yaml:"optional"`
 
151
        Limit_       int    `yaml:"limit"`
 
152
        Scope_       string `yaml:"scope"`
 
153
 
 
154
        UnitSettings_ map[string]map[string]interface{} `yaml:"unit-settings"`
 
155
}
 
156
 
 
157
// EndpointArgs is an argument struct used to specify a relation.
 
158
type EndpointArgs struct {
 
159
        ServiceName string
 
160
        Name        string
 
161
        Role        string
 
162
        Interface   string
 
163
        Optional    bool
 
164
        Limit       int
 
165
        Scope       string
 
166
}
 
167
 
 
168
func newEndpoint(args EndpointArgs) *endpoint {
 
169
        return &endpoint{
 
170
                ServiceName_:  args.ServiceName,
 
171
                Name_:         args.Name,
 
172
                Role_:         args.Role,
 
173
                Interface_:    args.Interface,
 
174
                Optional_:     args.Optional,
 
175
                Limit_:        args.Limit,
 
176
                Scope_:        args.Scope,
 
177
                UnitSettings_: make(map[string]map[string]interface{}),
 
178
        }
 
179
}
 
180
 
 
181
func (e *endpoint) unitNames() set.Strings {
 
182
        result := set.NewStrings()
 
183
        for key := range e.UnitSettings_ {
 
184
                result.Add(key)
 
185
        }
 
186
        return result
 
187
}
 
188
 
 
189
// ServiceName implements Endpoint.
 
190
func (e *endpoint) ServiceName() string {
 
191
        return e.ServiceName_
 
192
}
 
193
 
 
194
// Name implements Endpoint.
 
195
func (e *endpoint) Name() string {
 
196
        return e.Name_
 
197
}
 
198
 
 
199
// Role implements Endpoint.
 
200
func (e *endpoint) Role() string {
 
201
        return e.Role_
 
202
}
 
203
 
 
204
// Interface implements Endpoint.
 
205
func (e *endpoint) Interface() string {
 
206
        return e.Interface_
 
207
}
 
208
 
 
209
// Optional implements Endpoint.
 
210
func (e *endpoint) Optional() bool {
 
211
        return e.Optional_
 
212
}
 
213
 
 
214
// Limit implements Endpoint.
 
215
func (e *endpoint) Limit() int {
 
216
        return e.Limit_
 
217
}
 
218
 
 
219
// Scope implements Endpoint.
 
220
func (e *endpoint) Scope() string {
 
221
        return e.Scope_
 
222
}
 
223
 
 
224
// UnitCount implements Endpoint.
 
225
func (e *endpoint) UnitCount() int {
 
226
        return len(e.UnitSettings_)
 
227
}
 
228
 
 
229
// Settings implements Endpoint.
 
230
func (e *endpoint) Settings(unitName string) map[string]interface{} {
 
231
        return e.UnitSettings_[unitName]
 
232
}
 
233
 
 
234
// SetUnitSettings implements Endpoint.
 
235
func (e *endpoint) SetUnitSettings(unitName string, settings map[string]interface{}) {
 
236
        e.UnitSettings_[unitName] = settings
 
237
}
 
238
 
 
239
func importEndpoints(source map[string]interface{}) ([]*endpoint, error) {
 
240
        checker := versionedChecker("endpoints")
 
241
        coerced, err := checker.Coerce(source, nil)
 
242
        if err != nil {
 
243
                return nil, errors.Annotatef(err, "endpoints version schema check failed")
 
244
        }
 
245
        valid := coerced.(map[string]interface{})
 
246
 
 
247
        version := int(valid["version"].(int64))
 
248
        importFunc, ok := endpointDeserializationFuncs[version]
 
249
        if !ok {
 
250
                return nil, errors.NotValidf("version %d", version)
 
251
        }
 
252
        endpointList := valid["endpoints"].([]interface{})
 
253
        return importEndpointList(endpointList, importFunc)
 
254
}
 
255
 
 
256
func importEndpointList(sourceList []interface{}, importFunc endpointDeserializationFunc) ([]*endpoint, error) {
 
257
        result := make([]*endpoint, 0, len(sourceList))
 
258
        for i, value := range sourceList {
 
259
                source, ok := value.(map[string]interface{})
 
260
                if !ok {
 
261
                        return nil, errors.Errorf("unexpected value for endpoint %d, %T", i, value)
 
262
                }
 
263
                service, err := importFunc(source)
 
264
                if err != nil {
 
265
                        return nil, errors.Annotatef(err, "endpoint %d", i)
 
266
                }
 
267
                result = append(result, service)
 
268
        }
 
269
        return result, nil
 
270
}
 
271
 
 
272
type endpointDeserializationFunc func(map[string]interface{}) (*endpoint, error)
 
273
 
 
274
var endpointDeserializationFuncs = map[int]endpointDeserializationFunc{
 
275
        1: importEndpointV1,
 
276
}
 
277
 
 
278
func importEndpointV1(source map[string]interface{}) (*endpoint, error) {
 
279
        fields := schema.Fields{
 
280
                "service-name":  schema.String(),
 
281
                "name":          schema.String(),
 
282
                "role":          schema.String(),
 
283
                "interface":     schema.String(),
 
284
                "optional":      schema.Bool(),
 
285
                "limit":         schema.Int(),
 
286
                "scope":         schema.String(),
 
287
                "unit-settings": schema.StringMap(schema.StringMap(schema.Any())),
 
288
        }
 
289
 
 
290
        checker := schema.FieldMap(fields, nil) // No defaults.
 
291
 
 
292
        coerced, err := checker.Coerce(source, nil)
 
293
        if err != nil {
 
294
                return nil, errors.Annotatef(err, "endpoint v1 schema check failed")
 
295
        }
 
296
        valid := coerced.(map[string]interface{})
 
297
        // From here we know that the map returned from the schema coercion
 
298
        // contains fields of the right type.
 
299
 
 
300
        result := &endpoint{
 
301
                ServiceName_:  valid["service-name"].(string),
 
302
                Name_:         valid["name"].(string),
 
303
                Role_:         valid["role"].(string),
 
304
                Interface_:    valid["interface"].(string),
 
305
                Optional_:     valid["optional"].(bool),
 
306
                Limit_:        int(valid["limit"].(int64)),
 
307
                Scope_:        valid["scope"].(string),
 
308
                UnitSettings_: make(map[string]map[string]interface{}),
 
309
        }
 
310
 
 
311
        for unitname, settings := range valid["unit-settings"].(map[string]interface{}) {
 
312
                result.UnitSettings_[unitname] = settings.(map[string]interface{})
 
313
        }
 
314
 
 
315
        return result, nil
 
316
}