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