/
subnets.go
162 lines (136 loc) · 4.83 KB
/
subnets.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
package subnets
import (
"github.com/juju/collections/set"
"github.com/juju/errors"
"github.com/juju/loggo"
"github.com/juju/names/v5"
"github.com/juju/juju/apiserver/common/networkingcommon"
apiservererrors "github.com/juju/juju/apiserver/errors"
"github.com/juju/juju/apiserver/facade"
"github.com/juju/juju/core/network"
"github.com/juju/juju/core/permission"
"github.com/juju/juju/environs"
"github.com/juju/juju/environs/context"
"github.com/juju/juju/rpc/params"
)
var logger = loggo.GetLogger("juju.apiserver.subnets")
// Backing contains the state methods used in this package.
type Backing interface {
environs.EnvironConfigGetter
// AvailabilityZones returns all cached availability zones (i.e.
// not from the provider, but in state).
AvailabilityZones() (network.AvailabilityZones, error)
// SetAvailabilityZones replaces the cached list of availability
// zones with the given zones.
SetAvailabilityZones(network.AvailabilityZones) error
// AllSubnets returns all backing subnets.
AllSubnets() ([]networkingcommon.BackingSubnet, error)
// SubnetByCIDR returns a unique subnet based on the input CIDR.
SubnetByCIDR(cidr string) (networkingcommon.BackingSubnet, error)
// SubnetsByCIDR returns any subnets with the input CIDR.
SubnetsByCIDR(cidr string) ([]networkingcommon.BackingSubnet, error)
// AllSpaces returns all known Juju network spaces.
AllSpaces() ([]networkingcommon.BackingSpace, error)
// ModelTag returns the tag of the model this state is associated to.
ModelTag() names.ModelTag
}
// API provides the subnets API facade for version 5.
type API struct {
backing Backing
resources facade.Resources
authorizer facade.Authorizer
context context.ProviderCallContext
}
func (api *API) checkCanRead() error {
return api.authorizer.HasPermission(permission.ReadAccess, api.backing.ModelTag())
}
// newAPIWithBacking creates a new server-side Subnets API facade with
// a common.NetworkBacking
func newAPIWithBacking(backing Backing, ctx context.ProviderCallContext, resources facade.Resources, authorizer facade.Authorizer) (*API, error) {
// Only clients can access the Subnets facade.
if !authorizer.AuthClient() {
return nil, apiservererrors.ErrPerm
}
return &API{
backing: backing,
resources: resources,
authorizer: authorizer,
context: ctx,
}, nil
}
// AllZones returns all availability zones known to Juju. If a
// zone is unusable, unavailable, or deprecated the Available
// field will be false.
func (api *API) AllZones() (params.ZoneResults, error) {
if err := api.checkCanRead(); err != nil {
return params.ZoneResults{}, err
}
return allZones(api.context, api.backing)
}
// ListSubnets returns the matching subnets after applying
// optional filters.
func (api *API) ListSubnets(args params.SubnetsFilters) (results params.ListSubnetsResults, err error) {
if err := api.checkCanRead(); err != nil {
return params.ListSubnetsResults{}, err
}
subs, err := api.backing.AllSubnets()
if err != nil {
return results, errors.Trace(err)
}
var spaceFilter string
if args.SpaceTag != "" {
tag, err := names.ParseSpaceTag(args.SpaceTag)
if err != nil {
return results, errors.Trace(err)
}
spaceFilter = tag.Id()
}
zoneFilter := args.Zone
for _, subnet := range subs {
if spaceFilter != "" && subnet.SpaceName() != spaceFilter {
logger.Tracef(
"filtering subnet %q from space %q not matching filter %q",
subnet.CIDR(), subnet.SpaceName(), spaceFilter,
)
continue
}
zoneSet := set.NewStrings(subnet.AvailabilityZones()...)
if zoneFilter != "" && !zoneSet.IsEmpty() && !zoneSet.Contains(zoneFilter) {
logger.Tracef(
"filtering subnet %q with zones %v not matching filter %q",
subnet.CIDR(), subnet.AvailabilityZones(), zoneFilter,
)
continue
}
results.Results = append(results.Results, networkingcommon.BackingSubnetToParamsSubnet(subnet))
}
return results, nil
}
// SubnetsByCIDR returns the collection of subnets matching each CIDR in the input.
func (api *API) SubnetsByCIDR(arg params.CIDRParams) (params.SubnetsResults, error) {
result := params.SubnetsResults{}
if err := api.checkCanRead(); err != nil {
return result, err
}
results := make([]params.SubnetsResult, len(arg.CIDRS))
for i, cidr := range arg.CIDRS {
if !network.IsValidCIDR(cidr) {
results[i].Error = apiservererrors.ServerError(errors.NotValidf("CIDR %q", cidr))
continue
}
subnets, err := api.backing.SubnetsByCIDR(cidr)
if err != nil {
results[i].Error = apiservererrors.ServerError(err)
continue
}
subnetResults := make([]params.SubnetV2, len(subnets))
for j, subnet := range subnets {
subnetResults[j] = networkingcommon.BackingSubnetToParamsSubnetV2(subnet)
}
results[i].Subnets = subnetResults
}
result.Results = results
return result, nil
}