1
// Copyright 2016 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
7
"github.com/juju/errors"
8
"github.com/juju/schema"
11
type versionedOpenedPorts struct {
12
Version int `yaml:"version"`
13
OpenedPorts_ []*openedPorts `yaml:"opened-ports"`
16
type openedPorts struct {
17
SubnetID_ string `yaml:"subnet-id"`
18
OpenedPorts_ *portRanges `yaml:"opened-ports"`
21
// OpenedPortsArgs is an argument struct used to add a set of opened port ranges
23
type OpenedPortsArgs struct {
25
OpenedPorts []PortRangeArgs
28
func newOpenedPorts(args OpenedPortsArgs) *openedPorts {
29
result := &openedPorts{SubnetID_: args.SubnetID}
30
result.setOpenedPorts(nil)
31
for _, pargs := range args.OpenedPorts {
32
result.OpenedPorts_.add(pargs)
37
// SubnetID implements OpenedPorts.
38
func (p *openedPorts) SubnetID() string {
42
// OpenPorts implements OpenedPorts.
43
func (p *openedPorts) OpenPorts() []PortRange {
44
var result []PortRange
45
for _, pr := range p.OpenedPorts_.OpenedPorts_ {
46
result = append(result, pr)
51
func (p *openedPorts) setOpenedPorts(ports []*portRange) {
52
p.OpenedPorts_ = &portRanges{
58
func importOpenedPorts(source map[string]interface{}) ([]*openedPorts, error) {
59
checker := versionedChecker("opened-ports")
60
coerced, err := checker.Coerce(source, nil)
62
return nil, errors.Annotatef(err, "opened-ports version schema check failed")
64
valid := coerced.(map[string]interface{})
66
version := int(valid["version"].(int64))
67
importFunc, ok := openedPortsDeserializationFuncs[version]
69
return nil, errors.NotValidf("version %d", version)
71
sourceList := valid["opened-ports"].([]interface{})
72
return importOpenedPortsList(sourceList, importFunc)
75
func importOpenedPortsList(sourceList []interface{}, importFunc openedPortsDeserializationFunc) ([]*openedPorts, error) {
76
result := make([]*openedPorts, 0, len(sourceList))
77
for i, value := range sourceList {
78
source, ok := value.(map[string]interface{})
80
return nil, errors.Errorf("unexpected value for opened-ports %d, %T", i, value)
82
ports, err := importFunc(source)
84
return nil, errors.Annotatef(err, "opened-ports %d", i)
86
result = append(result, ports)
91
type openedPortsDeserializationFunc func(map[string]interface{}) (*openedPorts, error)
93
var openedPortsDeserializationFuncs = map[int]openedPortsDeserializationFunc{
94
1: importOpenedPortsV1,
97
func importOpenedPortsV1(source map[string]interface{}) (*openedPorts, error) {
98
fields := schema.Fields{
99
"subnet-id": schema.String(),
100
"opened-ports": schema.StringMap(schema.Any()),
103
checker := schema.FieldMap(fields, nil) // no defaults
105
coerced, err := checker.Coerce(source, nil)
107
return nil, errors.Annotatef(err, "opened-ports v1 schema check failed")
109
valid := coerced.(map[string]interface{})
110
// From here we know that the map returned from the schema coercion
111
// contains fields of the right type.
113
ports, err := importPortRanges(valid["opened-ports"].(map[string]interface{}))
115
return nil, errors.Trace(err)
117
result := &openedPorts{
118
SubnetID_: valid["subnet-id"].(string),
120
result.setOpenedPorts(ports)
124
type portRanges struct {
125
Version int `yaml:"version"`
126
OpenedPorts_ []*portRange `yaml:"opened-ports"`
129
type portRange struct {
130
UnitName_ string `yaml:"unit-name"`
131
FromPort_ int `yaml:"from-port"`
132
ToPort_ int `yaml:"to-port"`
133
Protocol_ string `yaml:"protocol"`
136
// PortRangeArgs is an argument struct used to create a PortRange. This is only
137
// done as part of creating OpenedPorts for a Machine.
138
type PortRangeArgs struct {
145
func newPortRange(args PortRangeArgs) *portRange {
147
UnitName_: args.UnitName,
148
FromPort_: args.FromPort,
149
ToPort_: args.ToPort,
150
Protocol_: args.Protocol,
154
func (p *portRanges) add(args PortRangeArgs) {
155
p.OpenedPorts_ = append(p.OpenedPorts_, newPortRange(args))
158
// UnitName implements PortRange.
159
func (p *portRange) UnitName() string {
163
// FromPort implements PortRange.
164
func (p *portRange) FromPort() int {
168
// ToPort implements PortRange.
169
func (p *portRange) ToPort() int {
173
// Protocol implements PortRange.
174
func (p *portRange) Protocol() string {
178
func importPortRanges(source map[string]interface{}) ([]*portRange, error) {
179
checker := versionedChecker("opened-ports")
180
coerced, err := checker.Coerce(source, nil)
182
return nil, errors.Annotatef(err, "port-range version schema check failed")
184
valid := coerced.(map[string]interface{})
186
version := int(valid["version"].(int64))
187
importFunc, ok := portRangeDeserializationFuncs[version]
189
return nil, errors.NotValidf("version %d", version)
191
sourceList := valid["opened-ports"].([]interface{})
192
return importPortRangeList(sourceList, importFunc)
195
func importPortRangeList(sourceList []interface{}, importFunc portRangeDeserializationFunc) ([]*portRange, error) {
196
result := make([]*portRange, 0, len(sourceList))
197
for i, value := range sourceList {
198
source, ok := value.(map[string]interface{})
200
return nil, errors.Errorf("unexpected value for port-range %d, %T", i, value)
202
ports, err := importFunc(source)
204
return nil, errors.Annotatef(err, "port-range %d", i)
206
result = append(result, ports)
211
type portRangeDeserializationFunc func(map[string]interface{}) (*portRange, error)
213
var portRangeDeserializationFuncs = map[int]portRangeDeserializationFunc{
214
1: importPortRangeV1,
217
func importPortRangeV1(source map[string]interface{}) (*portRange, error) {
218
fields := schema.Fields{
219
"unit-name": schema.String(),
220
"from-port": schema.Int(),
221
"to-port": schema.Int(),
222
"protocol": schema.String(),
225
checker := schema.FieldMap(fields, nil) // no defaults
227
coerced, err := checker.Coerce(source, nil)
229
return nil, errors.Annotatef(err, "port-range v1 schema check failed")
231
valid := coerced.(map[string]interface{})
232
// From here we know that the map returned from the schema coercion
233
// contains fields of the right type.
236
UnitName_: valid["unit-name"].(string),
237
FromPort_: int(valid["from-port"].(int64)),
238
ToPort_: int(valid["to-port"].(int64)),
239
Protocol_: valid["protocol"].(string),