github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/apiserver/controller/controller_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package controller_test 5 6 import ( 7 "time" 8 9 "github.com/juju/loggo" 10 "github.com/juju/names" 11 jc "github.com/juju/testing/checkers" 12 "github.com/juju/utils" 13 gc "gopkg.in/check.v1" 14 15 "github.com/juju/juju/apiserver" 16 "github.com/juju/juju/apiserver/common" 17 "github.com/juju/juju/apiserver/controller" 18 "github.com/juju/juju/apiserver/params" 19 apiservertesting "github.com/juju/juju/apiserver/testing" 20 jujutesting "github.com/juju/juju/juju/testing" 21 "github.com/juju/juju/state" 22 "github.com/juju/juju/state/multiwatcher" 23 "github.com/juju/juju/testing" 24 "github.com/juju/juju/testing/factory" 25 ) 26 27 type controllerSuite struct { 28 jujutesting.JujuConnSuite 29 30 controller *controller.ControllerAPI 31 resources *common.Resources 32 authorizer apiservertesting.FakeAuthorizer 33 } 34 35 var _ = gc.Suite(&controllerSuite{}) 36 37 func (s *controllerSuite) SetUpTest(c *gc.C) { 38 s.JujuConnSuite.SetUpTest(c) 39 s.resources = common.NewResources() 40 s.AddCleanup(func(_ *gc.C) { s.resources.StopAll() }) 41 42 s.authorizer = apiservertesting.FakeAuthorizer{ 43 Tag: s.AdminUserTag(c), 44 } 45 46 controller, err := controller.NewControllerAPI(s.State, s.resources, s.authorizer) 47 c.Assert(err, jc.ErrorIsNil) 48 s.controller = controller 49 50 loggo.GetLogger("juju.apiserver.controller").SetLogLevel(loggo.TRACE) 51 } 52 53 func (s *controllerSuite) TestNewAPIRefusesNonClient(c *gc.C) { 54 anAuthoriser := apiservertesting.FakeAuthorizer{ 55 Tag: names.NewUnitTag("mysql/0"), 56 } 57 endPoint, err := controller.NewControllerAPI(s.State, s.resources, anAuthoriser) 58 c.Assert(endPoint, gc.IsNil) 59 c.Assert(err, gc.ErrorMatches, "permission denied") 60 } 61 62 func (s *controllerSuite) TestNewAPIRefusesNonAdmins(c *gc.C) { 63 user := s.Factory.MakeUser(c, &factory.UserParams{NoModelUser: true}) 64 anAuthoriser := apiservertesting.FakeAuthorizer{ 65 Tag: user.Tag(), 66 } 67 endPoint, err := controller.NewControllerAPI(s.State, s.resources, anAuthoriser) 68 c.Assert(endPoint, gc.IsNil) 69 c.Assert(err, gc.ErrorMatches, "permission denied") 70 } 71 72 func (s *controllerSuite) checkEnvironmentMatches(c *gc.C, env params.Model, expected *state.Model) { 73 c.Check(env.Name, gc.Equals, expected.Name()) 74 c.Check(env.UUID, gc.Equals, expected.UUID()) 75 c.Check(env.OwnerTag, gc.Equals, expected.Owner().String()) 76 } 77 78 func (s *controllerSuite) TestAllModels(c *gc.C) { 79 admin := s.Factory.MakeUser(c, &factory.UserParams{Name: "foobar"}) 80 81 s.Factory.MakeModel(c, &factory.ModelParams{ 82 Name: "owned", Owner: admin.UserTag()}).Close() 83 remoteUserTag := names.NewUserTag("user@remote") 84 st := s.Factory.MakeModel(c, &factory.ModelParams{ 85 Name: "user", Owner: remoteUserTag}) 86 defer st.Close() 87 st.AddModelUser(state.ModelUserSpec{ 88 User: admin.UserTag(), 89 CreatedBy: remoteUserTag, 90 DisplayName: "Foo Bar"}) 91 92 s.Factory.MakeModel(c, &factory.ModelParams{ 93 Name: "no-access", Owner: remoteUserTag}).Close() 94 95 response, err := s.controller.AllModels() 96 c.Assert(err, jc.ErrorIsNil) 97 // The results are sorted. 98 expected := []string{"admin", "no-access", "owned", "user"} 99 var obtained []string 100 for _, env := range response.UserModels { 101 obtained = append(obtained, env.Name) 102 stateEnv, err := s.State.GetModel(names.NewModelTag(env.UUID)) 103 c.Assert(err, jc.ErrorIsNil) 104 s.checkEnvironmentMatches(c, env.Model, stateEnv) 105 } 106 c.Assert(obtained, jc.DeepEquals, expected) 107 } 108 109 func (s *controllerSuite) TestListBlockedModels(c *gc.C) { 110 st := s.Factory.MakeModel(c, &factory.ModelParams{ 111 Name: "test"}) 112 defer st.Close() 113 114 s.State.SwitchBlockOn(state.DestroyBlock, "TestBlockDestroyModel") 115 s.State.SwitchBlockOn(state.ChangeBlock, "TestChangeBlock") 116 st.SwitchBlockOn(state.DestroyBlock, "TestBlockDestroyModel") 117 st.SwitchBlockOn(state.ChangeBlock, "TestChangeBlock") 118 119 list, err := s.controller.ListBlockedModels() 120 c.Assert(err, jc.ErrorIsNil) 121 122 c.Assert(list.Models, jc.DeepEquals, []params.ModelBlockInfo{ 123 params.ModelBlockInfo{ 124 Name: "admin", 125 UUID: s.State.ModelUUID(), 126 OwnerTag: s.AdminUserTag(c).String(), 127 Blocks: []string{ 128 "BlockDestroy", 129 "BlockChange", 130 }, 131 }, 132 params.ModelBlockInfo{ 133 Name: "test", 134 UUID: st.ModelUUID(), 135 OwnerTag: s.AdminUserTag(c).String(), 136 Blocks: []string{ 137 "BlockDestroy", 138 "BlockChange", 139 }, 140 }, 141 }) 142 143 } 144 145 func (s *controllerSuite) TestListBlockedModelsNoBlocks(c *gc.C) { 146 list, err := s.controller.ListBlockedModels() 147 c.Assert(err, jc.ErrorIsNil) 148 c.Assert(list.Models, gc.HasLen, 0) 149 } 150 151 func (s *controllerSuite) TestModelConfig(c *gc.C) { 152 env, err := s.controller.ModelConfig() 153 c.Assert(err, jc.ErrorIsNil) 154 c.Assert(env.Config["name"], gc.Equals, "admin") 155 } 156 157 func (s *controllerSuite) TestModelConfigFromNonController(c *gc.C) { 158 st := s.Factory.MakeModel(c, &factory.ModelParams{ 159 Name: "test"}) 160 defer st.Close() 161 162 authorizer := &apiservertesting.FakeAuthorizer{Tag: s.AdminUserTag(c)} 163 controller, err := controller.NewControllerAPI(st, common.NewResources(), authorizer) 164 c.Assert(err, jc.ErrorIsNil) 165 env, err := controller.ModelConfig() 166 c.Assert(err, jc.ErrorIsNil) 167 c.Assert(env.Config["name"], gc.Equals, "admin") 168 } 169 170 func (s *controllerSuite) TestRemoveBlocks(c *gc.C) { 171 st := s.Factory.MakeModel(c, &factory.ModelParams{ 172 Name: "test"}) 173 defer st.Close() 174 175 s.State.SwitchBlockOn(state.DestroyBlock, "TestBlockDestroyModel") 176 s.State.SwitchBlockOn(state.ChangeBlock, "TestChangeBlock") 177 st.SwitchBlockOn(state.DestroyBlock, "TestBlockDestroyModel") 178 st.SwitchBlockOn(state.ChangeBlock, "TestChangeBlock") 179 180 err := s.controller.RemoveBlocks(params.RemoveBlocksArgs{All: true}) 181 c.Assert(err, jc.ErrorIsNil) 182 183 blocks, err := s.State.AllBlocksForController() 184 c.Assert(err, jc.ErrorIsNil) 185 c.Assert(blocks, gc.HasLen, 0) 186 } 187 188 func (s *controllerSuite) TestRemoveBlocksNotAll(c *gc.C) { 189 err := s.controller.RemoveBlocks(params.RemoveBlocksArgs{}) 190 c.Assert(err, gc.ErrorMatches, "not supported") 191 } 192 193 func (s *controllerSuite) TestWatchAllModels(c *gc.C) { 194 watcherId, err := s.controller.WatchAllModels() 195 c.Assert(err, jc.ErrorIsNil) 196 197 watcherAPI_, err := apiserver.NewAllWatcher(s.State, s.resources, s.authorizer, watcherId.AllWatcherId) 198 c.Assert(err, jc.ErrorIsNil) 199 watcherAPI := watcherAPI_.(*apiserver.SrvAllWatcher) 200 defer func() { 201 err := watcherAPI.Stop() 202 c.Assert(err, jc.ErrorIsNil) 203 }() 204 205 resultC := make(chan params.AllWatcherNextResults) 206 go func() { 207 result, err := watcherAPI.Next() 208 c.Assert(err, jc.ErrorIsNil) 209 resultC <- result 210 }() 211 212 select { 213 case result := <-resultC: 214 // Expect to see the initial environment be reported. 215 deltas := result.Deltas 216 c.Assert(deltas, gc.HasLen, 1) 217 envInfo := deltas[0].Entity.(*multiwatcher.ModelInfo) 218 c.Assert(envInfo.ModelUUID, gc.Equals, s.State.ModelUUID()) 219 case <-time.After(testing.LongWait): 220 c.Fatal("timed out") 221 } 222 } 223 224 func (s *controllerSuite) TestModelStatus(c *gc.C) { 225 otherEnvOwner := s.Factory.MakeModelUser(c, nil) 226 otherSt := s.Factory.MakeModel(c, &factory.ModelParams{ 227 Name: "dummytoo", 228 Owner: otherEnvOwner.UserTag(), 229 ConfigAttrs: testing.Attrs{ 230 "controller": false, 231 }, 232 }) 233 defer otherSt.Close() 234 235 s.Factory.MakeMachine(c, &factory.MachineParams{Jobs: []state.MachineJob{state.JobManageModel}}) 236 s.Factory.MakeMachine(c, &factory.MachineParams{Jobs: []state.MachineJob{state.JobHostUnits}}) 237 s.Factory.MakeService(c, &factory.ServiceParams{ 238 Charm: s.Factory.MakeCharm(c, nil), 239 }) 240 241 otherFactory := factory.NewFactory(otherSt) 242 otherFactory.MakeMachine(c, nil) 243 otherFactory.MakeMachine(c, nil) 244 otherFactory.MakeService(c, &factory.ServiceParams{ 245 Charm: otherFactory.MakeCharm(c, nil), 246 }) 247 248 controllerEnvTag := s.State.ModelTag().String() 249 hostedEnvTag := otherSt.ModelTag().String() 250 251 req := params.Entities{ 252 Entities: []params.Entity{{Tag: controllerEnvTag}, {Tag: hostedEnvTag}}, 253 } 254 results, err := s.controller.ModelStatus(req) 255 c.Assert(err, jc.ErrorIsNil) 256 c.Assert(results.Results, gc.DeepEquals, []params.ModelStatus{{ 257 ModelTag: controllerEnvTag, 258 HostedMachineCount: 1, 259 ServiceCount: 1, 260 OwnerTag: "user-admin@local", 261 Life: params.Alive, 262 }, { 263 ModelTag: hostedEnvTag, 264 HostedMachineCount: 2, 265 ServiceCount: 1, 266 OwnerTag: otherEnvOwner.UserTag().String(), 267 Life: params.Alive, 268 }}) 269 } 270 271 func (s *controllerSuite) TestInitiateModelMigration(c *gc.C) { 272 // Create two hosted models to migrate. 273 st1 := s.Factory.MakeModel(c, nil) 274 defer st1.Close() 275 276 st2 := s.Factory.MakeModel(c, nil) 277 defer st2.Close() 278 279 // Kick off the migration. 280 args := params.InitiateModelMigrationArgs{ 281 Specs: []params.ModelMigrationSpec{ 282 { 283 ModelTag: st1.ModelTag().String(), 284 TargetInfo: params.ModelMigrationTargetInfo{ 285 ControllerTag: randomModelTag(), 286 Addrs: []string{"1.1.1.1:1111", "2.2.2.2:2222"}, 287 CACert: "cert1", 288 AuthTag: names.NewUserTag("admin1").String(), 289 Password: "secret1", 290 }, 291 }, { 292 ModelTag: st2.ModelTag().String(), 293 TargetInfo: params.ModelMigrationTargetInfo{ 294 ControllerTag: randomModelTag(), 295 Addrs: []string{"3.3.3.3:3333"}, 296 CACert: "cert2", 297 AuthTag: names.NewUserTag("admin2").String(), 298 Password: "secret2", 299 }, 300 }, 301 }, 302 } 303 out, err := s.controller.InitiateModelMigration(args) 304 c.Assert(err, jc.ErrorIsNil) 305 c.Assert(out.Results, gc.HasLen, 2) 306 307 states := []*state.State{st1, st2} 308 for i, spec := range args.Specs { 309 st := states[i] 310 result := out.Results[i] 311 312 c.Check(result.Error, gc.IsNil) 313 c.Check(result.ModelTag, gc.Equals, spec.ModelTag) 314 expectedId := st.ModelUUID() + ":0" 315 c.Check(result.Id, gc.Equals, expectedId) 316 317 // Ensure the migration made it into the DB correctly. 318 mig, err := st.GetModelMigration() 319 c.Assert(err, jc.ErrorIsNil) 320 c.Check(mig.Id(), gc.Equals, expectedId) 321 c.Check(mig.ModelUUID(), gc.Equals, st.ModelUUID()) 322 c.Check(mig.InitiatedBy(), gc.Equals, s.AdminUserTag(c).Id()) 323 targetInfo, err := mig.TargetInfo() 324 c.Assert(err, jc.ErrorIsNil) 325 c.Check(targetInfo.ControllerTag.String(), gc.Equals, spec.TargetInfo.ControllerTag) 326 c.Check(targetInfo.Addrs, jc.SameContents, spec.TargetInfo.Addrs) 327 c.Check(targetInfo.CACert, gc.Equals, spec.TargetInfo.CACert) 328 c.Check(targetInfo.AuthTag.String(), gc.Equals, spec.TargetInfo.AuthTag) 329 c.Check(targetInfo.Password, gc.Equals, spec.TargetInfo.Password) 330 } 331 } 332 333 func (s *controllerSuite) TestInitiateModelMigrationValidationError(c *gc.C) { 334 // Create a hosted model to migrate. 335 st := s.Factory.MakeModel(c, nil) 336 defer st.Close() 337 338 // Kick off the migration with missing details. 339 args := params.InitiateModelMigrationArgs{ 340 Specs: []params.ModelMigrationSpec{{ 341 ModelTag: st.ModelTag().String(), 342 // TargetInfo missing 343 }}, 344 } 345 out, err := s.controller.InitiateModelMigration(args) 346 c.Assert(err, jc.ErrorIsNil) 347 c.Assert(out.Results, gc.HasLen, 1) 348 result := out.Results[0] 349 c.Check(result.ModelTag, gc.Equals, args.Specs[0].ModelTag) 350 c.Check(result.Id, gc.Equals, "") 351 c.Check(result.Error, gc.ErrorMatches, "controller tag: .+ is not a valid tag") 352 } 353 354 func (s *controllerSuite) TestInitiateModelMigrationPartialFailure(c *gc.C) { 355 st := s.Factory.MakeModel(c, nil) 356 defer st.Close() 357 358 args := params.InitiateModelMigrationArgs{ 359 Specs: []params.ModelMigrationSpec{ 360 { 361 ModelTag: st.ModelTag().String(), 362 TargetInfo: params.ModelMigrationTargetInfo{ 363 ControllerTag: randomModelTag(), 364 Addrs: []string{"1.1.1.1:1111", "2.2.2.2:2222"}, 365 CACert: "cert", 366 AuthTag: names.NewUserTag("admin").String(), 367 Password: "secret", 368 }, 369 }, { 370 ModelTag: randomModelTag(), // Doesn't exist. 371 }, 372 }, 373 } 374 out, err := s.controller.InitiateModelMigration(args) 375 c.Assert(err, jc.ErrorIsNil) 376 c.Assert(out.Results, gc.HasLen, 2) 377 378 c.Check(out.Results[0].ModelTag, gc.Equals, st.ModelTag().String()) 379 c.Check(out.Results[0].Error, gc.IsNil) 380 381 c.Check(out.Results[1].ModelTag, gc.Equals, args.Specs[1].ModelTag) 382 c.Check(out.Results[1].Error, gc.ErrorMatches, "unable to read model: .+") 383 } 384 385 func randomModelTag() string { 386 uuid := utils.MustNewUUID().String() 387 return names.NewModelTag(uuid).String() 388 }