github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/apiserver/modelmanager/modelmanager_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package modelmanager_test
     5  
     6  import (
     7  	"regexp"
     8  	"runtime"
     9  	"time"
    10  
    11  	"github.com/juju/errors"
    12  	"github.com/juju/loggo"
    13  	gitjujutesting "github.com/juju/testing"
    14  	jc "github.com/juju/testing/checkers"
    15  	gc "gopkg.in/check.v1"
    16  	"gopkg.in/juju/names.v2"
    17  
    18  	"github.com/juju/juju/apiserver/modelmanager"
    19  	"github.com/juju/juju/apiserver/params"
    20  	apiservertesting "github.com/juju/juju/apiserver/testing"
    21  	"github.com/juju/juju/cloud"
    22  	"github.com/juju/juju/environs"
    23  	"github.com/juju/juju/environs/config"
    24  	jujutesting "github.com/juju/juju/juju/testing"
    25  	"github.com/juju/juju/permission"
    26  	"github.com/juju/juju/state/stateenvirons"
    27  	"github.com/juju/juju/status"
    28  	jujuversion "github.com/juju/juju/version"
    29  	// Register the providers for the field check test
    30  	"github.com/juju/juju/apiserver/common"
    31  	_ "github.com/juju/juju/provider/azure"
    32  	"github.com/juju/juju/provider/dummy"
    33  	_ "github.com/juju/juju/provider/ec2"
    34  	_ "github.com/juju/juju/provider/joyent"
    35  	_ "github.com/juju/juju/provider/maas"
    36  	_ "github.com/juju/juju/provider/openstack"
    37  	"github.com/juju/juju/state"
    38  	coretesting "github.com/juju/juju/testing"
    39  	"github.com/juju/juju/testing/factory"
    40  )
    41  
    42  type modelManagerBaseSuite struct {
    43  }
    44  
    45  type modelManagerSuite struct {
    46  	gitjujutesting.IsolationSuite
    47  	st         *mockState
    48  	authoriser apiservertesting.FakeAuthorizer
    49  	api        *modelmanager.ModelManagerAPI
    50  }
    51  
    52  var _ = gc.Suite(&modelManagerSuite{})
    53  
    54  func (s *modelManagerSuite) SetUpTest(c *gc.C) {
    55  	s.IsolationSuite.SetUpTest(c)
    56  
    57  	attrs := dummy.SampleConfig()
    58  	attrs["agent-version"] = jujuversion.Current.String()
    59  	cfg, err := config.New(config.UseDefaults, attrs)
    60  	c.Assert(err, jc.ErrorIsNil)
    61  
    62  	dummyCloud := cloud.Cloud{
    63  		Type:      "dummy",
    64  		AuthTypes: []cloud.AuthType{cloud.EmptyAuthType},
    65  		Regions: []cloud.Region{
    66  			{Name: "some-region"},
    67  			{Name: "qux"},
    68  		},
    69  	}
    70  
    71  	s.st = &mockState{
    72  		modelUUID: coretesting.ModelTag.Id(),
    73  		cloud:     dummyCloud,
    74  		clouds: map[names.CloudTag]cloud.Cloud{
    75  			names.NewCloudTag("some-cloud"): dummyCloud,
    76  		},
    77  		controllerModel: &mockModel{
    78  			owner: names.NewUserTag("admin@local"),
    79  			life:  state.Alive,
    80  			cfg:   cfg,
    81  			status: status.StatusInfo{
    82  				Status: status.Available,
    83  				Since:  &time.Time{},
    84  			},
    85  			users: []*mockModelUser{{
    86  				userName: "admin",
    87  				access:   permission.AdminAccess,
    88  			}, {
    89  				userName: "otheruser",
    90  				access:   permission.WriteAccess,
    91  			}},
    92  		},
    93  		model: &mockModel{
    94  			owner: names.NewUserTag("admin@local"),
    95  			life:  state.Alive,
    96  			tag:   coretesting.ModelTag,
    97  			cfg:   cfg,
    98  			status: status.StatusInfo{
    99  				Status: status.Available,
   100  				Since:  &time.Time{},
   101  			},
   102  			users: []*mockModelUser{{
   103  				userName: "admin",
   104  				access:   permission.AdminAccess,
   105  			}, {
   106  				userName: "otheruser",
   107  				access:   permission.WriteAccess,
   108  			}},
   109  		},
   110  		cred: cloud.NewEmptyCredential(),
   111  		cfgDefaults: config.ModelDefaultAttributes{
   112  			"attr": config.AttributeDefaultValues{
   113  				Default:    "",
   114  				Controller: "val",
   115  				Regions: []config.RegionDefaultValue{{
   116  					Name:  "dummy",
   117  					Value: "val++"}}},
   118  			"attr2": config.AttributeDefaultValues{
   119  				Controller: "val3",
   120  				Default:    "val2",
   121  				Regions: []config.RegionDefaultValue{{
   122  					Name:  "left",
   123  					Value: "spam"}}},
   124  		},
   125  	}
   126  	s.authoriser = apiservertesting.FakeAuthorizer{
   127  		Tag: names.NewUserTag("admin@local"),
   128  	}
   129  	api, err := modelmanager.NewModelManagerAPI(s.st, nil, s.authoriser)
   130  	c.Assert(err, jc.ErrorIsNil)
   131  	s.api = api
   132  }
   133  
   134  func (s *modelManagerSuite) setAPIUser(c *gc.C, user names.UserTag) {
   135  	s.authoriser.Tag = user
   136  	mm, err := modelmanager.NewModelManagerAPI(s.st, nil, s.authoriser)
   137  	c.Assert(err, jc.ErrorIsNil)
   138  	s.api = mm
   139  }
   140  
   141  func (s *modelManagerSuite) getModelArgs(c *gc.C) state.ModelArgs {
   142  	for _, v := range s.st.Calls() {
   143  		if v.Args == nil {
   144  			continue
   145  		}
   146  		if newModelArgs, ok := v.Args[0].(state.ModelArgs); ok {
   147  			return newModelArgs
   148  		}
   149  	}
   150  	c.Fatal("failed to find state.ModelArgs")
   151  	panic("unreachable")
   152  }
   153  
   154  func (s *modelManagerSuite) TestCreateModelArgs(c *gc.C) {
   155  	args := params.ModelCreateArgs{
   156  		Name:     "foo",
   157  		OwnerTag: "user-admin@local",
   158  		Config: map[string]interface{}{
   159  			"bar": "baz",
   160  		},
   161  		CloudRegion:        "qux",
   162  		CloudCredentialTag: "cloudcred-some-cloud_admin@local_some-credential",
   163  	}
   164  	_, err := s.api.CreateModel(args)
   165  	c.Assert(err, jc.ErrorIsNil)
   166  	s.st.CheckCallNames(c,
   167  		"ControllerTag",
   168  		"ModelUUID",
   169  		"ControllerTag",
   170  		"ControllerModel",
   171  		"Cloud",
   172  		"CloudCredential",
   173  		"ControllerConfig",
   174  		"ComposeNewModelConfig",
   175  		"NewModel",
   176  		"ForModel",
   177  		"Model",
   178  		"ControllerConfig",
   179  		"LastModelConnection",
   180  		"LastModelConnection",
   181  		"AllMachines",
   182  		"Close",
   183  		"Close",
   184  	)
   185  
   186  	// We cannot predict the UUID, because it's generated,
   187  	// so we just extract it and ensure that it's not the
   188  	// same as the controller UUID.
   189  	newModelArgs := s.getModelArgs(c)
   190  	uuid := newModelArgs.Config.UUID()
   191  	c.Assert(uuid, gc.Not(gc.Equals), s.st.controllerModel.cfg.UUID())
   192  
   193  	cfg, err := config.New(config.UseDefaults, map[string]interface{}{
   194  		"name":          "foo",
   195  		"type":          "dummy",
   196  		"uuid":          uuid,
   197  		"agent-version": jujuversion.Current.String(),
   198  		"bar":           "baz",
   199  		"controller":    false,
   200  		"broken":        "",
   201  		"secret":        "pork",
   202  		"something":     "value",
   203  	})
   204  	c.Assert(err, jc.ErrorIsNil)
   205  
   206  	c.Assert(newModelArgs.StorageProviderRegistry, gc.NotNil)
   207  	newModelArgs.StorageProviderRegistry = nil
   208  
   209  	c.Assert(newModelArgs, jc.DeepEquals, state.ModelArgs{
   210  		Owner:       names.NewUserTag("admin@local"),
   211  		CloudName:   "some-cloud",
   212  		CloudRegion: "qux",
   213  		CloudCredential: names.NewCloudCredentialTag(
   214  			"some-cloud/admin@local/some-credential",
   215  		),
   216  		Config: cfg,
   217  	})
   218  }
   219  
   220  func (s *modelManagerSuite) TestCreateModelArgsWithCloud(c *gc.C) {
   221  	args := params.ModelCreateArgs{
   222  		Name:     "foo",
   223  		OwnerTag: "user-admin@local",
   224  		Config: map[string]interface{}{
   225  			"bar": "baz",
   226  		},
   227  		CloudTag:           "cloud-some-cloud",
   228  		CloudRegion:        "qux",
   229  		CloudCredentialTag: "cloudcred-some-cloud_admin@local_some-credential",
   230  	}
   231  	_, err := s.api.CreateModel(args)
   232  	c.Assert(err, jc.ErrorIsNil)
   233  
   234  	newModelArgs := s.getModelArgs(c)
   235  	c.Assert(newModelArgs.CloudName, gc.Equals, "some-cloud")
   236  }
   237  
   238  func (s *modelManagerSuite) TestCreateModelArgsWithCloudNotFound(c *gc.C) {
   239  	s.st.SetErrors(nil, errors.NotFoundf("cloud"))
   240  	args := params.ModelCreateArgs{
   241  		Name:     "foo",
   242  		OwnerTag: "user-admin@local",
   243  		CloudTag: "cloud-some-unknown-cloud",
   244  	}
   245  	_, err := s.api.CreateModel(args)
   246  	c.Assert(err, gc.ErrorMatches, `cloud "some-unknown-cloud" not found, expected one of \["some-cloud"\]`)
   247  }
   248  
   249  func (s *modelManagerSuite) TestCreateModelDefaultRegion(c *gc.C) {
   250  	args := params.ModelCreateArgs{
   251  		Name:     "foo",
   252  		OwnerTag: "user-admin@local",
   253  	}
   254  	_, err := s.api.CreateModel(args)
   255  	c.Assert(err, jc.ErrorIsNil)
   256  
   257  	newModelArgs := s.getModelArgs(c)
   258  	c.Assert(newModelArgs.CloudRegion, gc.Equals, "some-region")
   259  }
   260  
   261  func (s *modelManagerSuite) TestCreateModelDefaultCredentialAdmin(c *gc.C) {
   262  	s.testCreateModelDefaultCredentialAdmin(c, "user-admin@local")
   263  }
   264  
   265  func (s *modelManagerSuite) TestCreateModelDefaultCredentialAdminNoDomain(c *gc.C) {
   266  	s.testCreateModelDefaultCredentialAdmin(c, "user-admin")
   267  }
   268  
   269  func (s *modelManagerSuite) testCreateModelDefaultCredentialAdmin(c *gc.C, ownerTag string) {
   270  	s.st.cloud.AuthTypes = []cloud.AuthType{"userpass"}
   271  	args := params.ModelCreateArgs{
   272  		Name:     "foo",
   273  		OwnerTag: ownerTag,
   274  	}
   275  	_, err := s.api.CreateModel(args)
   276  	c.Assert(err, jc.ErrorIsNil)
   277  
   278  	newModelArgs := s.getModelArgs(c)
   279  	c.Assert(newModelArgs.CloudCredential, gc.Equals, names.NewCloudCredentialTag(
   280  		"some-cloud/bob@local/some-credential",
   281  	))
   282  }
   283  
   284  func (s *modelManagerSuite) TestCreateModelEmptyCredentialNonAdmin(c *gc.C) {
   285  	args := params.ModelCreateArgs{
   286  		Name:     "foo",
   287  		OwnerTag: "user-bob@local",
   288  	}
   289  	_, err := s.api.CreateModel(args)
   290  	c.Assert(err, jc.ErrorIsNil)
   291  
   292  	newModelArgs := s.getModelArgs(c)
   293  	c.Assert(newModelArgs.CloudCredential, gc.Equals, names.CloudCredentialTag{})
   294  }
   295  
   296  func (s *modelManagerSuite) TestCreateModelNoDefaultCredentialNonAdmin(c *gc.C) {
   297  	s.st.cloud.AuthTypes = nil
   298  	args := params.ModelCreateArgs{
   299  		Name:     "foo",
   300  		OwnerTag: "user-bob@local",
   301  	}
   302  	_, err := s.api.CreateModel(args)
   303  	c.Assert(err, gc.ErrorMatches, "no credential specified")
   304  }
   305  
   306  func (s *modelManagerSuite) TestCreateModelUnknownCredential(c *gc.C) {
   307  	s.st.SetErrors(nil, nil, errors.NotFoundf("credential"))
   308  	args := params.ModelCreateArgs{
   309  		Name:               "foo",
   310  		OwnerTag:           "user-admin@local",
   311  		CloudCredentialTag: "cloudcred-some-cloud_admin@local_bar",
   312  	}
   313  	_, err := s.api.CreateModel(args)
   314  	c.Assert(err, gc.ErrorMatches, `getting credential: credential not found`)
   315  }
   316  
   317  func (s *modelManagerSuite) TestModelDefaults(c *gc.C) {
   318  	result, err := s.api.ModelDefaults()
   319  	c.Assert(err, jc.ErrorIsNil)
   320  	expectedValues := map[string]params.ModelDefaults{
   321  		"attr": {
   322  			Controller: "val",
   323  			Default:    "",
   324  			Regions: []params.RegionDefaults{{
   325  				RegionName: "dummy",
   326  				Value:      "val++"}}},
   327  		"attr2": {
   328  			Controller: "val3",
   329  			Default:    "val2",
   330  			Regions: []params.RegionDefaults{{
   331  				RegionName: "left",
   332  				Value:      "spam"}}},
   333  	}
   334  	c.Assert(result.Config, jc.DeepEquals, expectedValues)
   335  }
   336  
   337  func (s *modelManagerSuite) TestSetModelDefaults(c *gc.C) {
   338  	params := params.SetModelDefaults{
   339  		Config: []params.ModelDefaultValues{{
   340  			Config: map[string]interface{}{
   341  				"attr3": "val3",
   342  				"attr4": "val4"},
   343  		}}}
   344  	result, err := s.api.SetModelDefaults(params)
   345  	c.Assert(err, jc.ErrorIsNil)
   346  	c.Assert(result.OneError(), jc.ErrorIsNil)
   347  	c.Assert(s.st.cfgDefaults, jc.DeepEquals, config.ModelDefaultAttributes{
   348  		"attr": {
   349  			Controller: "val",
   350  			Default:    "",
   351  			Regions: []config.RegionDefaultValue{{
   352  				Name:  "dummy",
   353  				Value: "val++"}}},
   354  		"attr2": {
   355  			Controller: "val3",
   356  			Default:    "val2",
   357  			Regions: []config.RegionDefaultValue{{
   358  				Name:  "left",
   359  				Value: "spam"}}},
   360  		"attr3": {Controller: "val3"},
   361  		"attr4": {Controller: "val4"},
   362  	})
   363  }
   364  
   365  func (s *modelManagerSuite) blockAllChanges(c *gc.C, msg string) {
   366  	s.st.blockMsg = msg
   367  	s.st.block = state.ChangeBlock
   368  }
   369  
   370  func (s *modelManagerSuite) assertBlocked(c *gc.C, err error, msg string) {
   371  	c.Assert(params.IsCodeOperationBlocked(err), jc.IsTrue, gc.Commentf("error: %#v", err))
   372  	c.Assert(errors.Cause(err), jc.DeepEquals, &params.Error{
   373  		Message: msg,
   374  		Code:    "operation is blocked",
   375  	})
   376  }
   377  
   378  func (s *modelManagerSuite) TestBlockChangesSetModelDefaults(c *gc.C) {
   379  	s.blockAllChanges(c, "TestBlockChangesSetModelDefaults")
   380  	_, err := s.api.SetModelDefaults(params.SetModelDefaults{})
   381  	s.assertBlocked(c, err, "TestBlockChangesSetModelDefaults")
   382  }
   383  
   384  func (s *modelManagerSuite) TestUnsetModelDefaults(c *gc.C) {
   385  	args := params.UnsetModelDefaults{
   386  		Keys: []params.ModelUnsetKeys{{
   387  			Keys: []string{"attr"},
   388  		}}}
   389  	result, err := s.api.UnsetModelDefaults(args)
   390  	c.Assert(err, jc.ErrorIsNil)
   391  	c.Assert(result.OneError(), jc.ErrorIsNil)
   392  	want := config.ModelDefaultAttributes{
   393  		"attr": config.AttributeDefaultValues{
   394  			Regions: []config.RegionDefaultValue{
   395  				config.RegionDefaultValue{
   396  					Name:  "dummy",
   397  					Value: "val++"},
   398  			}},
   399  		"attr2": config.AttributeDefaultValues{
   400  			Default:    "val2",
   401  			Controller: "val3",
   402  			Regions: []config.RegionDefaultValue{
   403  				config.RegionDefaultValue{
   404  					Name:  "left",
   405  					Value: "spam"}}}}
   406  	c.Assert(s.st.cfgDefaults, jc.DeepEquals, want)
   407  }
   408  
   409  func (s *modelManagerSuite) TestBlockUnsetModelDefaults(c *gc.C) {
   410  	s.blockAllChanges(c, "TestBlockUnsetModelDefaults")
   411  	args := params.UnsetModelDefaults{
   412  		Keys: []params.ModelUnsetKeys{{
   413  			Keys: []string{"abc"},
   414  		}}}
   415  	_, err := s.api.UnsetModelDefaults(args)
   416  	s.assertBlocked(c, err, "TestBlockUnsetModelDefaults")
   417  }
   418  
   419  func (s *modelManagerSuite) TestUnsetModelDefaultsMissing(c *gc.C) {
   420  	// It's okay to unset a non-existent attribute.
   421  	args := params.UnsetModelDefaults{
   422  		Keys: []params.ModelUnsetKeys{{
   423  			Keys: []string{"not there"},
   424  		}}}
   425  	result, err := s.api.UnsetModelDefaults(args)
   426  	c.Assert(err, jc.ErrorIsNil)
   427  	c.Assert(result.OneError(), jc.ErrorIsNil)
   428  }
   429  
   430  func (s *modelManagerSuite) TestModelDefaultsAsNormalUser(c *gc.C) {
   431  	s.setAPIUser(c, names.NewUserTag("charlie@local"))
   432  	got, err := s.api.ModelDefaults()
   433  	c.Assert(err, gc.ErrorMatches, "permission denied")
   434  	c.Assert(got, gc.DeepEquals, params.ModelDefaultsResult{})
   435  }
   436  
   437  func (s *modelManagerSuite) TestSetModelDefaultsAsNormalUser(c *gc.C) {
   438  	s.setAPIUser(c, names.NewUserTag("charlie@local"))
   439  	got, err := s.api.SetModelDefaults(params.SetModelDefaults{
   440  		Config: []params.ModelDefaultValues{{
   441  			Config: map[string]interface{}{
   442  				"ftp-proxy": "http://charlie",
   443  			}}}})
   444  	c.Assert(err, jc.ErrorIsNil)
   445  	c.Assert(got, jc.DeepEquals, params.ErrorResults{
   446  		Results: []params.ErrorResult{
   447  			params.ErrorResult{
   448  				Error: &params.Error{
   449  					Message: "permission denied",
   450  					Code:    "unauthorized access"}}}})
   451  
   452  	// Make sure it didn't change.
   453  	s.setAPIUser(c, names.NewUserTag("admin@local"))
   454  	cfg, err := s.api.ModelDefaults()
   455  	c.Assert(err, jc.ErrorIsNil)
   456  	c.Assert(cfg.Config["ftp-proxy"].Controller, gc.IsNil)
   457  }
   458  
   459  func (s *modelManagerSuite) TestUnsetModelDefaultsAsNormalUser(c *gc.C) {
   460  	s.setAPIUser(c, names.NewUserTag("charlie@local"))
   461  	got, err := s.api.UnsetModelDefaults(params.UnsetModelDefaults{
   462  		Keys: []params.ModelUnsetKeys{{
   463  			Keys: []string{"attr2"}}}})
   464  	c.Assert(err, gc.ErrorMatches, "permission denied")
   465  	c.Assert(got, gc.DeepEquals, params.ErrorResults{
   466  		Results: []params.ErrorResult{
   467  			params.ErrorResult{
   468  				Error: nil}}})
   469  
   470  	// Make sure it didn't change.
   471  	s.setAPIUser(c, names.NewUserTag("admin@local"))
   472  	cfg, err := s.api.ModelDefaults()
   473  	c.Assert(err, jc.ErrorIsNil)
   474  	c.Assert(cfg.Config["attr2"].Controller.(string), gc.Equals, "val3")
   475  }
   476  
   477  func (s *modelManagerSuite) TestDumpModel(c *gc.C) {
   478  	results := s.api.DumpModels(params.Entities{[]params.Entity{{
   479  		Tag: "bad-tag",
   480  	}, {
   481  		Tag: "application-foo",
   482  	}, {
   483  		Tag: s.st.ModelTag().String(),
   484  	}}})
   485  
   486  	c.Assert(results.Results, gc.HasLen, 3)
   487  	bad, notApp, good := results.Results[0], results.Results[1], results.Results[2]
   488  	c.Check(bad.Result, gc.IsNil)
   489  	c.Check(bad.Error.Message, gc.Equals, `"bad-tag" is not a valid tag`)
   490  
   491  	c.Check(notApp.Result, gc.IsNil)
   492  	c.Check(notApp.Error.Message, gc.Equals, `"application-foo" is not a valid model tag`)
   493  
   494  	c.Check(good.Error, gc.IsNil)
   495  	c.Check(good.Result, jc.DeepEquals, map[string]interface{}{
   496  		"model-uuid": "deadbeef-0bad-400d-8000-4b1d0d06f00d",
   497  	})
   498  }
   499  
   500  func (s *modelManagerSuite) TestDumpModelMissingModel(c *gc.C) {
   501  	s.st.SetErrors(errors.NotFoundf("boom"))
   502  	tag := names.NewModelTag("deadbeef-0bad-400d-8000-4b1d0d06f000")
   503  	models := params.Entities{[]params.Entity{{Tag: tag.String()}}}
   504  	results := s.api.DumpModels(models)
   505  
   506  	calls := s.st.Calls()
   507  	c.Logf("%#v", calls)
   508  	lastCall := calls[len(calls)-1]
   509  	c.Check(lastCall.FuncName, gc.Equals, "ForModel")
   510  
   511  	c.Assert(results.Results, gc.HasLen, 1)
   512  	result := results.Results[0]
   513  	c.Assert(result.Result, gc.IsNil)
   514  	c.Assert(result.Error, gc.NotNil)
   515  	c.Check(result.Error.Code, gc.Equals, `not found`)
   516  	c.Check(result.Error.Message, gc.Equals, `id not found`)
   517  }
   518  
   519  func (s *modelManagerSuite) TestDumpModelUsers(c *gc.C) {
   520  	models := params.Entities{[]params.Entity{{Tag: s.st.ModelTag().String()}}}
   521  	for _, user := range []names.UserTag{
   522  		names.NewUserTag("otheruser"),
   523  		names.NewUserTag("unknown"),
   524  	} {
   525  		s.setAPIUser(c, user)
   526  		results := s.api.DumpModels(models)
   527  		c.Assert(results.Results, gc.HasLen, 1)
   528  		result := results.Results[0]
   529  		c.Assert(result.Result, gc.IsNil)
   530  		c.Assert(result.Error, gc.NotNil)
   531  		c.Check(result.Error.Message, gc.Equals, `permission denied`)
   532  	}
   533  }
   534  
   535  func (s *modelManagerSuite) TestDumpModelsDB(c *gc.C) {
   536  	results := s.api.DumpModelsDB(params.Entities{[]params.Entity{{
   537  		Tag: "bad-tag",
   538  	}, {
   539  		Tag: "application-foo",
   540  	}, {
   541  		Tag: s.st.ModelTag().String(),
   542  	}}})
   543  
   544  	c.Assert(results.Results, gc.HasLen, 3)
   545  	bad, notApp, good := results.Results[0], results.Results[1], results.Results[2]
   546  	c.Check(bad.Result, gc.IsNil)
   547  	c.Check(bad.Error.Message, gc.Equals, `"bad-tag" is not a valid tag`)
   548  
   549  	c.Check(notApp.Result, gc.IsNil)
   550  	c.Check(notApp.Error.Message, gc.Equals, `"application-foo" is not a valid model tag`)
   551  
   552  	c.Check(good.Error, gc.IsNil)
   553  	c.Check(good.Result, jc.DeepEquals, map[string]interface{}{
   554  		"models": "lots of data",
   555  	})
   556  }
   557  
   558  func (s *modelManagerSuite) TestDumpModelsDBMissingModel(c *gc.C) {
   559  	s.st.SetErrors(errors.NotFoundf("boom"))
   560  	tag := names.NewModelTag("deadbeef-0bad-400d-8000-4b1d0d06f000")
   561  	models := params.Entities{[]params.Entity{{Tag: tag.String()}}}
   562  	results := s.api.DumpModelsDB(models)
   563  
   564  	calls := s.st.Calls()
   565  	c.Logf("%#v", calls)
   566  	lastCall := calls[len(calls)-1]
   567  	c.Check(lastCall.FuncName, gc.Equals, "ForModel")
   568  
   569  	c.Assert(results.Results, gc.HasLen, 1)
   570  	result := results.Results[0]
   571  	c.Assert(result.Result, gc.IsNil)
   572  	c.Assert(result.Error, gc.NotNil)
   573  	c.Check(result.Error.Code, gc.Equals, `not found`)
   574  	c.Check(result.Error.Message, gc.Equals, `id not found`)
   575  }
   576  
   577  func (s *modelManagerSuite) TestDumpModelsDBUsers(c *gc.C) {
   578  	models := params.Entities{[]params.Entity{{Tag: s.st.ModelTag().String()}}}
   579  	for _, user := range []names.UserTag{
   580  		names.NewUserTag("otheruser"),
   581  		names.NewUserTag("unknown"),
   582  	} {
   583  		s.setAPIUser(c, user)
   584  		results := s.api.DumpModelsDB(models)
   585  		c.Assert(results.Results, gc.HasLen, 1)
   586  		result := results.Results[0]
   587  		c.Assert(result.Result, gc.IsNil)
   588  		c.Assert(result.Error, gc.NotNil)
   589  		c.Check(result.Error.Message, gc.Equals, `permission denied`)
   590  	}
   591  }
   592  
   593  // modelManagerStateSuite contains end-to-end tests.
   594  // Prefer adding tests to modelManagerSuite above.
   595  type modelManagerStateSuite struct {
   596  	jujutesting.JujuConnSuite
   597  	modelmanager *modelmanager.ModelManagerAPI
   598  	authoriser   apiservertesting.FakeAuthorizer
   599  }
   600  
   601  var _ = gc.Suite(&modelManagerStateSuite{})
   602  
   603  func (s *modelManagerStateSuite) SetUpSuite(c *gc.C) {
   604  	// TODO(anastasiamac 2016-07-19): Fix this on windows
   605  	if runtime.GOOS != "linux" {
   606  		c.Skip("bug 1603585: Skipping this on windows for now")
   607  	}
   608  	s.JujuConnSuite.SetUpSuite(c)
   609  }
   610  
   611  func (s *modelManagerStateSuite) SetUpTest(c *gc.C) {
   612  	s.JujuConnSuite.SetUpTest(c)
   613  	s.authoriser = apiservertesting.FakeAuthorizer{
   614  		Tag: s.AdminUserTag(c),
   615  	}
   616  	loggo.GetLogger("juju.apiserver.modelmanager").SetLogLevel(loggo.TRACE)
   617  }
   618  
   619  func (s *modelManagerStateSuite) setAPIUser(c *gc.C, user names.UserTag) {
   620  	s.authoriser.Tag = user
   621  	modelmanager, err := modelmanager.NewModelManagerAPI(
   622  		common.NewModelManagerBackend(s.State),
   623  		stateenvirons.EnvironConfigGetter{s.State},
   624  		s.authoriser,
   625  	)
   626  	c.Assert(err, jc.ErrorIsNil)
   627  	s.modelmanager = modelmanager
   628  }
   629  
   630  func (s *modelManagerStateSuite) TestNewAPIAcceptsClient(c *gc.C) {
   631  	anAuthoriser := s.authoriser
   632  	anAuthoriser.Tag = names.NewUserTag("external@remote")
   633  	endPoint, err := modelmanager.NewModelManagerAPI(
   634  		common.NewModelManagerBackend(s.State), nil, anAuthoriser,
   635  	)
   636  	c.Assert(err, jc.ErrorIsNil)
   637  	c.Assert(endPoint, gc.NotNil)
   638  }
   639  
   640  func (s *modelManagerStateSuite) TestNewAPIRefusesNonClient(c *gc.C) {
   641  	anAuthoriser := s.authoriser
   642  	anAuthoriser.Tag = names.NewUnitTag("mysql/0")
   643  	endPoint, err := modelmanager.NewModelManagerAPI(
   644  		common.NewModelManagerBackend(s.State), nil, anAuthoriser,
   645  	)
   646  	c.Assert(endPoint, gc.IsNil)
   647  	c.Assert(err, gc.ErrorMatches, "permission denied")
   648  }
   649  
   650  func (s *modelManagerStateSuite) createArgs(c *gc.C, owner names.UserTag) params.ModelCreateArgs {
   651  	return params.ModelCreateArgs{
   652  		Name:     "test-model",
   653  		OwnerTag: owner.String(),
   654  		Config: map[string]interface{}{
   655  			"authorized-keys": "ssh-key",
   656  			// And to make it a valid dummy config
   657  			"controller": false,
   658  		},
   659  	}
   660  }
   661  
   662  func (s *modelManagerStateSuite) createArgsForVersion(c *gc.C, owner names.UserTag, ver interface{}) params.ModelCreateArgs {
   663  	params := s.createArgs(c, owner)
   664  	params.Config["agent-version"] = ver
   665  	return params
   666  }
   667  
   668  func (s *modelManagerStateSuite) TestUserCanCreateModel(c *gc.C) {
   669  	owner := names.NewUserTag("admin@local")
   670  	s.setAPIUser(c, owner)
   671  	model, err := s.modelmanager.CreateModel(s.createArgs(c, owner))
   672  	c.Assert(err, jc.ErrorIsNil)
   673  	c.Assert(model.OwnerTag, gc.Equals, owner.String())
   674  	c.Assert(model.Name, gc.Equals, "test-model")
   675  }
   676  
   677  func (s *modelManagerStateSuite) TestAdminCanCreateModelForSomeoneElse(c *gc.C) {
   678  	s.setAPIUser(c, s.AdminUserTag(c))
   679  	owner := names.NewUserTag("external@remote")
   680  	model, err := s.modelmanager.CreateModel(s.createArgs(c, owner))
   681  	c.Assert(err, jc.ErrorIsNil)
   682  	c.Assert(model.OwnerTag, gc.Equals, owner.String())
   683  	c.Assert(model.Name, gc.Equals, "test-model")
   684  	// Make sure that the environment created does actually have the correct
   685  	// owner, and that owner is actually allowed to use the environment.
   686  	newState, err := s.State.ForModel(names.NewModelTag(model.UUID))
   687  	c.Assert(err, jc.ErrorIsNil)
   688  	defer newState.Close()
   689  
   690  	newModel, err := newState.Model()
   691  	c.Assert(err, jc.ErrorIsNil)
   692  	c.Assert(newModel.Owner(), gc.Equals, owner)
   693  	_, err = newState.UserAccess(owner, newState.ModelTag())
   694  	c.Assert(err, jc.ErrorIsNil)
   695  }
   696  
   697  func (s *modelManagerStateSuite) TestNonAdminCannotCreateModelForSomeoneElse(c *gc.C) {
   698  	s.setAPIUser(c, names.NewUserTag("non-admin@remote"))
   699  	owner := names.NewUserTag("external@remote")
   700  	_, err := s.modelmanager.CreateModel(s.createArgs(c, owner))
   701  	c.Assert(err, gc.ErrorMatches, "permission denied")
   702  }
   703  
   704  func (s *modelManagerStateSuite) TestNonAdminCannotCreateModelForSelf(c *gc.C) {
   705  	owner := names.NewUserTag("non-admin@remote")
   706  	s.setAPIUser(c, owner)
   707  	_, err := s.modelmanager.CreateModel(s.createArgs(c, owner))
   708  	c.Assert(err, gc.ErrorMatches, "permission denied")
   709  }
   710  
   711  func (s *modelManagerStateSuite) TestCreateModelValidatesConfig(c *gc.C) {
   712  	admin := s.AdminUserTag(c)
   713  	s.setAPIUser(c, admin)
   714  	args := s.createArgs(c, admin)
   715  	args.Config["controller"] = "maybe"
   716  	_, err := s.modelmanager.CreateModel(args)
   717  	c.Assert(err, gc.ErrorMatches,
   718  		"failed to create config: provider config preparation failed: controller: expected bool, got string\\(\"maybe\"\\)",
   719  	)
   720  }
   721  
   722  func (s *modelManagerStateSuite) TestCreateModelBadConfig(c *gc.C) {
   723  	owner := names.NewUserTag("admin@local")
   724  	s.setAPIUser(c, owner)
   725  	for i, test := range []struct {
   726  		key      string
   727  		value    interface{}
   728  		errMatch string
   729  	}{
   730  		{
   731  			key:      "uuid",
   732  			value:    "anything",
   733  			errMatch: `failed to create config: uuid is generated, you cannot specify one`,
   734  		}, {
   735  			key:      "type",
   736  			value:    "fake",
   737  			errMatch: `failed to create config: specified type "fake" does not match controller "dummy"`,
   738  		},
   739  	} {
   740  		c.Logf("%d: %s", i, test.key)
   741  		args := s.createArgs(c, owner)
   742  		args.Config[test.key] = test.value
   743  		_, err := s.modelmanager.CreateModel(args)
   744  		c.Assert(err, gc.ErrorMatches, test.errMatch)
   745  
   746  	}
   747  }
   748  
   749  func (s *modelManagerStateSuite) TestCreateModelSameAgentVersion(c *gc.C) {
   750  	admin := s.AdminUserTag(c)
   751  	s.setAPIUser(c, admin)
   752  	args := s.createArgsForVersion(c, admin, jujuversion.Current.String())
   753  	_, err := s.modelmanager.CreateModel(args)
   754  	c.Assert(err, jc.ErrorIsNil)
   755  }
   756  
   757  func (s *modelManagerStateSuite) TestCreateModelBadAgentVersion(c *gc.C) {
   758  	err := s.BackingState.SetModelAgentVersion(coretesting.FakeVersionNumber)
   759  	c.Assert(err, jc.ErrorIsNil)
   760  
   761  	admin := s.AdminUserTag(c)
   762  	s.setAPIUser(c, admin)
   763  
   764  	bigger := coretesting.FakeVersionNumber
   765  	bigger.Minor += 1
   766  
   767  	smaller := coretesting.FakeVersionNumber
   768  	smaller.Minor -= 1
   769  
   770  	for i, test := range []struct {
   771  		value    interface{}
   772  		errMatch string
   773  	}{
   774  		{
   775  			value:    42,
   776  			errMatch: `failed to create config: agent-version must be a string but has type 'int'`,
   777  		}, {
   778  			value:    "not a number",
   779  			errMatch: `failed to create config: invalid version \"not a number\"`,
   780  		}, {
   781  			value:    bigger.String(),
   782  			errMatch: "failed to create config: agent-version .* cannot be greater than the controller .*",
   783  		}, {
   784  			value:    smaller.String(),
   785  			errMatch: "failed to create config: no tools found for version .*",
   786  		},
   787  	} {
   788  		c.Logf("test %d", i)
   789  		args := s.createArgsForVersion(c, admin, test.value)
   790  		_, err := s.modelmanager.CreateModel(args)
   791  		c.Check(err, gc.ErrorMatches, test.errMatch)
   792  	}
   793  }
   794  
   795  func (s *modelManagerStateSuite) TestListModelsForSelf(c *gc.C) {
   796  	user := names.NewUserTag("external@remote")
   797  	s.setAPIUser(c, user)
   798  	result, err := s.modelmanager.ListModels(params.Entity{Tag: user.String()})
   799  	c.Assert(err, jc.ErrorIsNil)
   800  	c.Assert(result.UserModels, gc.HasLen, 0)
   801  }
   802  
   803  func (s *modelManagerStateSuite) TestListModelsForSelfLocalUser(c *gc.C) {
   804  	// When the user's credentials cache stores the simple name, but the
   805  	// api server converts it to a fully qualified name.
   806  	user := names.NewUserTag("local-user")
   807  	s.setAPIUser(c, names.NewUserTag("local-user@local"))
   808  	result, err := s.modelmanager.ListModels(params.Entity{Tag: user.String()})
   809  	c.Assert(err, jc.ErrorIsNil)
   810  	c.Assert(result.UserModels, gc.HasLen, 0)
   811  }
   812  
   813  func (s *modelManagerStateSuite) checkModelMatches(c *gc.C, model params.Model, expected *state.Model) {
   814  	c.Check(model.Name, gc.Equals, expected.Name())
   815  	c.Check(model.UUID, gc.Equals, expected.UUID())
   816  	c.Check(model.OwnerTag, gc.Equals, expected.Owner().String())
   817  }
   818  
   819  func (s *modelManagerStateSuite) TestListModelsAdminSelf(c *gc.C) {
   820  	user := s.AdminUserTag(c)
   821  	s.setAPIUser(c, user)
   822  	result, err := s.modelmanager.ListModels(params.Entity{Tag: user.String()})
   823  	c.Assert(err, jc.ErrorIsNil)
   824  	c.Assert(result.UserModels, gc.HasLen, 1)
   825  	expected, err := s.State.Model()
   826  	c.Assert(err, jc.ErrorIsNil)
   827  	s.checkModelMatches(c, result.UserModels[0].Model, expected)
   828  }
   829  
   830  func (s *modelManagerStateSuite) TestListModelsAdminListsOther(c *gc.C) {
   831  	user := s.AdminUserTag(c)
   832  	s.setAPIUser(c, user)
   833  	other := names.NewUserTag("external@remote")
   834  	result, err := s.modelmanager.ListModels(params.Entity{Tag: other.String()})
   835  	c.Assert(err, jc.ErrorIsNil)
   836  	c.Assert(result.UserModels, gc.HasLen, 0)
   837  }
   838  
   839  func (s *modelManagerStateSuite) TestListModelsDenied(c *gc.C) {
   840  	user := names.NewUserTag("external@remote")
   841  	s.setAPIUser(c, user)
   842  	other := names.NewUserTag("other@remote")
   843  	_, err := s.modelmanager.ListModels(params.Entity{Tag: other.String()})
   844  	c.Assert(err, gc.ErrorMatches, "permission denied")
   845  }
   846  
   847  func (s *modelManagerStateSuite) TestAdminModelManager(c *gc.C) {
   848  	user := s.AdminUserTag(c)
   849  	s.setAPIUser(c, user)
   850  	c.Assert(modelmanager.AuthCheck(c, s.modelmanager, user), jc.IsTrue)
   851  }
   852  
   853  func (s *modelManagerStateSuite) TestNonAdminModelManager(c *gc.C) {
   854  	user := names.NewUserTag("external@remote")
   855  	s.setAPIUser(c, user)
   856  	c.Assert(modelmanager.AuthCheck(c, s.modelmanager, user), jc.IsFalse)
   857  }
   858  
   859  func (s *modelManagerStateSuite) TestDestroyOwnModel(c *gc.C) {
   860  	// TODO(perrito666) this test is not valid until we have
   861  	// proper controller permission since the only users that
   862  	// can create models are controller admins.
   863  	owner := names.NewUserTag("admin@local")
   864  	s.setAPIUser(c, owner)
   865  	m, err := s.modelmanager.CreateModel(s.createArgs(c, owner))
   866  	c.Assert(err, jc.ErrorIsNil)
   867  	st, err := s.State.ForModel(names.NewModelTag(m.UUID))
   868  	c.Assert(err, jc.ErrorIsNil)
   869  	defer st.Close()
   870  
   871  	s.modelmanager, err = modelmanager.NewModelManagerAPI(
   872  		common.NewModelManagerBackend(st), nil, s.authoriser,
   873  	)
   874  	c.Assert(err, jc.ErrorIsNil)
   875  
   876  	results, err := s.modelmanager.DestroyModels(params.Entities{
   877  		Entities: []params.Entity{{"model-" + m.UUID}},
   878  	})
   879  	c.Assert(err, jc.ErrorIsNil)
   880  	c.Assert(results.Results, gc.HasLen, 1)
   881  	c.Assert(results.Results[0].Error, gc.IsNil)
   882  
   883  	model, err := st.Model()
   884  	c.Assert(err, jc.ErrorIsNil)
   885  	c.Assert(model.Life(), gc.Not(gc.Equals), state.Alive)
   886  }
   887  
   888  func (s *modelManagerStateSuite) TestAdminDestroysOtherModel(c *gc.C) {
   889  	// TODO(perrito666) Both users are admins in this case, this tesst is of dubious
   890  	// usefulness until proper controller permissions are in place.
   891  	owner := names.NewUserTag("admin@local")
   892  	s.setAPIUser(c, owner)
   893  	m, err := s.modelmanager.CreateModel(s.createArgs(c, owner))
   894  	c.Assert(err, jc.ErrorIsNil)
   895  	st, err := s.State.ForModel(names.NewModelTag(m.UUID))
   896  	c.Assert(err, jc.ErrorIsNil)
   897  	defer st.Close()
   898  
   899  	s.modelmanager, err = modelmanager.NewModelManagerAPI(
   900  		common.NewModelManagerBackend(st), nil, s.authoriser,
   901  	)
   902  	c.Assert(err, jc.ErrorIsNil)
   903  
   904  	other := s.AdminUserTag(c)
   905  	s.setAPIUser(c, other)
   906  
   907  	results, err := s.modelmanager.DestroyModels(params.Entities{
   908  		Entities: []params.Entity{{"model-" + m.UUID}},
   909  	})
   910  	c.Assert(err, jc.ErrorIsNil)
   911  	c.Assert(results.Results, gc.HasLen, 1)
   912  	c.Assert(results.Results[0].Error, gc.IsNil)
   913  
   914  	s.setAPIUser(c, owner)
   915  	model, err := st.Model()
   916  	c.Assert(err, jc.ErrorIsNil)
   917  	c.Assert(model.Life(), gc.Not(gc.Equals), state.Alive)
   918  }
   919  
   920  func (s *modelManagerStateSuite) TestDestroyModelErrors(c *gc.C) {
   921  	owner := names.NewUserTag("admin@local")
   922  	s.setAPIUser(c, owner)
   923  	m, err := s.modelmanager.CreateModel(s.createArgs(c, owner))
   924  	c.Assert(err, jc.ErrorIsNil)
   925  	st, err := s.State.ForModel(names.NewModelTag(m.UUID))
   926  	c.Assert(err, jc.ErrorIsNil)
   927  	defer st.Close()
   928  
   929  	s.modelmanager, err = modelmanager.NewModelManagerAPI(
   930  		common.NewModelManagerBackend(st), nil, s.authoriser,
   931  	)
   932  	c.Assert(err, jc.ErrorIsNil)
   933  
   934  	user := names.NewUserTag("other@remote")
   935  	s.setAPIUser(c, user)
   936  
   937  	results, err := s.modelmanager.DestroyModels(params.Entities{
   938  		Entities: []params.Entity{
   939  			{"model-" + m.UUID},
   940  			{"model-9f484882-2f18-4fd2-967d-db9663db7bea"},
   941  			{"machine-42"},
   942  		},
   943  	})
   944  	c.Assert(err, jc.ErrorIsNil)
   945  	c.Assert(results.Results, jc.DeepEquals, []params.ErrorResult{{
   946  		// we don't have admin access to the model
   947  		&params.Error{
   948  			Message: "permission denied",
   949  			Code:    params.CodeUnauthorized,
   950  		},
   951  	}, {
   952  		&params.Error{
   953  			Message: "model not found",
   954  			Code:    params.CodeNotFound,
   955  		},
   956  	}, {
   957  		&params.Error{
   958  			Message: `"machine-42" is not a valid model tag`,
   959  		},
   960  	}})
   961  
   962  	s.setAPIUser(c, owner)
   963  	model, err := st.Model()
   964  	c.Assert(err, jc.ErrorIsNil)
   965  	c.Assert(model.Life(), gc.Equals, state.Alive)
   966  }
   967  
   968  func (s *modelManagerStateSuite) modifyAccess(c *gc.C, user names.UserTag, action params.ModelAction, access params.UserAccessPermission, model names.ModelTag) error {
   969  	args := params.ModifyModelAccessRequest{
   970  		Changes: []params.ModifyModelAccess{{
   971  			UserTag:  user.String(),
   972  			Action:   action,
   973  			Access:   access,
   974  			ModelTag: model.String(),
   975  		}}}
   976  
   977  	result, err := s.modelmanager.ModifyModelAccess(args)
   978  	if err != nil {
   979  		return err
   980  	}
   981  	return result.OneError()
   982  }
   983  
   984  func (s *modelManagerStateSuite) grant(c *gc.C, user names.UserTag, access params.UserAccessPermission, model names.ModelTag) error {
   985  	return s.modifyAccess(c, user, params.GrantModelAccess, access, model)
   986  }
   987  
   988  func (s *modelManagerStateSuite) revoke(c *gc.C, user names.UserTag, access params.UserAccessPermission, model names.ModelTag) error {
   989  	return s.modifyAccess(c, user, params.RevokeModelAccess, access, model)
   990  }
   991  
   992  func (s *modelManagerStateSuite) TestGrantMissingUserFails(c *gc.C) {
   993  	s.setAPIUser(c, s.AdminUserTag(c))
   994  	st := s.Factory.MakeModel(c, nil)
   995  	defer st.Close()
   996  
   997  	user := names.NewLocalUserTag("foobar")
   998  	err := s.grant(c, user, params.ModelReadAccess, st.ModelTag())
   999  	expectedErr := `could not grant model access: user "foobar" does not exist locally: user "foobar" not found`
  1000  	c.Assert(err, gc.ErrorMatches, expectedErr)
  1001  }
  1002  
  1003  func (s *modelManagerStateSuite) TestGrantMissingModelFails(c *gc.C) {
  1004  	s.setAPIUser(c, s.AdminUserTag(c))
  1005  	user := s.Factory.MakeModelUser(c, nil)
  1006  	model := names.NewModelTag("17e4bd2d-3e08-4f3d-b945-087be7ebdce4")
  1007  	err := s.grant(c, user.UserTag, params.ModelReadAccess, model)
  1008  	expectedErr := `.*model not found`
  1009  	c.Assert(err, gc.ErrorMatches, expectedErr)
  1010  }
  1011  
  1012  func (s *modelManagerStateSuite) TestRevokeAdminLeavesReadAccess(c *gc.C) {
  1013  	s.setAPIUser(c, s.AdminUserTag(c))
  1014  	user := s.Factory.MakeModelUser(c, &factory.ModelUserParams{Access: permission.WriteAccess})
  1015  
  1016  	err := s.revoke(c, user.UserTag, params.ModelWriteAccess, user.Object.(names.ModelTag))
  1017  	c.Assert(err, gc.IsNil)
  1018  
  1019  	modelUser, err := s.State.UserAccess(user.UserTag, user.Object)
  1020  	c.Assert(err, jc.ErrorIsNil)
  1021  	c.Assert(modelUser.Access, gc.Equals, permission.ReadAccess)
  1022  }
  1023  
  1024  func (s *modelManagerStateSuite) TestRevokeReadRemovesModelUser(c *gc.C) {
  1025  	s.setAPIUser(c, s.AdminUserTag(c))
  1026  	user := s.Factory.MakeModelUser(c, nil)
  1027  
  1028  	err := s.revoke(c, user.UserTag, params.ModelReadAccess, user.Object.(names.ModelTag))
  1029  	c.Assert(err, gc.IsNil)
  1030  
  1031  	_, err = s.State.UserAccess(user.UserTag, user.Object)
  1032  	c.Assert(errors.IsNotFound(err), jc.IsTrue)
  1033  }
  1034  
  1035  func (s *modelManagerStateSuite) TestRevokeModelMissingUser(c *gc.C) {
  1036  	s.setAPIUser(c, s.AdminUserTag(c))
  1037  	st := s.Factory.MakeModel(c, nil)
  1038  	defer st.Close()
  1039  
  1040  	user := names.NewUserTag("bob")
  1041  	err := s.revoke(c, user, params.ModelReadAccess, st.ModelTag())
  1042  	c.Assert(err, gc.ErrorMatches, `could not revoke model access: model user "bob@local" does not exist`)
  1043  
  1044  	_, err = st.UserAccess(user, st.ModelTag())
  1045  	c.Assert(errors.IsNotFound(err), jc.IsTrue)
  1046  }
  1047  
  1048  func (s *modelManagerStateSuite) TestGrantOnlyGreaterAccess(c *gc.C) {
  1049  	user := s.Factory.MakeUser(c, &factory.UserParams{Name: "foobar", NoModelUser: true})
  1050  	s.setAPIUser(c, s.AdminUserTag(c))
  1051  	st := s.Factory.MakeModel(c, nil)
  1052  	defer st.Close()
  1053  
  1054  	err := s.grant(c, user.UserTag(), params.ModelReadAccess, st.ModelTag())
  1055  	c.Assert(err, jc.ErrorIsNil)
  1056  
  1057  	err = s.grant(c, user.UserTag(), params.ModelReadAccess, st.ModelTag())
  1058  	c.Assert(err, gc.ErrorMatches, `user already has "read" access or greater`)
  1059  }
  1060  
  1061  func (s *modelManagerStateSuite) assertNewUser(c *gc.C, modelUser permission.UserAccess, userTag, creatorTag names.UserTag) {
  1062  	c.Assert(modelUser.UserTag, gc.Equals, userTag)
  1063  	c.Assert(modelUser.CreatedBy, gc.Equals, creatorTag)
  1064  	_, err := s.State.LastModelConnection(modelUser.UserTag)
  1065  	c.Assert(err, jc.Satisfies, state.IsNeverConnectedError)
  1066  }
  1067  
  1068  func (s *modelManagerStateSuite) assertModelAccess(c *gc.C, st *state.State) {
  1069  	result, err := s.modelmanager.ModelInfo(params.Entities{Entities: []params.Entity{{Tag: st.ModelTag().String()}}})
  1070  	c.Assert(err, jc.ErrorIsNil)
  1071  	c.Assert(result.Results, gc.HasLen, 1)
  1072  	c.Assert(result.Results[0].Error, gc.IsNil)
  1073  }
  1074  
  1075  func (s *modelManagerStateSuite) TestGrantModelAddLocalUser(c *gc.C) {
  1076  	user := s.Factory.MakeUser(c, &factory.UserParams{Name: "foobar", NoModelUser: true})
  1077  	apiUser := s.AdminUserTag(c)
  1078  	s.setAPIUser(c, apiUser)
  1079  	st := s.Factory.MakeModel(c, nil)
  1080  	defer st.Close()
  1081  
  1082  	err := s.grant(c, user.UserTag(), params.ModelReadAccess, st.ModelTag())
  1083  	c.Assert(err, jc.ErrorIsNil)
  1084  
  1085  	modelUser, err := st.UserAccess(user.UserTag(), st.ModelTag())
  1086  	c.Assert(err, jc.ErrorIsNil)
  1087  	s.assertNewUser(c, modelUser, user.UserTag(), apiUser)
  1088  	c.Assert(modelUser.Access, gc.Equals, permission.ReadAccess)
  1089  	s.setAPIUser(c, user.UserTag())
  1090  	s.assertModelAccess(c, st)
  1091  }
  1092  
  1093  func (s *modelManagerStateSuite) TestGrantModelAddRemoteUser(c *gc.C) {
  1094  	userTag := names.NewUserTag("foobar@ubuntuone")
  1095  	apiUser := s.AdminUserTag(c)
  1096  	s.setAPIUser(c, apiUser)
  1097  	st := s.Factory.MakeModel(c, nil)
  1098  	defer st.Close()
  1099  
  1100  	err := s.grant(c, userTag, params.ModelReadAccess, st.ModelTag())
  1101  	c.Assert(err, jc.ErrorIsNil)
  1102  
  1103  	modelUser, err := st.UserAccess(userTag, st.ModelTag())
  1104  	c.Assert(err, jc.ErrorIsNil)
  1105  
  1106  	s.assertNewUser(c, modelUser, userTag, apiUser)
  1107  	c.Assert(modelUser.Access, gc.Equals, permission.ReadAccess)
  1108  	s.setAPIUser(c, userTag)
  1109  	s.assertModelAccess(c, st)
  1110  }
  1111  
  1112  func (s *modelManagerStateSuite) TestGrantModelAddAdminUser(c *gc.C) {
  1113  	user := s.Factory.MakeUser(c, &factory.UserParams{Name: "foobar", NoModelUser: true})
  1114  	apiUser := s.AdminUserTag(c)
  1115  	s.setAPIUser(c, apiUser)
  1116  	st := s.Factory.MakeModel(c, nil)
  1117  	defer st.Close()
  1118  
  1119  	err := s.grant(c, user.UserTag(), params.ModelWriteAccess, st.ModelTag())
  1120  
  1121  	modelUser, err := st.UserAccess(user.UserTag(), st.ModelTag())
  1122  	c.Assert(err, jc.ErrorIsNil)
  1123  	s.assertNewUser(c, modelUser, user.UserTag(), apiUser)
  1124  	c.Assert(modelUser.Access, gc.Equals, permission.WriteAccess)
  1125  	s.setAPIUser(c, user.UserTag())
  1126  	s.assertModelAccess(c, st)
  1127  }
  1128  
  1129  func (s *modelManagerStateSuite) TestGrantModelIncreaseAccess(c *gc.C) {
  1130  	s.setAPIUser(c, s.AdminUserTag(c))
  1131  	st := s.Factory.MakeModel(c, nil)
  1132  	defer st.Close()
  1133  	stFactory := factory.NewFactory(st)
  1134  	user := stFactory.MakeModelUser(c, &factory.ModelUserParams{Access: permission.ReadAccess})
  1135  
  1136  	err := s.grant(c, user.UserTag, params.ModelWriteAccess, st.ModelTag())
  1137  	c.Assert(err, jc.ErrorIsNil)
  1138  
  1139  	modelUser, err := st.UserAccess(user.UserTag, st.ModelTag())
  1140  	c.Assert(err, jc.ErrorIsNil)
  1141  	c.Assert(modelUser.Access, gc.Equals, permission.WriteAccess)
  1142  }
  1143  
  1144  func (s *modelManagerStateSuite) TestGrantToModelNoAccess(c *gc.C) {
  1145  	s.setAPIUser(c, s.AdminUserTag(c))
  1146  	st := s.Factory.MakeModel(c, nil)
  1147  	defer st.Close()
  1148  
  1149  	apiUser := names.NewUserTag("bob@remote")
  1150  	s.setAPIUser(c, apiUser)
  1151  
  1152  	other := names.NewUserTag("other@remote")
  1153  	err := s.grant(c, other, params.ModelReadAccess, st.ModelTag())
  1154  	c.Assert(err, gc.ErrorMatches, "permission denied")
  1155  }
  1156  
  1157  func (s *modelManagerStateSuite) TestGrantToModelReadAccess(c *gc.C) {
  1158  	s.setAPIUser(c, s.AdminUserTag(c))
  1159  	st := s.Factory.MakeModel(c, nil)
  1160  	defer st.Close()
  1161  
  1162  	apiUser := names.NewUserTag("bob@remote")
  1163  	s.setAPIUser(c, apiUser)
  1164  
  1165  	stFactory := factory.NewFactory(st)
  1166  	stFactory.MakeModelUser(c, &factory.ModelUserParams{
  1167  		User: apiUser.Canonical(), Access: permission.ReadAccess})
  1168  
  1169  	other := names.NewUserTag("other@remote")
  1170  	err := s.grant(c, other, params.ModelReadAccess, st.ModelTag())
  1171  	c.Assert(err, gc.ErrorMatches, "permission denied")
  1172  }
  1173  
  1174  func (s *modelManagerStateSuite) TestGrantToModelWriteAccess(c *gc.C) {
  1175  	s.setAPIUser(c, s.AdminUserTag(c))
  1176  	st := s.Factory.MakeModel(c, nil)
  1177  	defer st.Close()
  1178  
  1179  	apiUser := names.NewUserTag("admin@remote")
  1180  	s.setAPIUser(c, apiUser)
  1181  	stFactory := factory.NewFactory(st)
  1182  	stFactory.MakeModelUser(c, &factory.ModelUserParams{
  1183  		User: apiUser.Canonical(), Access: permission.AdminAccess})
  1184  
  1185  	other := names.NewUserTag("other@remote")
  1186  	err := s.grant(c, other, params.ModelReadAccess, st.ModelTag())
  1187  	c.Assert(err, jc.ErrorIsNil)
  1188  
  1189  	modelUser, err := st.UserAccess(other, st.ModelTag())
  1190  	c.Assert(err, jc.ErrorIsNil)
  1191  	s.assertNewUser(c, modelUser, other, apiUser)
  1192  	c.Assert(modelUser.Access, gc.Equals, permission.ReadAccess)
  1193  }
  1194  
  1195  func (s *modelManagerStateSuite) TestGrantModelInvalidUserTag(c *gc.C) {
  1196  	s.setAPIUser(c, s.AdminUserTag(c))
  1197  	for _, testParam := range []struct {
  1198  		tag      string
  1199  		validTag bool
  1200  	}{{
  1201  		tag:      "unit-foo/0",
  1202  		validTag: true,
  1203  	}, {
  1204  		tag:      "application-foo",
  1205  		validTag: true,
  1206  	}, {
  1207  		tag:      "relation-wordpress:db mysql:db",
  1208  		validTag: true,
  1209  	}, {
  1210  		tag:      "machine-0",
  1211  		validTag: true,
  1212  	}, {
  1213  		tag:      "user@local",
  1214  		validTag: false,
  1215  	}, {
  1216  		tag:      "user-Mua^h^h^h^arh",
  1217  		validTag: true,
  1218  	}, {
  1219  		tag:      "user@",
  1220  		validTag: false,
  1221  	}, {
  1222  		tag:      "user@ubuntuone",
  1223  		validTag: false,
  1224  	}, {
  1225  		tag:      "user@ubuntuone",
  1226  		validTag: false,
  1227  	}, {
  1228  		tag:      "@ubuntuone",
  1229  		validTag: false,
  1230  	}, {
  1231  		tag:      "in^valid.",
  1232  		validTag: false,
  1233  	}, {
  1234  		tag:      "",
  1235  		validTag: false,
  1236  	},
  1237  	} {
  1238  		var expectedErr string
  1239  		errPart := `could not modify model access: "` + regexp.QuoteMeta(testParam.tag) + `" is not a valid `
  1240  
  1241  		if testParam.validTag {
  1242  			// The string is a valid tag, but not a user tag.
  1243  			expectedErr = errPart + `user tag`
  1244  		} else {
  1245  			// The string is not a valid tag of any kind.
  1246  			expectedErr = errPart + `tag`
  1247  		}
  1248  
  1249  		args := params.ModifyModelAccessRequest{
  1250  			Changes: []params.ModifyModelAccess{{
  1251  				ModelTag: "model-deadbeef-0bad-400d-8000-4b1d0d06f00d",
  1252  				UserTag:  testParam.tag,
  1253  				Action:   params.GrantModelAccess,
  1254  				Access:   params.ModelReadAccess,
  1255  			}}}
  1256  
  1257  		result, err := s.modelmanager.ModifyModelAccess(args)
  1258  		c.Assert(err, jc.ErrorIsNil)
  1259  		c.Assert(result.OneError(), gc.ErrorMatches, expectedErr)
  1260  	}
  1261  }
  1262  
  1263  func (s *modelManagerStateSuite) TestModifyModelAccessEmptyArgs(c *gc.C) {
  1264  	s.setAPIUser(c, s.AdminUserTag(c))
  1265  	args := params.ModifyModelAccessRequest{Changes: []params.ModifyModelAccess{{}}}
  1266  
  1267  	result, err := s.modelmanager.ModifyModelAccess(args)
  1268  	c.Assert(err, jc.ErrorIsNil)
  1269  	expectedErr := `could not modify model access: "" model access not valid`
  1270  	c.Assert(result.OneError(), gc.ErrorMatches, expectedErr)
  1271  }
  1272  
  1273  func (s *modelManagerStateSuite) TestModifyModelAccessInvalidAction(c *gc.C) {
  1274  	s.setAPIUser(c, s.AdminUserTag(c))
  1275  	var dance params.ModelAction = "dance"
  1276  	args := params.ModifyModelAccessRequest{
  1277  		Changes: []params.ModifyModelAccess{{
  1278  			UserTag:  "user-user@local",
  1279  			Action:   dance,
  1280  			Access:   params.ModelReadAccess,
  1281  			ModelTag: s.State.ModelTag().String(),
  1282  		}}}
  1283  
  1284  	result, err := s.modelmanager.ModifyModelAccess(args)
  1285  	c.Assert(err, jc.ErrorIsNil)
  1286  	expectedErr := `unknown action "dance"`
  1287  	c.Assert(result.OneError(), gc.ErrorMatches, expectedErr)
  1288  }
  1289  
  1290  type fakeProvider struct {
  1291  	environs.EnvironProvider
  1292  }
  1293  
  1294  func (*fakeProvider) Validate(cfg, old *config.Config) (*config.Config, error) {
  1295  	return cfg, nil
  1296  }
  1297  
  1298  func (*fakeProvider) PrepareForCreateEnvironment(controllerUUID string, cfg *config.Config) (*config.Config, error) {
  1299  	return cfg, nil
  1300  }
  1301  
  1302  func init() {
  1303  	environs.RegisterProvider("fake", &fakeProvider{})
  1304  }