1
// Copyright 2016 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
4
package networkingcommon_test
7
"github.com/juju/errors"
8
jc "github.com/juju/testing/checkers"
11
"github.com/juju/juju/apiserver/common/networkingcommon"
12
"github.com/juju/juju/apiserver/params"
13
apiservertesting "github.com/juju/juju/apiserver/testing"
14
"github.com/juju/juju/instance"
15
"github.com/juju/juju/network"
16
providercommon "github.com/juju/juju/provider/common"
17
coretesting "github.com/juju/juju/testing"
20
type SubnetsSuite struct {
22
apiservertesting.StubNetwork
25
var _ = gc.Suite(&SubnetsSuite{})
27
func (s *SubnetsSuite) SetUpSuite(c *gc.C) {
28
s.StubNetwork.SetUpSuite(c)
29
s.BaseSuite.SetUpSuite(c)
32
func (s *SubnetsSuite) TearDownSuite(c *gc.C) {
33
s.BaseSuite.TearDownSuite(c)
36
func (s *SubnetsSuite) SetUpTest(c *gc.C) {
37
s.BaseSuite.SetUpTest(c)
38
apiservertesting.BackingInstance.SetUp(
40
apiservertesting.StubZonedEnvironName,
41
apiservertesting.WithZones,
42
apiservertesting.WithSpaces,
43
apiservertesting.WithSubnets)
46
func (s *SubnetsSuite) TearDownTest(c *gc.C) {
47
s.BaseSuite.TearDownTest(c)
50
// AssertAllZonesResult makes it easier to verify AllZones results.
51
func (s *SubnetsSuite) AssertAllZonesResult(c *gc.C, got params.ZoneResults, expected []providercommon.AvailabilityZone) {
52
results := make([]params.ZoneResult, len(expected))
53
for i, zone := range expected {
54
results[i].Name = zone.Name()
55
results[i].Available = zone.Available()
57
c.Assert(got, jc.DeepEquals, params.ZoneResults{Results: results})
60
func (s *SubnetsSuite) TestAllZonesWhenBackingAvailabilityZonesFails(c *gc.C) {
61
apiservertesting.SharedStub.SetErrors(errors.NotSupportedf("zones"))
63
results, err := networkingcommon.AllZones(apiservertesting.BackingInstance)
64
c.Assert(err, gc.ErrorMatches, "zones not supported")
65
// Verify the cause is not obscured.
66
c.Assert(err, jc.Satisfies, errors.IsNotSupported)
67
c.Assert(results, jc.DeepEquals, params.ZoneResults{})
69
apiservertesting.CheckMethodCalls(c, apiservertesting.SharedStub,
70
apiservertesting.BackingCall("AvailabilityZones"),
74
func (s *SubnetsSuite) TestAllZonesUsesBackingZonesWhenAvailable(c *gc.C) {
75
results, err := networkingcommon.AllZones(apiservertesting.BackingInstance)
76
c.Assert(err, jc.ErrorIsNil)
77
s.AssertAllZonesResult(c, results, apiservertesting.BackingInstance.Zones)
79
apiservertesting.CheckMethodCalls(c, apiservertesting.SharedStub,
80
apiservertesting.BackingCall("AvailabilityZones"),
84
func (s *SubnetsSuite) TestAllZonesWithNoBackingZonesUpdates(c *gc.C) {
85
apiservertesting.BackingInstance.SetUp(
87
apiservertesting.StubZonedEnvironName,
88
apiservertesting.WithoutZones,
89
apiservertesting.WithSpaces,
90
apiservertesting.WithSubnets)
92
results, err := networkingcommon.AllZones(apiservertesting.BackingInstance)
93
c.Assert(err, jc.ErrorIsNil)
94
s.AssertAllZonesResult(c, results, apiservertesting.ProviderInstance.Zones)
96
apiservertesting.CheckMethodCalls(c, apiservertesting.SharedStub,
97
apiservertesting.BackingCall("AvailabilityZones"),
98
apiservertesting.BackingCall("ModelConfig"),
99
apiservertesting.BackingCall("CloudSpec"),
100
apiservertesting.ProviderCall("Open", apiservertesting.BackingInstance.EnvConfig),
101
apiservertesting.ZonedEnvironCall("AvailabilityZones"),
102
apiservertesting.BackingCall("SetAvailabilityZones", apiservertesting.ProviderInstance.Zones),
106
func (s *SubnetsSuite) TestAllZonesWithNoBackingZonesAndSetFails(c *gc.C) {
107
apiservertesting.BackingInstance.SetUp(
109
apiservertesting.StubZonedEnvironName,
110
apiservertesting.WithoutZones,
111
apiservertesting.WithSpaces,
112
apiservertesting.WithSubnets)
114
apiservertesting.SharedStub.SetErrors(
115
nil, // Backing.AvailabilityZones
116
nil, // Backing.ModelConfig
117
nil, // Backing.CloudSpec
118
nil, // Provider.Open
119
nil, // ZonedEnviron.AvailabilityZones
120
errors.NotSupportedf("setting"), // Backing.SetAvailabilityZones
123
results, err := networkingcommon.AllZones(apiservertesting.BackingInstance)
124
c.Assert(err, gc.ErrorMatches,
125
`cannot update known zones: setting not supported`,
127
// Verify the cause is not obscured.
128
c.Assert(err, jc.Satisfies, errors.IsNotSupported)
129
c.Assert(results, jc.DeepEquals, params.ZoneResults{})
131
apiservertesting.CheckMethodCalls(c, apiservertesting.SharedStub,
132
apiservertesting.BackingCall("AvailabilityZones"),
133
apiservertesting.BackingCall("ModelConfig"),
134
apiservertesting.BackingCall("CloudSpec"),
135
apiservertesting.ProviderCall("Open", apiservertesting.BackingInstance.EnvConfig),
136
apiservertesting.ZonedEnvironCall("AvailabilityZones"),
137
apiservertesting.BackingCall("SetAvailabilityZones", apiservertesting.ProviderInstance.Zones),
141
func (s *SubnetsSuite) TestAllZonesWithNoBackingZonesAndFetchingZonesFails(c *gc.C) {
142
apiservertesting.BackingInstance.SetUp(
144
apiservertesting.StubZonedEnvironName,
145
apiservertesting.WithoutZones,
146
apiservertesting.WithSpaces,
147
apiservertesting.WithSubnets)
149
apiservertesting.SharedStub.SetErrors(
150
nil, // Backing.AvailabilityZones
151
nil, // Backing.ModelConfig
152
nil, // Backing.CloudSpec
153
nil, // Provider.Open
154
errors.NotValidf("foo"), // ZonedEnviron.AvailabilityZones
157
results, err := networkingcommon.AllZones(apiservertesting.BackingInstance)
158
c.Assert(err, gc.ErrorMatches,
159
`cannot update known zones: foo not valid`,
161
// Verify the cause is not obscured.
162
c.Assert(err, jc.Satisfies, errors.IsNotValid)
163
c.Assert(results, jc.DeepEquals, params.ZoneResults{})
165
apiservertesting.CheckMethodCalls(c, apiservertesting.SharedStub,
166
apiservertesting.BackingCall("AvailabilityZones"),
167
apiservertesting.BackingCall("ModelConfig"),
168
apiservertesting.BackingCall("CloudSpec"),
169
apiservertesting.ProviderCall("Open", apiservertesting.BackingInstance.EnvConfig),
170
apiservertesting.ZonedEnvironCall("AvailabilityZones"),
174
func (s *SubnetsSuite) TestAllZonesWithNoBackingZonesAndModelConfigFails(c *gc.C) {
175
apiservertesting.BackingInstance.SetUp(
177
apiservertesting.StubZonedEnvironName,
178
apiservertesting.WithoutZones,
179
apiservertesting.WithSpaces,
180
apiservertesting.WithSubnets)
182
apiservertesting.SharedStub.SetErrors(
183
nil, // Backing.AvailabilityZones
184
errors.NotFoundf("config"), // Backing.ModelConfig
187
results, err := networkingcommon.AllZones(apiservertesting.BackingInstance)
188
c.Assert(err, gc.ErrorMatches,
189
`cannot update known zones: opening environment: config not found`,
191
// Verify the cause is not obscured.
192
c.Assert(err, jc.Satisfies, errors.IsNotFound)
193
c.Assert(results, jc.DeepEquals, params.ZoneResults{})
195
apiservertesting.CheckMethodCalls(c, apiservertesting.SharedStub,
196
apiservertesting.BackingCall("AvailabilityZones"),
197
apiservertesting.BackingCall("ModelConfig"),
201
func (s *SubnetsSuite) TestAllZonesWithNoBackingZonesAndOpenFails(c *gc.C) {
202
apiservertesting.BackingInstance.SetUp(
204
apiservertesting.StubZonedEnvironName,
205
apiservertesting.WithoutZones,
206
apiservertesting.WithSpaces,
207
apiservertesting.WithSubnets)
209
apiservertesting.SharedStub.SetErrors(
210
nil, // Backing.AvailabilityZones
211
nil, // Backing.ModelConfig
212
nil, // Backing.CloudSpec
213
errors.NotValidf("config"), // Provider.Open
216
results, err := networkingcommon.AllZones(apiservertesting.BackingInstance)
217
c.Assert(err, gc.ErrorMatches,
218
`cannot update known zones: opening environment: config not valid`,
220
// Verify the cause is not obscured.
221
c.Assert(err, jc.Satisfies, errors.IsNotValid)
222
c.Assert(results, jc.DeepEquals, params.ZoneResults{})
224
apiservertesting.CheckMethodCalls(c, apiservertesting.SharedStub,
225
apiservertesting.BackingCall("AvailabilityZones"),
226
apiservertesting.BackingCall("ModelConfig"),
227
apiservertesting.BackingCall("CloudSpec"),
228
apiservertesting.ProviderCall("Open", apiservertesting.BackingInstance.EnvConfig),
232
func (s *SubnetsSuite) TestAllZonesWithNoBackingZonesAndZonesNotSupported(c *gc.C) {
233
// ZonedEnviron not supported
234
apiservertesting.BackingInstance.SetUp(
236
apiservertesting.StubEnvironName,
237
apiservertesting.WithoutZones,
238
apiservertesting.WithSpaces,
239
apiservertesting.WithSubnets)
241
results, err := networkingcommon.AllZones(apiservertesting.BackingInstance)
242
c.Assert(err, gc.ErrorMatches,
243
`cannot update known zones: availability zones not supported`,
245
// Verify the cause is not obscured.
246
c.Assert(err, jc.Satisfies, errors.IsNotSupported)
247
c.Assert(results, jc.DeepEquals, params.ZoneResults{})
249
apiservertesting.CheckMethodCalls(c, apiservertesting.SharedStub,
250
apiservertesting.BackingCall("AvailabilityZones"),
251
apiservertesting.BackingCall("ModelConfig"),
252
apiservertesting.BackingCall("CloudSpec"),
253
apiservertesting.ProviderCall("Open", apiservertesting.BackingInstance.EnvConfig),
257
func (s *SubnetsSuite) TestAddSubnetsParamsCombinations(c *gc.C) {
258
apiservertesting.BackingInstance.SetUp(
260
apiservertesting.StubNetworkingEnvironName,
261
apiservertesting.WithZones,
262
apiservertesting.WithSpaces,
263
apiservertesting.WithSubnets)
265
args := params.AddSubnetsParams{Subnets: []params.AddSubnetParams{{
266
// nothing set; early exit: no calls
268
// neither tag nor id set: the rest is ignored; same as above
270
Zones: []string{"any", "ignored"},
272
// both tag and id set; same as above
274
SubnetProviderId: "any",
276
// lookup by id needed, no cached subnets; ModelConfig(): error
277
SubnetProviderId: "any",
279
// same as above, need to cache subnets; ModelConfig(): ok; Open(): error
280
SubnetProviderId: "ignored",
282
// as above, caching again; ModelConfig(), Open(): ok; Subnets(): error
283
SubnetProviderId: "unimportant",
285
// exactly as above, except all 3 calls ok; cached lookup: id not found
286
SubnetProviderId: "missing",
288
// cached lookup by id (no calls): not found error
289
SubnetProviderId: "void",
291
// cached lookup by id: ok; parsing space tag: invalid tag error
292
SubnetProviderId: "sn-deadbeef",
295
// as above, but slightly different error: invalid space tag error
296
SubnetProviderId: "sn-zadf00d",
297
SpaceTag: "unit-foo",
299
// as above; yet another similar error (valid tag with another kind)
300
SubnetProviderId: "vlan-42",
301
SpaceTag: "unit-foo-0",
303
// invalid tag (no kind): error (no calls)
304
SubnetTag: "invalid",
306
// invalid subnet tag (another kind): same as above
307
SubnetTag: "application-bar",
309
// cached lookup by missing CIDR: not found error
310
SubnetTag: "subnet-1.2.3.0/24",
312
// cached lookup by duplicate CIDR: multiple choices error
313
SubnetTag: "subnet-10.10.0.0/24",
315
// cached lookup by CIDR with empty provider id: ok; space tag is required error
316
SubnetTag: "subnet-10.20.0.0/16",
318
// cached lookup by id with invalid CIDR: cannot be added error
319
SubnetProviderId: "sn-invalid",
321
// cached lookup by id with empty CIDR: cannot be added error
322
SubnetProviderId: "sn-empty",
324
// cached lookup by id with incorrectly specified CIDR: cannot be added error
325
SubnetProviderId: "sn-awesome",
327
// cached lookup by CIDR: ok; valid tag; caching spaces: AllSpaces(): error
328
SubnetTag: "subnet-10.30.1.0/24",
329
SpaceTag: "space-unverified",
331
// exactly as above, except AllSpaces(): ok; cached lookup: space not found
332
SubnetTag: "subnet-2001:db8::/32",
333
SpaceTag: "space-missing",
335
// both cached lookups (CIDR, space): ok; no provider or given zones: error
336
SubnetTag: "subnet-10.42.0.0/16",
337
SpaceTag: "space-dmz",
339
// like above; with provider zones, extra given: error
340
SubnetProviderId: "vlan-42",
341
SpaceTag: "space-private",
343
"zone2", // not allowed, existing, unavailable
344
"zone3", // allowed, existing, available
345
"missing", // not allowed, non-existing
346
"zone3", // duplicates are ignored (should they ?)
347
"zone1", // not allowed, existing, available
350
// like above; no provider, only given zones; caching: AllZones(): error
351
SubnetTag: "subnet-10.42.0.0/16",
352
SpaceTag: "space-dmz",
353
Zones: []string{"any", "ignored"},
355
// as above, but unknown zones given: cached: AllZones(): ok; unknown zones error
356
SubnetTag: "subnet-10.42.0.0/16",
357
SpaceTag: "space-dmz",
358
Zones: []string{"missing", "gone"},
360
// as above, but unknown and unavailable zones given: same error (no calls)
361
SubnetTag: "subnet-10.42.0.0/16",
362
SpaceTag: "space-dmz",
363
Zones: []string{"zone4", "missing", "zone2"},
365
// as above, but unavailable zones given: Zones contains unavailable error
366
SubnetTag: "subnet-10.42.0.0/16",
367
SpaceTag: "space-dmz",
368
Zones: []string{"zone2", "zone4"},
370
// as above, but available and unavailable zones given: same error as above
371
SubnetTag: "subnet-10.42.0.0/16",
372
SpaceTag: "space-dmz",
373
Zones: []string{"zone4", "zone3"},
375
// everything succeeds, using caches as needed, until: AddSubnet(): error
376
SubnetProviderId: "sn-ipv6",
377
SpaceTag: "space-dmz",
378
Zones: []string{"zone1"},
379
// restriction of provider zones [zone1, zone3]
381
// cached lookups by CIDR, space: ok; duplicated provider id: unavailable zone2
382
SubnetTag: "subnet-10.99.88.0/24",
383
SpaceTag: "space-dmz",
384
Zones: []string{"zone2"},
385
// due to the duplicate ProviderId provider zones from subnet
386
// with the last ProviderId=sn-deadbeef are used
387
// (10.10.0.0/24); [zone2], not the 10.99.88.0/24 provider
388
// zones: [zone1, zone2].
390
// same as above, but AddSubnet(): ok; success (backing verified later)
391
SubnetProviderId: "sn-ipv6",
392
SpaceTag: "space-dmz",
393
Zones: []string{"zone1"},
394
// restriction of provider zones [zone1, zone3]
396
// success (CIDR lookup; with provider (no given) zones): AddSubnet(): ok
397
SubnetTag: "subnet-10.30.1.0/24",
398
SpaceTag: "space-private",
399
// Zones not given, so provider zones are used instead: [zone3]
401
// success (id lookup; given zones match provider zones) AddSubnet(): ok
402
SubnetProviderId: "sn-zadf00d",
403
SpaceTag: "space-private",
404
Zones: []string{"zone1"},
406
apiservertesting.SharedStub.SetErrors(
407
// caching subnets (1st attempt): fails
408
errors.NotFoundf("config"), // BackingInstance.ModelConfig (1st call)
410
// caching subnets (2nd attepmt): fails
411
nil, // BackingInstance.ModelConfig (2nd call)
412
nil, // BackingInstance.CloudSpec (1st call)
413
errors.NotFoundf("provider"), // ProviderInstance.Open (1st call)
415
// caching subnets (3rd attempt): fails
416
nil, // BackingInstance.ModelConfig (3rd call)
417
nil, // BackingInstance.CloudSpec (2nd call)
418
nil, // ProviderInstance.Open (2nd call)
419
errors.NotFoundf("subnets"), // NetworkingEnvironInstance.Subnets (1st call)
421
// caching subnets (4th attempt): succeeds
422
nil, // BackingInstance.ModelConfig (4th call)
423
nil, // BackingInstance.CloudSpec (3rd call)
424
nil, // ProviderInstance.Open (3rd call)
425
nil, // NetworkingEnvironInstance.Subnets (2nd call)
427
// caching spaces (1st and 2nd attempts)
428
errors.NotFoundf("spaces"), // BackingInstance.AllSpaces (1st call)
429
nil, // BackingInstance.AllSpaces (2nd call)
431
// cacing zones (1st and 2nd attempts)
432
errors.NotFoundf("zones"), // BackingInstance.AvailabilityZones (1st call)
433
nil, // BackingInstance.AvailabilityZones (2nd call)
435
// validation done; adding subnets to backing store
436
errors.NotFoundf("state"), // BackingInstance.AddSubnet (1st call)
437
// the next 3 BackingInstance.AddSubnet calls succeed(2nd call)
440
expectedErrors := []struct {
442
satisfier func(error) bool
444
{"either SubnetTag or SubnetProviderId is required", nil},
445
{"either SubnetTag or SubnetProviderId is required", nil},
446
{"SubnetTag and SubnetProviderId cannot be both set", nil},
447
{"opening environment: config not found", params.IsCodeNotFound},
448
{"opening environment: provider not found", params.IsCodeNotFound},
449
{"cannot get provider subnets: subnets not found", params.IsCodeNotFound},
450
{`subnet with CIDR "" and ProviderId "missing" not found`, params.IsCodeNotFound},
451
{`subnet with CIDR "" and ProviderId "void" not found`, params.IsCodeNotFound},
452
{`given SpaceTag is invalid: "invalid" is not a valid tag`, nil},
453
{`given SpaceTag is invalid: "unit-foo" is not a valid unit tag`, nil},
454
{`given SpaceTag is invalid: "unit-foo-0" is not a valid space tag`, nil},
455
{`given SubnetTag is invalid: "invalid" is not a valid tag`, nil},
456
{`given SubnetTag is invalid: "application-bar" is not a valid subnet tag`, nil},
457
{`subnet with CIDR "1.2.3.0/24" not found`, params.IsCodeNotFound},
459
`multiple subnets with CIDR "10.10.0.0/24": ` +
460
`retry using ProviderId from: "sn-deadbeef", "sn-zadf00d"`, nil,
462
{"SpaceTag is required", nil},
463
{`subnet with CIDR "invalid" and ProviderId "sn-invalid": invalid CIDR`, nil},
464
{`subnet with ProviderId "sn-empty": empty CIDR`, nil},
466
`subnet with ProviderId "sn-awesome": ` +
467
`incorrect CIDR format "0.1.2.3/4", expected "0.0.0.0/4"`, nil,
469
{"cannot validate given SpaceTag: spaces not found", params.IsCodeNotFound},
470
{`space "missing" not found`, params.IsCodeNotFound},
471
{"Zones cannot be discovered from the provider and must be set", nil},
472
{`Zones contain zones not allowed by the provider: "missing", "zone1", "zone2"`, nil},
473
{"given Zones cannot be validated: zones not found", params.IsCodeNotFound},
474
{`Zones contain unknown zones: "gone", "missing"`, nil},
475
{`Zones contain unknown zones: "missing"`, nil},
476
{`Zones contain unavailable zones: "zone2", "zone4"`, nil},
477
{`Zones contain unavailable zones: "zone4"`, nil},
478
{"state not found", params.IsCodeNotFound},
479
{`Zones contain unavailable zones: "zone2"`, nil},
484
expectedBackingInfos := []networkingcommon.BackingSubnetInfo{{
485
ProviderId: "sn-ipv6",
486
CIDR: "2001:db8::/32",
488
AvailabilityZones: []string{"zone1"},
491
ProviderId: "vlan-42",
492
CIDR: "10.30.1.0/24",
494
AvailabilityZones: []string{"zone3"},
495
SpaceName: "private",
497
ProviderId: "sn-zadf00d",
498
CIDR: "10.10.0.0/24",
500
AvailabilityZones: []string{"zone1"},
501
SpaceName: "private",
503
c.Check(expectedErrors, gc.HasLen, len(args.Subnets))
504
results, err := networkingcommon.AddSubnets(apiservertesting.BackingInstance, args)
505
c.Assert(err, jc.ErrorIsNil)
506
c.Assert(len(results.Results), gc.Equals, len(args.Subnets))
507
for i, result := range results.Results {
508
c.Logf("result #%d: expected: %q", i, expectedErrors[i].message)
509
if expectedErrors[i].message == "" {
510
if !c.Check(result.Error, gc.IsNil) {
511
c.Logf("unexpected error: %v; args: %#v", result.Error, args.Subnets[i])
515
if !c.Check(result.Error, gc.NotNil) {
516
c.Logf("unexpected success; args: %#v", args.Subnets[i])
519
c.Check(result.Error.Message, gc.Equals, expectedErrors[i].message)
520
if expectedErrors[i].satisfier != nil {
521
c.Check(result.Error, jc.Satisfies, expectedErrors[i].satisfier)
523
c.Check(result.Error.Code, gc.Equals, "")
527
apiservertesting.CheckMethodCalls(c, apiservertesting.SharedStub,
528
// caching subnets (1st attempt): fails
529
apiservertesting.BackingCall("ModelConfig"),
531
// caching subnets (2nd attepmt): fails
532
apiservertesting.BackingCall("ModelConfig"),
533
apiservertesting.BackingCall("CloudSpec"),
534
apiservertesting.ProviderCall("Open", apiservertesting.BackingInstance.EnvConfig),
536
// caching subnets (3rd attempt): fails
537
apiservertesting.BackingCall("ModelConfig"),
538
apiservertesting.BackingCall("CloudSpec"),
539
apiservertesting.ProviderCall("Open", apiservertesting.BackingInstance.EnvConfig),
540
apiservertesting.NetworkingEnvironCall("Subnets", instance.UnknownId, []network.Id(nil)),
542
// caching subnets (4th attempt): succeeds
543
apiservertesting.BackingCall("ModelConfig"),
544
apiservertesting.BackingCall("CloudSpec"),
545
apiservertesting.ProviderCall("Open", apiservertesting.BackingInstance.EnvConfig),
546
apiservertesting.NetworkingEnvironCall("Subnets", instance.UnknownId, []network.Id(nil)),
548
// caching spaces (1st and 2nd attempts)
549
apiservertesting.BackingCall("AllSpaces"),
550
apiservertesting.BackingCall("AllSpaces"),
552
// caching zones (1st and 2nd attempts)
553
apiservertesting.BackingCall("AvailabilityZones"),
554
apiservertesting.BackingCall("AvailabilityZones"),
556
// validation done; adding subnets to backing store
557
apiservertesting.BackingCall("AddSubnet", expectedBackingInfos[0]),
558
apiservertesting.BackingCall("AddSubnet", expectedBackingInfos[0]),
559
apiservertesting.BackingCall("AddSubnet", expectedBackingInfos[1]),
560
apiservertesting.BackingCall("AddSubnet", expectedBackingInfos[2]),
562
apiservertesting.ResetStub(apiservertesting.SharedStub)
564
// Finally, check that no params yields no results.
565
results, err = networkingcommon.AddSubnets(apiservertesting.BackingInstance, params.AddSubnetsParams{})
566
c.Assert(err, jc.ErrorIsNil)
567
c.Assert(results.Results, gc.NotNil)
568
c.Assert(results.Results, gc.HasLen, 0)
570
apiservertesting.CheckMethodCalls(c, apiservertesting.SharedStub)
573
func (s *SubnetsSuite) CheckAddSubnetsFails(
574
c *gc.C, envName string,
575
withZones, withSpaces, withSubnets apiservertesting.SetUpFlag,
576
expectedError string,
577
expectedSatisfies func(error) bool,
579
apiservertesting.BackingInstance.SetUp(c, envName, withZones, withSpaces, withSubnets)
581
// These calls always happen.
582
expectedCalls := []apiservertesting.StubMethodCall{
583
apiservertesting.BackingCall("ModelConfig"),
584
apiservertesting.BackingCall("CloudSpec"),
585
apiservertesting.ProviderCall("Open", apiservertesting.BackingInstance.EnvConfig),
588
// Subnets is also always called. but the receiver is different.
590
case apiservertesting.StubNetworkingEnvironName:
591
expectedCalls = append(
593
apiservertesting.NetworkingEnvironCall("Subnets", instance.UnknownId, []network.Id(nil)),
595
case apiservertesting.StubZonedNetworkingEnvironName:
596
expectedCalls = append(
598
apiservertesting.ZonedNetworkingEnvironCall("Subnets", instance.UnknownId, []network.Id(nil)),
603
// Set provider subnets to empty for this test.
604
originalSubnets := make([]network.SubnetInfo, len(apiservertesting.ProviderInstance.Subnets))
605
copy(originalSubnets, apiservertesting.ProviderInstance.Subnets)
606
apiservertesting.ProviderInstance.Subnets = []network.SubnetInfo{}
609
apiservertesting.ProviderInstance.Subnets = make([]network.SubnetInfo, len(originalSubnets))
610
copy(apiservertesting.ProviderInstance.Subnets, originalSubnets)
613
if envName == apiservertesting.StubEnvironName || envName == apiservertesting.StubNetworkingEnvironName {
614
// networking is either not supported or no subnets are
615
// defined, so expected the same calls for each of the two
616
// arguments to AddSubnets() below.
617
expectedCalls = append(expectedCalls, expectedCalls...)
620
// Having subnets implies spaces will be cached as well.
621
expectedCalls = append(expectedCalls, apiservertesting.BackingCall("AllSpaces"))
624
if withSpaces && withSubnets {
625
// Having both subnets and spaces means we'll also cache zones.
626
expectedCalls = append(expectedCalls, apiservertesting.BackingCall("AvailabilityZones"))
629
if !withZones && withSpaces {
630
// Set provider zones to empty for this test.
631
originalZones := make([]providercommon.AvailabilityZone, len(apiservertesting.ProviderInstance.Zones))
632
copy(originalZones, apiservertesting.ProviderInstance.Zones)
633
apiservertesting.ProviderInstance.Zones = []providercommon.AvailabilityZone{}
636
apiservertesting.ProviderInstance.Zones = make([]providercommon.AvailabilityZone, len(originalZones))
637
copy(apiservertesting.ProviderInstance.Zones, originalZones)
640
// updateZones tries to constructs a ZonedEnviron with these calls.
641
zoneCalls := append([]apiservertesting.StubMethodCall{},
642
apiservertesting.BackingCall("ModelConfig"),
643
apiservertesting.BackingCall("CloudSpec"),
644
apiservertesting.ProviderCall("Open", apiservertesting.BackingInstance.EnvConfig),
646
// Receiver can differ according to envName, but
647
// AvailabilityZones() will be called on either receiver.
649
case apiservertesting.StubZonedEnvironName:
652
apiservertesting.ZonedEnvironCall("AvailabilityZones"),
654
case apiservertesting.StubZonedNetworkingEnvironName:
657
apiservertesting.ZonedNetworkingEnvironCall("AvailabilityZones"),
660
// Finally after caching provider zones backing zones are
664
apiservertesting.BackingCall("SetAvailabilityZones", apiservertesting.ProviderInstance.Zones),
667
// Now, because we have 2 arguments to AddSubnets() below, we
668
// need to expect the same zoneCalls twice, with a
669
// AvailabilityZones backing lookup between them.
670
expectedCalls = append(expectedCalls, zoneCalls...)
671
expectedCalls = append(expectedCalls, apiservertesting.BackingCall("AvailabilityZones"))
672
expectedCalls = append(expectedCalls, zoneCalls...)
675
// Pass 2 arguments covering all cases we need.
676
args := params.AddSubnetsParams{
677
Subnets: []params.AddSubnetParams{{
678
SubnetTag: "subnet-10.42.0.0/16",
679
SpaceTag: "space-dmz",
680
Zones: []string{"zone1"},
682
SubnetProviderId: "vlan-42",
683
SpaceTag: "space-private",
684
Zones: []string{"zone3"},
687
results, err := networkingcommon.AddSubnets(apiservertesting.BackingInstance, args)
688
c.Assert(err, jc.ErrorIsNil)
689
c.Assert(results.Results, gc.HasLen, len(args.Subnets))
690
for _, result := range results.Results {
691
if !c.Check(result.Error, gc.NotNil) {
694
c.Check(result.Error, gc.ErrorMatches, expectedError)
695
if expectedSatisfies != nil {
696
c.Check(result.Error, jc.Satisfies, expectedSatisfies)
698
c.Check(result.Error.Code, gc.Equals, "")
702
apiservertesting.CheckMethodCalls(c, apiservertesting.SharedStub, expectedCalls...)
705
func (s *SubnetsSuite) TestAddSubnetsWithNoProviderSubnetsFails(c *gc.C) {
706
s.CheckAddSubnetsFails(
707
c, apiservertesting.StubNetworkingEnvironName,
708
apiservertesting.WithoutZones, apiservertesting.WithoutSpaces, apiservertesting.WithoutSubnets,
709
"no subnets defined",
714
func (s *SubnetsSuite) TestAddSubnetsWithNoBackingSpacesFails(c *gc.C) {
715
s.CheckAddSubnetsFails(
716
c, apiservertesting.StubNetworkingEnvironName,
717
apiservertesting.WithoutZones, apiservertesting.WithoutSpaces, apiservertesting.WithSubnets,
723
func (s *SubnetsSuite) TestAddSubnetsWithNoProviderZonesFails(c *gc.C) {
724
s.CheckAddSubnetsFails(
725
c, apiservertesting.StubZonedNetworkingEnvironName,
726
apiservertesting.WithoutZones, apiservertesting.WithSpaces, apiservertesting.WithSubnets,
732
func (s *SubnetsSuite) TestAddSubnetsWhenNetworkingEnvironNotSupported(c *gc.C) {
733
s.CheckAddSubnetsFails(
734
c, apiservertesting.StubEnvironName,
735
apiservertesting.WithoutZones, apiservertesting.WithoutSpaces, apiservertesting.WithoutSubnets,
736
"model networking features not supported",
737
params.IsCodeNotSupported,
741
func (s *SubnetsSuite) TestListSubnetsAndFiltering(c *gc.C) {
742
expected := []params.Subnet{{
743
CIDR: "10.10.0.0/24",
744
ProviderId: "sn-zadf00d",
747
SpaceTag: "space-private",
748
Zones: []string{"zone1"},
751
CIDR: "2001:db8::/32",
752
ProviderId: "sn-ipv6",
755
SpaceTag: "space-dmz",
756
Zones: []string{"zone1", "zone3"},
760
args := params.SubnetsFilters{}
761
subnets, err := networkingcommon.ListSubnets(apiservertesting.BackingInstance, args)
762
c.Assert(err, jc.ErrorIsNil)
763
c.Assert(subnets.Results, jc.DeepEquals, expected)
765
// Filter by space only.
766
args.SpaceTag = "space-dmz"
767
subnets, err = networkingcommon.ListSubnets(apiservertesting.BackingInstance, args)
768
c.Assert(err, jc.ErrorIsNil)
769
c.Assert(subnets.Results, jc.DeepEquals, expected[1:])
771
// Filter by zone only.
774
subnets, err = networkingcommon.ListSubnets(apiservertesting.BackingInstance, args)
775
c.Assert(err, jc.ErrorIsNil)
776
c.Assert(subnets.Results, jc.DeepEquals, expected[1:])
778
// Filter by both space and zone.
779
args.SpaceTag = "space-private"
781
subnets, err = networkingcommon.ListSubnets(apiservertesting.BackingInstance, args)
782
c.Assert(err, jc.ErrorIsNil)
783
c.Assert(subnets.Results, jc.DeepEquals, expected[:1])
786
func (s *SubnetsSuite) TestListSubnetsInvalidSpaceTag(c *gc.C) {
787
args := params.SubnetsFilters{SpaceTag: "invalid"}
788
_, err := networkingcommon.ListSubnets(apiservertesting.BackingInstance, args)
789
c.Assert(err, gc.ErrorMatches, `"invalid" is not a valid tag`)
792
func (s *SubnetsSuite) TestListSubnetsAllSubnetError(c *gc.C) {
793
boom := errors.New("no subnets for you")
794
apiservertesting.BackingInstance.SetErrors(boom)
795
_, err := networkingcommon.ListSubnets(apiservertesting.BackingInstance, params.SubnetsFilters{})
796
c.Assert(err, gc.ErrorMatches, "no subnets for you")