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  }