github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/controller/firewaller/firewaller_base_test.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package firewaller_test 5 6 import ( 7 "github.com/juju/errors" 8 jc "github.com/juju/testing/checkers" 9 gc "gopkg.in/check.v1" 10 11 "github.com/juju/juju/apiserver/common" 12 "github.com/juju/juju/apiserver/facade" 13 "github.com/juju/juju/apiserver/params" 14 apiservertesting "github.com/juju/juju/apiserver/testing" 15 "github.com/juju/juju/core/instance" 16 "github.com/juju/juju/juju/testing" 17 "github.com/juju/juju/state" 18 statetesting "github.com/juju/juju/state/testing" 19 ) 20 21 // firewallerBaseSuite implements common testing suite for all API 22 // versions. It's not intended to be used directly or registered as a 23 // suite, but embedded. 24 type firewallerBaseSuite struct { 25 testing.JujuConnSuite 26 27 machines []*state.Machine 28 application *state.Application 29 charm *state.Charm 30 units []*state.Unit 31 relations []*state.Relation 32 33 authorizer apiservertesting.FakeAuthorizer 34 resources *common.Resources 35 } 36 37 func (s *firewallerBaseSuite) setUpTest(c *gc.C) { 38 s.JujuConnSuite.SetUpTest(c) 39 40 // Reset previous machines and units (if any) and create 3 41 // machines for the tests. 42 s.machines = nil 43 s.units = nil 44 // Note that the specific machine ids allocated are assumed 45 // to be numerically consecutive from zero. 46 for i := 0; i <= 2; i++ { 47 machine, err := s.State.AddMachine("quantal", state.JobHostUnits) 48 c.Check(err, jc.ErrorIsNil) 49 s.machines = append(s.machines, machine) 50 } 51 // Create an application and three units for these machines. 52 s.charm = s.AddTestingCharm(c, "wordpress") 53 s.application = s.AddTestingApplication(c, "wordpress", s.charm) 54 // Add the rest of the units and assign them. 55 for i := 0; i <= 2; i++ { 56 unit, err := s.application.AddUnit(state.AddUnitParams{}) 57 c.Check(err, jc.ErrorIsNil) 58 err = unit.AssignToMachine(s.machines[i]) 59 c.Check(err, jc.ErrorIsNil) 60 s.units = append(s.units, unit) 61 } 62 63 // Create a relation. 64 s.AddTestingApplication(c, "mysql", s.AddTestingCharm(c, "mysql")) 65 eps, err := s.State.InferEndpoints("wordpress", "mysql") 66 c.Assert(err, jc.ErrorIsNil) 67 68 s.relations = make([]*state.Relation, 1) 69 s.relations[0], err = s.State.AddRelation(eps...) 70 c.Assert(err, jc.ErrorIsNil) 71 72 // Create a FakeAuthorizer so we can check permissions, 73 // set up assuming we logged in as the controller. 74 s.authorizer = apiservertesting.FakeAuthorizer{ 75 Controller: true, 76 } 77 78 // Create the resource registry separately to track invocations to 79 // Register. 80 s.resources = common.NewResources() 81 } 82 83 func (s *firewallerBaseSuite) testFirewallerFailsWithNonControllerUser( 84 c *gc.C, 85 factory func(_ *state.State, _ facade.Resources, _ facade.Authorizer) error, 86 ) { 87 anAuthorizer := s.authorizer 88 anAuthorizer.Controller = false 89 err := factory(s.State, s.resources, anAuthorizer) 90 c.Assert(err, gc.NotNil) 91 c.Assert(err, gc.ErrorMatches, "permission denied") 92 } 93 94 func (s *firewallerBaseSuite) testLife( 95 c *gc.C, 96 facade interface { 97 Life(args params.Entities) (params.LifeResults, error) 98 }, 99 ) { 100 // Unassign unit 1 from its machine, so we can change its life cycle. 101 err := s.units[1].UnassignFromMachine() 102 c.Assert(err, jc.ErrorIsNil) 103 104 err = s.machines[1].EnsureDead() 105 c.Assert(err, jc.ErrorIsNil) 106 s.assertLife(c, 0, state.Alive) 107 s.assertLife(c, 1, state.Dead) 108 s.assertLife(c, 2, state.Alive) 109 110 args := addFakeEntities(params.Entities{Entities: []params.Entity{ 111 {Tag: s.machines[0].Tag().String()}, 112 {Tag: s.machines[1].Tag().String()}, 113 {Tag: s.machines[2].Tag().String()}, 114 {Tag: s.relations[0].Tag().String()}, 115 }}) 116 result, err := facade.Life(args) 117 c.Assert(err, jc.ErrorIsNil) 118 c.Assert(result, jc.DeepEquals, params.LifeResults{ 119 Results: []params.LifeResult{ 120 {Life: "alive"}, 121 {Life: "dead"}, 122 {Life: "alive"}, 123 {Life: "alive"}, 124 {Error: apiservertesting.NotFoundError("machine 42")}, 125 {Error: apiservertesting.NotFoundError(`unit "foo/0"`)}, 126 {Error: apiservertesting.NotFoundError(`application "bar"`)}, 127 {Error: apiservertesting.ErrUnauthorized}, 128 {Error: apiservertesting.ErrUnauthorized}, 129 {Error: apiservertesting.ErrUnauthorized}, 130 }, 131 }) 132 133 // Remove a machine and make sure it's detected. 134 err = s.machines[1].Remove() 135 c.Assert(err, jc.ErrorIsNil) 136 err = s.machines[1].Refresh() 137 c.Assert(err, jc.Satisfies, errors.IsNotFound) 138 139 args = params.Entities{ 140 Entities: []params.Entity{ 141 {Tag: s.machines[1].Tag().String()}, 142 }, 143 } 144 result, err = facade.Life(args) 145 c.Assert(err, jc.ErrorIsNil) 146 c.Assert(result, jc.DeepEquals, params.LifeResults{ 147 Results: []params.LifeResult{ 148 {Error: apiservertesting.NotFoundError("machine 1")}, 149 }, 150 }) 151 } 152 153 func (s *firewallerBaseSuite) testInstanceId( 154 c *gc.C, 155 facade interface { 156 InstanceId(args params.Entities) (params.StringResults, error) 157 }, 158 ) { 159 // Provision 2 machines first. 160 err := s.machines[0].SetProvisioned("i-am", "", "fake_nonce", nil) 161 c.Assert(err, jc.ErrorIsNil) 162 hwChars := instance.MustParseHardware("arch=i386", "mem=4G") 163 err = s.machines[1].SetProvisioned("i-am-not", "", "fake_nonce", &hwChars) 164 c.Assert(err, jc.ErrorIsNil) 165 166 args := addFakeEntities(params.Entities{Entities: []params.Entity{ 167 {Tag: s.machines[0].Tag().String()}, 168 {Tag: s.machines[1].Tag().String()}, 169 {Tag: s.machines[2].Tag().String()}, 170 {Tag: s.application.Tag().String()}, 171 {Tag: s.units[2].Tag().String()}, 172 }}) 173 result, err := facade.InstanceId(args) 174 c.Assert(err, jc.ErrorIsNil) 175 c.Assert(result, jc.DeepEquals, params.StringResults{ 176 Results: []params.StringResult{ 177 {Result: "i-am"}, 178 {Result: "i-am-not"}, 179 {Error: apiservertesting.NotProvisionedError("2")}, 180 {Error: apiservertesting.ErrUnauthorized}, 181 {Error: apiservertesting.ErrUnauthorized}, 182 {Error: apiservertesting.NotFoundError("machine 42")}, 183 {Error: apiservertesting.ErrUnauthorized}, 184 {Error: apiservertesting.ErrUnauthorized}, 185 {Error: apiservertesting.ErrUnauthorized}, 186 {Error: apiservertesting.ErrUnauthorized}, 187 {Error: apiservertesting.ErrUnauthorized}, 188 }, 189 }) 190 } 191 192 func (s *firewallerBaseSuite) testWatchModelMachines( 193 c *gc.C, 194 facade interface { 195 WatchModelMachines() (params.StringsWatchResult, error) 196 }, 197 ) { 198 c.Assert(s.resources.Count(), gc.Equals, 0) 199 200 got, err := facade.WatchModelMachines() 201 c.Assert(err, jc.ErrorIsNil) 202 want := params.StringsWatchResult{ 203 StringsWatcherId: "1", 204 Changes: []string{"0", "1", "2"}, 205 } 206 c.Assert(got.StringsWatcherId, gc.Equals, want.StringsWatcherId) 207 c.Assert(got.Changes, jc.SameContents, want.Changes) 208 209 // Verify the resources were registered and stop them when done. 210 c.Assert(s.resources.Count(), gc.Equals, 1) 211 resource := s.resources.Get("1") 212 defer statetesting.AssertStop(c, resource) 213 214 // Check that the Watch has consumed the initial event ("returned" 215 // in the Watch call) 216 wc := statetesting.NewStringsWatcherC(c, s.State, resource.(state.StringsWatcher)) 217 wc.AssertNoChange() 218 } 219 220 const ( 221 canWatchUnits = true 222 cannotWatchUnits = false 223 ) 224 225 func (s *firewallerBaseSuite) testWatch( 226 c *gc.C, 227 watcher interface { 228 Watch(args params.Entities) (params.NotifyWatchResults, error) 229 }, 230 allowUnits bool, 231 ) { 232 c.Assert(s.resources.Count(), gc.Equals, 0) 233 234 args := addFakeEntities(params.Entities{Entities: []params.Entity{ 235 {Tag: s.machines[0].Tag().String()}, 236 {Tag: s.application.Tag().String()}, 237 {Tag: s.units[0].Tag().String()}, 238 }}) 239 result, err := watcher.Watch(args) 240 c.Assert(err, jc.ErrorIsNil) 241 if allowUnits { 242 c.Assert(result, jc.DeepEquals, params.NotifyWatchResults{ 243 Results: []params.NotifyWatchResult{ 244 {Error: apiservertesting.ErrUnauthorized}, 245 {NotifyWatcherId: "1"}, 246 {NotifyWatcherId: "2"}, 247 {Error: apiservertesting.ErrUnauthorized}, 248 {Error: apiservertesting.NotFoundError(`unit "foo/0"`)}, 249 {Error: apiservertesting.NotFoundError(`application "bar"`)}, 250 {Error: apiservertesting.ErrUnauthorized}, 251 {Error: apiservertesting.ErrUnauthorized}, 252 {Error: apiservertesting.ErrUnauthorized}, 253 }, 254 }) 255 } else { 256 c.Assert(result, jc.DeepEquals, params.NotifyWatchResults{ 257 Results: []params.NotifyWatchResult{ 258 {Error: apiservertesting.ErrUnauthorized}, 259 {NotifyWatcherId: "1"}, 260 {Error: apiservertesting.ErrUnauthorized}, 261 {Error: apiservertesting.ErrUnauthorized}, 262 {Error: apiservertesting.ErrUnauthorized}, 263 {Error: apiservertesting.NotFoundError(`application "bar"`)}, 264 {Error: apiservertesting.ErrUnauthorized}, 265 {Error: apiservertesting.ErrUnauthorized}, 266 {Error: apiservertesting.ErrUnauthorized}, 267 }, 268 }) 269 } 270 271 // Verify the resources were registered and stop when done. 272 if allowUnits { 273 c.Assert(s.resources.Count(), gc.Equals, 2) 274 } else { 275 c.Assert(s.resources.Count(), gc.Equals, 1) 276 } 277 c.Assert(result.Results[1].NotifyWatcherId, gc.Equals, "1") 278 watcher1 := s.resources.Get("1") 279 defer statetesting.AssertStop(c, watcher1) 280 var watcher2 facade.Resource 281 if allowUnits { 282 c.Assert(result.Results[2].NotifyWatcherId, gc.Equals, "2") 283 watcher2 = s.resources.Get("2") 284 defer statetesting.AssertStop(c, watcher2) 285 } 286 287 // Check that the Watch has consumed the initial event ("returned" in 288 // the Watch call) 289 wc1 := statetesting.NewNotifyWatcherC(c, s.State, watcher1.(state.NotifyWatcher)) 290 wc1.AssertNoChange() 291 if allowUnits { 292 wc2 := statetesting.NewNotifyWatcherC(c, s.State, watcher2.(state.NotifyWatcher)) 293 wc2.AssertNoChange() 294 } 295 } 296 297 func (s *firewallerBaseSuite) testWatchUnits( 298 c *gc.C, 299 facade interface { 300 WatchUnits(args params.Entities) (params.StringsWatchResults, error) 301 }, 302 ) { 303 c.Assert(s.resources.Count(), gc.Equals, 0) 304 305 args := addFakeEntities(params.Entities{Entities: []params.Entity{ 306 {Tag: s.machines[0].Tag().String()}, 307 {Tag: s.application.Tag().String()}, 308 {Tag: s.units[0].Tag().String()}, 309 }}) 310 result, err := facade.WatchUnits(args) 311 c.Assert(err, jc.ErrorIsNil) 312 c.Assert(result, jc.DeepEquals, params.StringsWatchResults{ 313 Results: []params.StringsWatchResult{ 314 {Changes: []string{"wordpress/0"}, StringsWatcherId: "1"}, 315 {Error: apiservertesting.ErrUnauthorized}, 316 {Error: apiservertesting.ErrUnauthorized}, 317 {Error: apiservertesting.NotFoundError("machine 42")}, 318 {Error: apiservertesting.ErrUnauthorized}, 319 {Error: apiservertesting.ErrUnauthorized}, 320 {Error: apiservertesting.ErrUnauthorized}, 321 {Error: apiservertesting.ErrUnauthorized}, 322 {Error: apiservertesting.ErrUnauthorized}, 323 }, 324 }) 325 326 // Verify the resource was registered and stop when done 327 c.Assert(s.resources.Count(), gc.Equals, 1) 328 c.Assert(result.Results[0].StringsWatcherId, gc.Equals, "1") 329 resource := s.resources.Get("1") 330 defer statetesting.AssertStop(c, resource) 331 332 // Check that the Watch has consumed the initial event ("returned" in 333 // the Watch call) 334 wc := statetesting.NewStringsWatcherC(c, s.State, resource.(state.StringsWatcher)) 335 wc.AssertNoChange() 336 } 337 338 func (s *firewallerBaseSuite) testGetExposed( 339 c *gc.C, 340 facade interface { 341 GetExposed(args params.Entities) (params.BoolResults, error) 342 }, 343 ) { 344 // Set the application to exposed first. 345 err := s.application.SetExposed() 346 c.Assert(err, jc.ErrorIsNil) 347 348 args := addFakeEntities(params.Entities{Entities: []params.Entity{ 349 {Tag: s.application.Tag().String()}, 350 }}) 351 result, err := facade.GetExposed(args) 352 c.Assert(err, jc.ErrorIsNil) 353 c.Assert(result, jc.DeepEquals, params.BoolResults{ 354 Results: []params.BoolResult{ 355 {Result: true}, 356 {Error: apiservertesting.ErrUnauthorized}, 357 {Error: apiservertesting.ErrUnauthorized}, 358 {Error: apiservertesting.NotFoundError(`application "bar"`)}, 359 {Error: apiservertesting.ErrUnauthorized}, 360 {Error: apiservertesting.ErrUnauthorized}, 361 {Error: apiservertesting.ErrUnauthorized}, 362 }, 363 }) 364 365 // Now reset the exposed flag for the application and check again. 366 err = s.application.ClearExposed() 367 c.Assert(err, jc.ErrorIsNil) 368 369 args = params.Entities{Entities: []params.Entity{ 370 {Tag: s.application.Tag().String()}, 371 }} 372 result, err = facade.GetExposed(args) 373 c.Assert(err, jc.ErrorIsNil) 374 c.Assert(result, jc.DeepEquals, params.BoolResults{ 375 Results: []params.BoolResult{ 376 {Result: false}, 377 }, 378 }) 379 } 380 381 func (s *firewallerBaseSuite) testGetAssignedMachine( 382 c *gc.C, 383 facade interface { 384 GetAssignedMachine(args params.Entities) (params.StringResults, error) 385 }, 386 ) { 387 // Unassign a unit first. 388 err := s.units[2].UnassignFromMachine() 389 c.Assert(err, jc.ErrorIsNil) 390 391 args := addFakeEntities(params.Entities{Entities: []params.Entity{ 392 {Tag: s.units[0].Tag().String()}, 393 {Tag: s.units[1].Tag().String()}, 394 {Tag: s.units[2].Tag().String()}, 395 }}) 396 result, err := facade.GetAssignedMachine(args) 397 c.Assert(err, jc.ErrorIsNil) 398 c.Assert(result, jc.DeepEquals, params.StringResults{ 399 Results: []params.StringResult{ 400 {Result: s.machines[0].Tag().String()}, 401 {Result: s.machines[1].Tag().String()}, 402 {Error: apiservertesting.NotAssignedError("wordpress/2")}, 403 {Error: apiservertesting.ErrUnauthorized}, 404 {Error: apiservertesting.NotFoundError(`unit "foo/0"`)}, 405 {Error: apiservertesting.ErrUnauthorized}, 406 {Error: apiservertesting.ErrUnauthorized}, 407 {Error: apiservertesting.ErrUnauthorized}, 408 {Error: apiservertesting.ErrUnauthorized}, 409 }, 410 }) 411 412 // Now reset assign unit 2 again and check. 413 err = s.units[2].AssignToMachine(s.machines[0]) 414 c.Assert(err, jc.ErrorIsNil) 415 416 args = params.Entities{Entities: []params.Entity{ 417 {Tag: s.units[2].Tag().String()}, 418 }} 419 result, err = facade.GetAssignedMachine(args) 420 c.Assert(err, jc.ErrorIsNil) 421 c.Assert(result, jc.DeepEquals, params.StringResults{ 422 Results: []params.StringResult{ 423 {Result: s.machines[0].Tag().String()}, 424 }, 425 }) 426 } 427 428 func (s *firewallerBaseSuite) assertLife(c *gc.C, index int, expectLife state.Life) { 429 err := s.machines[index].Refresh() 430 c.Assert(err, jc.ErrorIsNil) 431 c.Assert(s.machines[index].Life(), gc.Equals, expectLife) 432 } 433 434 var commonFakeEntities = []params.Entity{ 435 {Tag: "machine-42"}, 436 {Tag: "unit-foo-0"}, 437 {Tag: "application-bar"}, 438 {Tag: "user-foo"}, 439 {Tag: "foo-bar"}, 440 {Tag: ""}, 441 } 442 443 func addFakeEntities(actual params.Entities) params.Entities { 444 for _, entity := range commonFakeEntities { 445 actual.Entities = append(actual.Entities, entity) 446 } 447 return actual 448 }