github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/client/spaces/spaces_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package spaces_test 5 6 import ( 7 "fmt" 8 9 "github.com/juju/errors" 10 jc "github.com/juju/testing/checkers" 11 gc "gopkg.in/check.v1" 12 "gopkg.in/juju/names.v2" 13 14 "github.com/juju/juju/apiserver/common" 15 "github.com/juju/juju/apiserver/facades/client/spaces" 16 "github.com/juju/juju/apiserver/params" 17 apiservertesting "github.com/juju/juju/apiserver/testing" 18 "github.com/juju/juju/environs/context" 19 "github.com/juju/juju/network" 20 coretesting "github.com/juju/juju/testing" 21 ) 22 23 type SpacesSuite struct { 24 coretesting.BaseSuite 25 apiservertesting.StubNetwork 26 27 resources *common.Resources 28 authorizer apiservertesting.FakeAuthorizer 29 facade spaces.API 30 31 callContext context.ProviderCallContext 32 } 33 34 var _ = gc.Suite(&SpacesSuite{}) 35 36 func (s *SpacesSuite) SetUpSuite(c *gc.C) { 37 s.StubNetwork.SetUpSuite(c) 38 s.BaseSuite.SetUpSuite(c) 39 } 40 41 func (s *SpacesSuite) TearDownSuite(c *gc.C) { 42 s.BaseSuite.TearDownSuite(c) 43 } 44 45 func (s *SpacesSuite) SetUpTest(c *gc.C) { 46 s.BaseSuite.SetUpTest(c) 47 apiservertesting.BackingInstance.SetUp(c, apiservertesting.StubZonedNetworkingEnvironName, apiservertesting.WithZones, apiservertesting.WithSpaces, apiservertesting.WithSubnets) 48 49 s.resources = common.NewResources() 50 s.authorizer = apiservertesting.FakeAuthorizer{ 51 Tag: names.NewUserTag("admin"), 52 Controller: false, 53 } 54 55 s.callContext = context.NewCloudCallContext() 56 var err error 57 s.facade, err = spaces.NewAPIWithBacking( 58 apiservertesting.BackingInstance, 59 s.callContext, 60 s.resources, s.authorizer, 61 ) 62 c.Assert(err, jc.ErrorIsNil) 63 c.Assert(s.facade, gc.NotNil) 64 } 65 66 func (s *SpacesSuite) TearDownTest(c *gc.C) { 67 if s.resources != nil { 68 s.resources.StopAll() 69 } 70 s.BaseSuite.TearDownTest(c) 71 } 72 73 func (s *SpacesSuite) TestNewAPIWithBacking(c *gc.C) { 74 // Clients are allowed. 75 facade, err := spaces.NewAPIWithBacking( 76 apiservertesting.BackingInstance, 77 s.callContext, 78 s.resources, s.authorizer, 79 ) 80 c.Assert(err, jc.ErrorIsNil) 81 c.Assert(facade, gc.NotNil) 82 // No calls so far. 83 apiservertesting.CheckMethodCalls(c, apiservertesting.SharedStub) 84 85 // Agents are not allowed 86 agentAuthorizer := s.authorizer 87 agentAuthorizer.Tag = names.NewMachineTag("42") 88 facade, err = spaces.NewAPIWithBacking( 89 apiservertesting.BackingInstance, 90 context.NewCloudCallContext(), 91 s.resources, 92 agentAuthorizer, 93 ) 94 c.Assert(err, jc.DeepEquals, common.ErrPerm) 95 c.Assert(facade, gc.IsNil) 96 // No calls so far. 97 apiservertesting.CheckMethodCalls(c, apiservertesting.SharedStub) 98 } 99 100 type checkAddSpacesParams struct { 101 Name string 102 Subnets []string 103 Error string 104 MakesCall bool 105 Public bool 106 } 107 108 func (s *SpacesSuite) checkAddSpaces(c *gc.C, p checkAddSpacesParams) { 109 args := params.CreateSpaceParams{} 110 if p.Name != "" { 111 args.SpaceTag = "space-" + p.Name 112 } 113 if len(p.Subnets) > 0 { 114 for _, cidr := range p.Subnets { 115 args.SubnetTags = append(args.SubnetTags, "subnet-"+cidr) 116 } 117 } 118 args.Public = p.Public 119 120 spaces := params.CreateSpacesParams{} 121 spaces.Spaces = append(spaces.Spaces, args) 122 results, err := s.facade.CreateSpaces(spaces) 123 124 c.Assert(len(results.Results), gc.Equals, 1) 125 c.Assert(err, gc.IsNil) 126 if p.Error == "" { 127 c.Assert(results.Results[0].Error, gc.IsNil) 128 } else { 129 c.Assert(results.Results[0].Error, gc.NotNil) 130 c.Assert(results.Results[0].Error, gc.ErrorMatches, p.Error) 131 } 132 133 baseCalls := []apiservertesting.StubMethodCall{ 134 apiservertesting.BackingCall("ModelConfig"), 135 apiservertesting.BackingCall("CloudSpec"), 136 apiservertesting.ProviderCall("Open", apiservertesting.BackingInstance.EnvConfig), 137 apiservertesting.ZonedNetworkingEnvironCall("SupportsSpaces", s.callContext), 138 } 139 140 // AddSpace from the api always uses an empty ProviderId. 141 addSpaceCalls := append(baseCalls, apiservertesting.BackingCall("AddSpace", p.Name, network.Id(""), p.Subnets, p.Public)) 142 143 if p.Error == "" || p.MakesCall { 144 apiservertesting.CheckMethodCalls(c, apiservertesting.SharedStub, addSpaceCalls...) 145 } else { 146 apiservertesting.CheckMethodCalls(c, apiservertesting.SharedStub, baseCalls...) 147 } 148 } 149 150 func (s *SpacesSuite) TestAddSpacesOneSubnet(c *gc.C) { 151 p := checkAddSpacesParams{ 152 Name: "foo", 153 Subnets: []string{"10.0.0.0/24"}, 154 } 155 s.checkAddSpaces(c, p) 156 } 157 158 func (s *SpacesSuite) TestAddSpacesTwoSubnets(c *gc.C) { 159 p := checkAddSpacesParams{ 160 Name: "foo", 161 Subnets: []string{"10.0.0.0/24", "10.0.1.0/24"}, 162 } 163 s.checkAddSpaces(c, p) 164 } 165 166 func (s *SpacesSuite) TestAddSpacesManySubnets(c *gc.C) { 167 p := checkAddSpacesParams{ 168 Name: "foo", 169 Subnets: []string{"10.0.0.0/24", "10.0.1.0/24", "10.0.2.0/24", 170 "10.0.3.0/24", "10.0.4.0/24", "10.0.5.0/24", "10.0.6.0/24"}, 171 } 172 s.checkAddSpaces(c, p) 173 } 174 175 func (s *SpacesSuite) TestAddSpacesAPIError(c *gc.C) { 176 apiservertesting.SharedStub.SetErrors( 177 nil, // Backing.ModelConfig() 178 nil, // Backing.CloudSpec() 179 nil, // Provider.Open() 180 nil, // ZonedNetworkingEnviron.SupportsSpaces() 181 errors.AlreadyExistsf("space-foo"), // Backing.AddSpace() 182 ) 183 p := checkAddSpacesParams{ 184 Name: "foo", 185 Subnets: []string{"10.0.0.0/24"}, 186 MakesCall: true, 187 Error: "space-foo already exists", 188 } 189 s.checkAddSpaces(c, p) 190 } 191 192 func (s *SpacesSuite) TestCreateInvalidSpace(c *gc.C) { 193 p := checkAddSpacesParams{ 194 Name: "-", 195 Subnets: []string{"10.0.0.0/24"}, 196 Error: `"space--" is not a valid space tag`, 197 } 198 s.checkAddSpaces(c, p) 199 } 200 201 func (s *SpacesSuite) TestCreateInvalidSubnet(c *gc.C) { 202 p := checkAddSpacesParams{ 203 Name: "foo", 204 Subnets: []string{"bar"}, 205 Error: `"subnet-bar" is not a valid subnet tag`, 206 } 207 s.checkAddSpaces(c, p) 208 } 209 210 func (s *SpacesSuite) TestPublic(c *gc.C) { 211 p := checkAddSpacesParams{ 212 Name: "foo", 213 Subnets: []string{"10.0.0.0/24"}, 214 Public: true, 215 } 216 s.checkAddSpaces(c, p) 217 } 218 219 func (s *SpacesSuite) TestEmptySpaceName(c *gc.C) { 220 p := checkAddSpacesParams{ 221 Subnets: []string{"10.0.0.0/24"}, 222 Error: `"" is not a valid tag`, 223 } 224 s.checkAddSpaces(c, p) 225 } 226 227 func (s *SpacesSuite) TestNoSubnets(c *gc.C) { 228 p := checkAddSpacesParams{ 229 Name: "foo", 230 Subnets: nil, 231 } 232 s.checkAddSpaces(c, p) 233 } 234 235 func (s *SpacesSuite) TestListSpacesDefault(c *gc.C) { 236 expected := []params.Space{{ 237 Name: "default", 238 Subnets: []params.Subnet{{ 239 CIDR: "192.168.0.0/24", 240 ProviderId: "provider-192.168.0.0/24", 241 Zones: []string{"foo"}, 242 Status: "in-use", 243 SpaceTag: "space-default", 244 }, { 245 CIDR: "192.168.3.0/24", 246 ProviderId: "provider-192.168.3.0/24", 247 VLANTag: 23, 248 Zones: []string{"bar", "bam"}, 249 SpaceTag: "space-default", 250 }}, 251 }, { 252 Name: "dmz", 253 Subnets: []params.Subnet{{ 254 CIDR: "192.168.1.0/24", 255 ProviderId: "provider-192.168.1.0/24", 256 VLANTag: 23, 257 Zones: []string{"bar", "bam"}, 258 SpaceTag: "space-dmz", 259 }}, 260 }, { 261 Name: "private", 262 Subnets: []params.Subnet{{ 263 CIDR: "192.168.2.0/24", 264 ProviderId: "provider-192.168.2.0/24", 265 Zones: []string{"foo"}, 266 Status: "in-use", 267 SpaceTag: "space-private", 268 }}, 269 }} 270 spaces, err := s.facade.ListSpaces() 271 c.Assert(err, jc.ErrorIsNil) 272 c.Assert(spaces.Results, jc.DeepEquals, expected) 273 } 274 275 func (s *SpacesSuite) TestListSpacesAllSpacesError(c *gc.C) { 276 boom := errors.New("backing boom") 277 apiservertesting.BackingInstance.SetErrors(boom) 278 _, err := s.facade.ListSpaces() 279 c.Assert(err, gc.ErrorMatches, "getting environ: backing boom") 280 } 281 282 func (s *SpacesSuite) TestListSpacesSubnetsError(c *gc.C) { 283 apiservertesting.SharedStub.SetErrors( 284 nil, // Backing.ModelConfig() 285 nil, // Backing.CloudSpec() 286 nil, // Provider.Open() 287 nil, // ZonedNetworkingEnviron.SupportsSpaces() 288 nil, // Backing.AllSpaces() 289 errors.New("space0 subnets failed"), // Space.Subnets() 290 errors.New("space1 subnets failed"), // Space.Subnets() 291 errors.New("space2 subnets failed"), // Space.Subnets() 292 ) 293 294 results, err := s.facade.ListSpaces() 295 for i, space := range results.Results { 296 errmsg := fmt.Sprintf("fetching subnets: space%d subnets failed", i) 297 c.Assert(space.Error, gc.ErrorMatches, errmsg) 298 } 299 c.Assert(err, jc.ErrorIsNil) 300 } 301 302 func (s *SpacesSuite) TestListSpacesSubnetsSingleSubnetError(c *gc.C) { 303 boom := errors.New("boom") 304 apiservertesting.SharedStub.SetErrors( 305 nil, // Backing.ModelConfig() 306 nil, // Backing.CloudSpec() 307 nil, // Provider.Open() 308 nil, // ZonedNetworkingEnviron.SupportsSpaces() 309 nil, // Backing.AllSpaces() 310 nil, // Space.Subnets() (1st no error) 311 boom, // Space.Subnets() (2nd with error) 312 ) 313 314 results, err := s.facade.ListSpaces() 315 for i, space := range results.Results { 316 if i == 1 { 317 c.Assert(space.Error, gc.ErrorMatches, "fetching subnets: boom") 318 } else { 319 c.Assert(space.Error, gc.IsNil) 320 } 321 } 322 c.Assert(err, jc.ErrorIsNil) 323 } 324 325 func (s *SpacesSuite) TestCreateSpacesModelConfigError(c *gc.C) { 326 apiservertesting.SharedStub.SetErrors( 327 errors.New("boom"), // Backing.ModelConfig() 328 ) 329 330 spaces := params.CreateSpacesParams{} 331 _, err := s.facade.CreateSpaces(spaces) 332 c.Assert(err, gc.ErrorMatches, "getting environ: boom") 333 } 334 335 func (s *SpacesSuite) TestCreateSpacesProviderOpenError(c *gc.C) { 336 apiservertesting.SharedStub.SetErrors( 337 nil, // Backing.ModelConfig() 338 nil, // Backing.CloudSpec() 339 errors.New("boom"), // Provider.Open() 340 ) 341 342 spaces := params.CreateSpacesParams{} 343 _, err := s.facade.CreateSpaces(spaces) 344 c.Assert(err, gc.ErrorMatches, "getting environ: boom") 345 } 346 347 func (s *SpacesSuite) TestCreateSpacesNotSupportedError(c *gc.C) { 348 apiservertesting.SharedStub.SetErrors( 349 nil, // Backing.ModelConfig() 350 nil, // Backing.CloudSpec() 351 nil, // Provider.Open() 352 errors.NotSupportedf("spaces"), // ZonedNetworkingEnviron.SupportsSpaces() 353 ) 354 355 spaces := params.CreateSpacesParams{} 356 _, err := s.facade.CreateSpaces(spaces) 357 c.Assert(err, gc.ErrorMatches, "spaces not supported") 358 } 359 360 func (s *SpacesSuite) TestListSpacesNotSupportedError(c *gc.C) { 361 apiservertesting.SharedStub.SetErrors( 362 nil, // Backing.ModelConfig() 363 nil, // Backing.CloudSpec() 364 nil, // Provider.Open 365 errors.NotSupportedf("spaces"), // ZonedNetworkingEnviron.SupportsSpaces() 366 ) 367 368 _, err := s.facade.ListSpaces() 369 c.Assert(err, gc.ErrorMatches, "spaces not supported") 370 } 371 372 func (s *SpacesSuite) TestReloadSpacesNotSupportedError(c *gc.C) { 373 apiservertesting.SharedStub.SetErrors( 374 nil, // Backing.ModelConfig() 375 nil, // Backing.CloudSpec() 376 nil, // Provider.Open() 377 errors.NotSupportedf("spaces"), // ZonedNetworkingEnviron.SupportsSpaces() 378 ) 379 err := s.facade.ReloadSpaces() 380 c.Assert(err, gc.ErrorMatches, "spaces not supported") 381 } 382 383 func (s *SpacesSuite) TestReloadSpacesUserDenied(c *gc.C) { 384 agentAuthorizer := s.authorizer 385 agentAuthorizer.Tag = names.NewUserTag("regular") 386 facade, err := spaces.NewAPIWithBacking( 387 apiservertesting.BackingInstance, 388 context.NewCloudCallContext(), 389 s.resources, agentAuthorizer, 390 ) 391 c.Assert(err, jc.ErrorIsNil) 392 err = facade.ReloadSpaces() 393 c.Check(err, gc.ErrorMatches, "permission denied") 394 apiservertesting.CheckMethodCalls(c, apiservertesting.SharedStub) 395 }