github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/client/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  	"time"
     9  
    10  	"github.com/juju/errors"
    11  	"github.com/juju/loggo"
    12  	gitjujutesting "github.com/juju/testing"
    13  	jc "github.com/juju/testing/checkers"
    14  	gc "gopkg.in/check.v1"
    15  	"gopkg.in/juju/names.v2"
    16  
    17  	// Register the providers for the field check test
    18  	"github.com/juju/juju/apiserver/common"
    19  	"github.com/juju/juju/apiserver/facades/client/modelmanager"
    20  	"github.com/juju/juju/apiserver/params"
    21  	apiservertesting "github.com/juju/juju/apiserver/testing"
    22  	"github.com/juju/juju/caas"
    23  	"github.com/juju/juju/cloud"
    24  	"github.com/juju/juju/core/status"
    25  	"github.com/juju/juju/environs"
    26  	"github.com/juju/juju/environs/config"
    27  	"github.com/juju/juju/environs/context"
    28  	jujutesting "github.com/juju/juju/juju/testing"
    29  	"github.com/juju/juju/permission"
    30  	_ "github.com/juju/juju/provider/azure"
    31  	"github.com/juju/juju/provider/dummy"
    32  	_ "github.com/juju/juju/provider/ec2"
    33  	_ "github.com/juju/juju/provider/joyent"
    34  	_ "github.com/juju/juju/provider/maas"
    35  	_ "github.com/juju/juju/provider/openstack"
    36  	"github.com/juju/juju/state"
    37  	"github.com/juju/juju/state/stateenvirons"
    38  	statetesting "github.com/juju/juju/state/testing"
    39  	coretesting "github.com/juju/juju/testing"
    40  	"github.com/juju/juju/testing/factory"
    41  	jujuversion "github.com/juju/juju/version"
    42  )
    43  
    44  func createArgs(owner names.UserTag) params.ModelCreateArgs {
    45  	return params.ModelCreateArgs{
    46  		Name:     "test-model",
    47  		OwnerTag: owner.String(),
    48  		Config: map[string]interface{}{
    49  			"authorized-keys": "ssh-key",
    50  			// And to make it a valid dummy config
    51  			"controller": false,
    52  		},
    53  	}
    54  }
    55  
    56  type modelManagerSuite struct {
    57  	gitjujutesting.IsolationSuite
    58  	st         *mockState
    59  	ctlrSt     *mockState
    60  	caasSt     *mockState
    61  	caasBroker *mockCaasBroker
    62  	authoriser apiservertesting.FakeAuthorizer
    63  	api        *modelmanager.ModelManagerAPI
    64  	caasApi    *modelmanager.ModelManagerAPI
    65  
    66  	callContext context.ProviderCallContext
    67  }
    68  
    69  var _ = gc.Suite(&modelManagerSuite{})
    70  
    71  func (s *modelManagerSuite) SetUpTest(c *gc.C) {
    72  	s.IsolationSuite.SetUpTest(c)
    73  
    74  	attrs := dummy.SampleConfig()
    75  	attrs["agent-version"] = jujuversion.Current.String()
    76  	cfg, err := config.New(config.UseDefaults, attrs)
    77  	c.Assert(err, jc.ErrorIsNil)
    78  
    79  	dummyCloud := cloud.Cloud{
    80  		Name:      "dummy",
    81  		Type:      "dummy",
    82  		AuthTypes: []cloud.AuthType{cloud.EmptyAuthType},
    83  		Regions: []cloud.Region{
    84  			{Name: "some-region"},
    85  			{Name: "qux"},
    86  		},
    87  	}
    88  
    89  	mockK8sCloud := cloud.Cloud{
    90  		Name:      "k8s-cloud",
    91  		Type:      "kubernetes",
    92  		AuthTypes: []cloud.AuthType{cloud.UserPassAuthType},
    93  	}
    94  
    95  	controllerModel := &mockModel{
    96  		owner: names.NewUserTag("admin"),
    97  		life:  state.Alive,
    98  		cfg:   cfg,
    99  		status: status.StatusInfo{
   100  			Status: status.Available,
   101  			Since:  &time.Time{},
   102  		},
   103  		users: []*mockModelUser{{
   104  			userName: "admin",
   105  			access:   permission.AdminAccess,
   106  		}, {
   107  			userName: "add-model",
   108  			access:   permission.AdminAccess,
   109  		}, {
   110  
   111  			userName: "otheruser",
   112  			access:   permission.WriteAccess,
   113  		}},
   114  	}
   115  
   116  	s.st = &mockState{
   117  		block: -1,
   118  		cloud: dummyCloud,
   119  		clouds: map[names.CloudTag]cloud.Cloud{
   120  			names.NewCloudTag("some-cloud"): dummyCloud,
   121  		},
   122  		controllerModel: controllerModel,
   123  		model: &mockModel{
   124  			owner: names.NewUserTag("admin"),
   125  			life:  state.Alive,
   126  			tag:   coretesting.ModelTag,
   127  			cfg:   cfg,
   128  			status: status.StatusInfo{
   129  				Status: status.Available,
   130  				Since:  &time.Time{},
   131  			},
   132  			users: []*mockModelUser{{
   133  				userName: "admin",
   134  				access:   permission.AdminAccess,
   135  			}, {
   136  				userName: "add-model",
   137  				access:   permission.AdminAccess,
   138  			}, {
   139  
   140  				userName: "otheruser",
   141  				access:   permission.WriteAccess,
   142  			}},
   143  			cfgDefaults: config.ModelDefaultAttributes{
   144  				"attr": config.AttributeDefaultValues{
   145  					Default:    "",
   146  					Controller: "val",
   147  					Regions: []config.RegionDefaultValue{{
   148  						Name:  "dummy",
   149  						Value: "val++"}}},
   150  				"attr2": config.AttributeDefaultValues{
   151  					Controller: "val3",
   152  					Default:    "val2",
   153  					Regions: []config.RegionDefaultValue{{
   154  						Name:  "left",
   155  						Value: "spam"}}},
   156  			},
   157  		},
   158  		cred: statetesting.NewEmptyCredential(),
   159  		cfgDefaults: config.ModelDefaultAttributes{
   160  			"attr": config.AttributeDefaultValues{
   161  				Default:    "",
   162  				Controller: "val",
   163  				Regions: []config.RegionDefaultValue{{
   164  					Name:  "dummy",
   165  					Value: "val++"}}},
   166  			"attr2": config.AttributeDefaultValues{
   167  				Controller: "val3",
   168  				Default:    "val2",
   169  				Regions: []config.RegionDefaultValue{{
   170  					Name:  "left",
   171  					Value: "spam"}}},
   172  		},
   173  		modelConfig: coretesting.ModelConfig(c),
   174  	}
   175  	s.ctlrSt = &mockState{
   176  		model:           controllerModel,
   177  		controllerModel: controllerModel,
   178  		cred:            statetesting.NewEmptyCredential(),
   179  		cloud:           dummyCloud,
   180  		clouds: map[names.CloudTag]cloud.Cloud{
   181  			names.NewCloudTag("some-cloud"): dummyCloud,
   182  		},
   183  		cloudUsers: map[string]permission.Access{},
   184  	}
   185  
   186  	caasCred := state.Credential{}
   187  	caasCred.AuthType = string(cloud.UserPassAuthType)
   188  	s.caasSt = &mockState{
   189  		cloud: mockK8sCloud,
   190  		clouds: map[names.CloudTag]cloud.Cloud{
   191  			names.NewCloudTag("k8s-cloud"): mockK8sCloud,
   192  		},
   193  		controllerModel: controllerModel,
   194  		model: &mockModel{
   195  			owner: names.NewUserTag("admin"),
   196  			life:  state.Alive,
   197  			tag:   coretesting.ModelTag,
   198  			cfg:   cfg,
   199  			status: status.StatusInfo{
   200  				Status: status.Available,
   201  				Since:  &time.Time{},
   202  			},
   203  			users: []*mockModelUser{{
   204  				userName: "admin",
   205  				access:   permission.AdminAccess,
   206  			}, {
   207  				userName: "add-model",
   208  				access:   permission.AdminAccess,
   209  			}},
   210  		},
   211  		cred:        caasCred,
   212  		modelConfig: coretesting.ModelConfig(c),
   213  	}
   214  
   215  	s.authoriser = apiservertesting.FakeAuthorizer{
   216  		Tag: names.NewUserTag("admin"),
   217  	}
   218  
   219  	s.callContext = context.NewCloudCallContext()
   220  
   221  	s.caasBroker = &mockCaasBroker{}
   222  	newBroker := func(args environs.OpenParams) (caas.Broker, error) {
   223  		return s.caasBroker, nil
   224  	}
   225  
   226  	api, err := modelmanager.NewModelManagerAPI(s.st, s.ctlrSt, nil, newBroker, s.authoriser, s.st.model, s.callContext)
   227  	c.Assert(err, jc.ErrorIsNil)
   228  	s.api = api
   229  	caasApi, err := modelmanager.NewModelManagerAPI(s.caasSt, s.ctlrSt, nil, newBroker, s.authoriser, s.st.model, s.callContext)
   230  	c.Assert(err, jc.ErrorIsNil)
   231  	s.caasApi = caasApi
   232  }
   233  
   234  func (s *modelManagerSuite) setAPIUser(c *gc.C, user names.UserTag) {
   235  	s.authoriser.Tag = user
   236  	newBroker := func(args environs.OpenParams) (caas.Broker, error) {
   237  		return s.caasBroker, nil
   238  	}
   239  	mm, err := modelmanager.NewModelManagerAPI(s.st, s.ctlrSt, nil, newBroker, s.authoriser, s.st.model, s.callContext)
   240  	c.Assert(err, jc.ErrorIsNil)
   241  	s.api = mm
   242  }
   243  
   244  func (s *modelManagerSuite) getModelArgs(c *gc.C) state.ModelArgs {
   245  	return getModelArgsFor(c, s.st)
   246  }
   247  
   248  func getModelArgsFor(c *gc.C, mockState *mockState) state.ModelArgs {
   249  	for _, v := range mockState.Calls() {
   250  		if v.Args == nil {
   251  			continue
   252  		}
   253  		if newModelArgs, ok := v.Args[0].(state.ModelArgs); ok {
   254  			return newModelArgs
   255  		}
   256  	}
   257  	c.Fatal("failed to find state.ModelArgs")
   258  	panic("unreachable")
   259  }
   260  
   261  func (s *modelManagerSuite) TestCreateModelArgs(c *gc.C) {
   262  	args := params.ModelCreateArgs{
   263  		Name:     "foo",
   264  		OwnerTag: "user-admin",
   265  		Config: map[string]interface{}{
   266  			"bar": "baz",
   267  		},
   268  		CloudRegion:        "qux",
   269  		CloudCredentialTag: "cloudcred-some-cloud_admin_some-credential",
   270  	}
   271  	_, err := s.api.CreateModel(args)
   272  	c.Assert(err, jc.ErrorIsNil)
   273  	s.st.CheckCallNames(c,
   274  		"ControllerTag",
   275  		"ModelUUID",
   276  		"ControllerTag",
   277  		"Cloud",
   278  		"CloudCredential",
   279  		"ComposeNewModelConfig",
   280  		"ControllerConfig",
   281  		"NewModel",
   282  		"ReloadSpaces",
   283  		"Close",
   284  		"GetBackend",
   285  		"Model",
   286  		"IsController",
   287  		"AllMachines",
   288  		"LatestMigration",
   289  	)
   290  
   291  	// Check that Model.LastModelConnection is called three times
   292  	// without making the test depend on other calls to Model
   293  	n := 0
   294  	for _, call := range s.st.model.Calls() {
   295  		if call.FuncName == "LastModelConnection" {
   296  			n = n + 1
   297  		}
   298  	}
   299  	c.Assert(n, gc.Equals, 3)
   300  
   301  	// We cannot predict the UUID, because it's generated,
   302  	// so we just extract it and ensure that it's not the
   303  	// same as the controller UUID.
   304  	newModelArgs := s.getModelArgs(c)
   305  	uuid := newModelArgs.Config.UUID()
   306  	c.Assert(uuid, gc.Not(gc.Equals), s.st.controllerModel.cfg.UUID())
   307  
   308  	cfg, err := config.New(config.UseDefaults, map[string]interface{}{
   309  		"name":          "foo",
   310  		"type":          "dummy",
   311  		"uuid":          uuid,
   312  		"agent-version": jujuversion.Current.String(),
   313  		"bar":           "baz",
   314  		"controller":    false,
   315  		"broken":        "",
   316  		"secret":        "pork",
   317  		"something":     "value",
   318  	})
   319  	c.Assert(err, jc.ErrorIsNil)
   320  
   321  	c.Assert(newModelArgs.StorageProviderRegistry, gc.NotNil)
   322  	newModelArgs.StorageProviderRegistry = nil
   323  
   324  	c.Assert(newModelArgs, jc.DeepEquals, state.ModelArgs{
   325  		Type:        state.ModelTypeIAAS,
   326  		Owner:       names.NewUserTag("admin"),
   327  		CloudName:   "some-cloud",
   328  		CloudRegion: "qux",
   329  		CloudCredential: names.NewCloudCredentialTag(
   330  			"some-cloud/admin/some-credential",
   331  		),
   332  		Config: cfg,
   333  	})
   334  }
   335  
   336  func (s *modelManagerSuite) TestCreateModelArgsWithCloud(c *gc.C) {
   337  	args := params.ModelCreateArgs{
   338  		Name:     "foo",
   339  		OwnerTag: "user-admin",
   340  		Config: map[string]interface{}{
   341  			"bar": "baz",
   342  		},
   343  		CloudTag:           "cloud-some-cloud",
   344  		CloudRegion:        "qux",
   345  		CloudCredentialTag: "cloudcred-some-cloud_admin_some-credential",
   346  	}
   347  	_, err := s.api.CreateModel(args)
   348  	c.Assert(err, jc.ErrorIsNil)
   349  
   350  	newModelArgs := s.getModelArgs(c)
   351  	c.Assert(newModelArgs.CloudName, gc.Equals, "some-cloud")
   352  }
   353  
   354  func (s *modelManagerSuite) TestCreateModelArgsWithCloudNotFound(c *gc.C) {
   355  	s.st.SetErrors(errors.NotFoundf("cloud"))
   356  	args := params.ModelCreateArgs{
   357  		Name:     "foo",
   358  		OwnerTag: "user-admin",
   359  		CloudTag: "cloud-some-unknown-cloud",
   360  	}
   361  	_, err := s.api.CreateModel(args)
   362  	c.Assert(err, gc.ErrorMatches, `cloud "some-unknown-cloud" not found, expected one of \["some-cloud"\]`)
   363  }
   364  
   365  func (s *modelManagerSuite) TestCreateModelDefaultRegion(c *gc.C) {
   366  	args := params.ModelCreateArgs{
   367  		Name:     "foo",
   368  		OwnerTag: "user-admin",
   369  	}
   370  	_, err := s.api.CreateModel(args)
   371  	c.Assert(err, jc.ErrorIsNil)
   372  
   373  	newModelArgs := s.getModelArgs(c)
   374  	c.Assert(newModelArgs.CloudRegion, gc.Equals, "some-region")
   375  }
   376  
   377  func (s *modelManagerSuite) TestCreateModelDefaultCredentialAdmin(c *gc.C) {
   378  	s.testCreateModelDefaultCredentialAdmin(c, "user-admin")
   379  }
   380  
   381  func (s *modelManagerSuite) TestCreateModelDefaultCredentialAdminNoDomain(c *gc.C) {
   382  	s.testCreateModelDefaultCredentialAdmin(c, "user-admin")
   383  }
   384  
   385  func (s *modelManagerSuite) testCreateModelDefaultCredentialAdmin(c *gc.C, ownerTag string) {
   386  	s.st.cloud.AuthTypes = []cloud.AuthType{"userpass"}
   387  	args := params.ModelCreateArgs{
   388  		Name:     "foo",
   389  		OwnerTag: ownerTag,
   390  	}
   391  	_, err := s.api.CreateModel(args)
   392  	c.Assert(err, jc.ErrorIsNil)
   393  
   394  	newModelArgs := s.getModelArgs(c)
   395  	c.Assert(newModelArgs.CloudCredential, gc.Equals, names.NewCloudCredentialTag(
   396  		"some-cloud/bob/some-credential",
   397  	))
   398  }
   399  
   400  func (s *modelManagerSuite) TestCreateModelEmptyCredentialNonAdmin(c *gc.C) {
   401  	args := params.ModelCreateArgs{
   402  		Name:     "foo",
   403  		OwnerTag: "user-bob",
   404  	}
   405  	_, err := s.api.CreateModel(args)
   406  	c.Assert(err, jc.ErrorIsNil)
   407  
   408  	newModelArgs := s.getModelArgs(c)
   409  	c.Assert(newModelArgs.CloudCredential, gc.Equals, names.CloudCredentialTag{})
   410  }
   411  
   412  func (s *modelManagerSuite) TestCreateModelNoDefaultCredentialNonAdmin(c *gc.C) {
   413  	s.st.cloud.AuthTypes = nil
   414  	args := params.ModelCreateArgs{
   415  		Name:     "foo",
   416  		OwnerTag: "user-bob",
   417  	}
   418  	_, err := s.api.CreateModel(args)
   419  	c.Assert(err, gc.ErrorMatches, "no credential specified")
   420  }
   421  
   422  func (s *modelManagerSuite) TestCreateModelUnknownCredential(c *gc.C) {
   423  	s.st.SetErrors(nil, errors.NotFoundf("credential"))
   424  	args := params.ModelCreateArgs{
   425  		Name:               "foo",
   426  		OwnerTag:           "user-admin",
   427  		CloudCredentialTag: "cloudcred-some-cloud_admin_bar",
   428  	}
   429  	_, err := s.api.CreateModel(args)
   430  	c.Assert(err, gc.ErrorMatches, `getting credential: credential not found`)
   431  }
   432  
   433  func (s *modelManagerSuite) TestCreateCAASModelArgs(c *gc.C) {
   434  	args := params.ModelCreateArgs{
   435  		Name:               "foo",
   436  		OwnerTag:           "user-admin",
   437  		Config:             map[string]interface{}{},
   438  		CloudTag:           "cloud-k8s-cloud",
   439  		CloudCredentialTag: "cloudcred-k8s-cloud_admin_some-credential",
   440  	}
   441  	_, err := s.caasApi.CreateModel(args)
   442  	c.Assert(err, jc.ErrorIsNil)
   443  	s.caasSt.CheckCallNames(c,
   444  		"ControllerTag",
   445  		"ModelUUID",
   446  		"ControllerTag",
   447  		"Cloud",
   448  		"CloudCredential",
   449  		"NewModel",
   450  		"Close",
   451  		"GetBackend",
   452  		"Model",
   453  		"IsController",
   454  		"AllMachines",
   455  		"LatestMigration",
   456  	)
   457  
   458  	// Check that Model.LastModelConnection is called just twice
   459  	// without making the test depend on other calls to Model
   460  	n := 0
   461  	for _, call := range s.caasSt.model.Calls() {
   462  		if call.FuncName == "LastModelConnection" {
   463  			n = n + 1
   464  		}
   465  	}
   466  	c.Assert(n, gc.Equals, 2)
   467  
   468  	// We cannot predict the UUID, because it's generated,
   469  	// so we just extract it and ensure that it's not the
   470  	// same as the controller UUID.
   471  	newModelArgs := getModelArgsFor(c, s.caasSt)
   472  	uuid := newModelArgs.Config.UUID()
   473  	c.Assert(uuid, gc.Not(gc.Equals), s.caasSt.controllerModel.cfg.UUID())
   474  
   475  	cfg, err := config.New(config.UseDefaults, map[string]interface{}{
   476  		"name":          "foo",
   477  		"type":          "kubernetes",
   478  		"uuid":          uuid,
   479  		"agent-version": jujuversion.Current.String(),
   480  	})
   481  	c.Assert(err, jc.ErrorIsNil)
   482  
   483  	c.Assert(newModelArgs.StorageProviderRegistry, gc.NotNil)
   484  	newModelArgs.StorageProviderRegistry = nil
   485  
   486  	c.Assert(newModelArgs, jc.DeepEquals, state.ModelArgs{
   487  		Type:      state.ModelTypeCAAS,
   488  		Owner:     names.NewUserTag("admin"),
   489  		CloudName: "k8s-cloud",
   490  		CloudCredential: names.NewCloudCredentialTag(
   491  			"k8s-cloud/admin/some-credential",
   492  		),
   493  		Config: cfg,
   494  	})
   495  }
   496  
   497  func (s *modelManagerSuite) TestCreateCAASModelNamespaceClash(c *gc.C) {
   498  	s.caasBroker.namespaces = []string{"foo"}
   499  	args := params.ModelCreateArgs{
   500  		Name:               "foo",
   501  		OwnerTag:           "user-admin",
   502  		Config:             map[string]interface{}{},
   503  		CloudTag:           "cloud-k8s-cloud",
   504  		CloudCredentialTag: "cloudcred-k8s-cloud_admin_some-credential",
   505  	}
   506  	_, err := s.caasApi.CreateModel(args)
   507  	c.Assert(err, gc.ErrorMatches, `namespace called "foo" already exists, would clash with model name`)
   508  }
   509  
   510  func (s *modelManagerSuite) TestModelDefaults(c *gc.C) {
   511  	result, err := s.api.ModelDefaults()
   512  	c.Assert(err, jc.ErrorIsNil)
   513  	expectedValues := map[string]params.ModelDefaults{
   514  		"attr": {
   515  			Controller: "val",
   516  			Default:    "",
   517  			Regions: []params.RegionDefaults{{
   518  				RegionName: "dummy",
   519  				Value:      "val++"}}},
   520  		"attr2": {
   521  			Controller: "val3",
   522  			Default:    "val2",
   523  			Regions: []params.RegionDefaults{{
   524  				RegionName: "left",
   525  				Value:      "spam"}}},
   526  	}
   527  	c.Assert(result.Config, jc.DeepEquals, expectedValues)
   528  }
   529  
   530  func (s *modelManagerSuite) TestSetModelDefaults(c *gc.C) {
   531  	params := params.SetModelDefaults{
   532  		Config: []params.ModelDefaultValues{{
   533  			Config: map[string]interface{}{
   534  				"attr3": "val3",
   535  				"attr4": "val4"},
   536  		}}}
   537  	result, err := s.api.SetModelDefaults(params)
   538  	c.Assert(err, jc.ErrorIsNil)
   539  	c.Assert(result.OneError(), jc.ErrorIsNil)
   540  	c.Assert(s.st.cfgDefaults, jc.DeepEquals, config.ModelDefaultAttributes{
   541  		"attr": {
   542  			Controller: "val",
   543  			Default:    "",
   544  			Regions: []config.RegionDefaultValue{{
   545  				Name:  "dummy",
   546  				Value: "val++"}}},
   547  		"attr2": {
   548  			Controller: "val3",
   549  			Default:    "val2",
   550  			Regions: []config.RegionDefaultValue{{
   551  				Name:  "left",
   552  				Value: "spam"}}},
   553  		"attr3": {Controller: "val3"},
   554  		"attr4": {Controller: "val4"},
   555  	})
   556  }
   557  
   558  func (s *modelManagerSuite) blockAllChanges(c *gc.C, msg string) {
   559  	s.st.blockMsg = msg
   560  	s.st.block = state.ChangeBlock
   561  }
   562  
   563  func (s *modelManagerSuite) assertBlocked(c *gc.C, err error, msg string) {
   564  	c.Assert(params.IsCodeOperationBlocked(err), jc.IsTrue, gc.Commentf("error: %#v", err))
   565  	c.Assert(errors.Cause(err), jc.DeepEquals, &params.Error{
   566  		Message: msg,
   567  		Code:    "operation is blocked",
   568  	})
   569  }
   570  
   571  func (s *modelManagerSuite) TestBlockChangesSetModelDefaults(c *gc.C) {
   572  	s.blockAllChanges(c, "TestBlockChangesSetModelDefaults")
   573  	_, err := s.api.SetModelDefaults(params.SetModelDefaults{})
   574  	s.assertBlocked(c, err, "TestBlockChangesSetModelDefaults")
   575  }
   576  
   577  func (s *modelManagerSuite) TestUnsetModelDefaults(c *gc.C) {
   578  	args := params.UnsetModelDefaults{
   579  		Keys: []params.ModelUnsetKeys{{
   580  			Keys: []string{"attr"},
   581  		}}}
   582  	result, err := s.api.UnsetModelDefaults(args)
   583  	c.Assert(err, jc.ErrorIsNil)
   584  	c.Assert(result.OneError(), jc.ErrorIsNil)
   585  	want := config.ModelDefaultAttributes{
   586  		"attr": config.AttributeDefaultValues{
   587  			Regions: []config.RegionDefaultValue{
   588  				{Name: "dummy", Value: "val++"},
   589  			},
   590  		},
   591  		"attr2": config.AttributeDefaultValues{
   592  			Default:    "val2",
   593  			Controller: "val3",
   594  			Regions: []config.RegionDefaultValue{
   595  				{Name: "left", Value: "spam"},
   596  			},
   597  		},
   598  	}
   599  	c.Assert(s.st.cfgDefaults, jc.DeepEquals, want)
   600  }
   601  
   602  func (s *modelManagerSuite) TestBlockUnsetModelDefaults(c *gc.C) {
   603  	s.blockAllChanges(c, "TestBlockUnsetModelDefaults")
   604  	args := params.UnsetModelDefaults{
   605  		Keys: []params.ModelUnsetKeys{{
   606  			Keys: []string{"abc"},
   607  		}}}
   608  	_, err := s.api.UnsetModelDefaults(args)
   609  	s.assertBlocked(c, err, "TestBlockUnsetModelDefaults")
   610  }
   611  
   612  func (s *modelManagerSuite) TestUnsetModelDefaultsMissing(c *gc.C) {
   613  	// It's okay to unset a non-existent attribute.
   614  	args := params.UnsetModelDefaults{
   615  		Keys: []params.ModelUnsetKeys{{
   616  			Keys: []string{"not there"},
   617  		}}}
   618  	result, err := s.api.UnsetModelDefaults(args)
   619  	c.Assert(err, jc.ErrorIsNil)
   620  	c.Assert(result.OneError(), jc.ErrorIsNil)
   621  }
   622  
   623  func (s *modelManagerSuite) TestModelDefaultsAsNormalUser(c *gc.C) {
   624  	s.setAPIUser(c, names.NewUserTag("charlie"))
   625  	got, err := s.api.ModelDefaults()
   626  	c.Assert(err, gc.ErrorMatches, "permission denied")
   627  	c.Assert(got, gc.DeepEquals, params.ModelDefaultsResult{})
   628  }
   629  
   630  func (s *modelManagerSuite) TestSetModelDefaultsAsNormalUser(c *gc.C) {
   631  	s.setAPIUser(c, names.NewUserTag("charlie"))
   632  	got, err := s.api.SetModelDefaults(params.SetModelDefaults{
   633  		Config: []params.ModelDefaultValues{{
   634  			Config: map[string]interface{}{
   635  				"ftp-proxy": "http://charlie",
   636  			}}}})
   637  	c.Assert(err, jc.ErrorIsNil)
   638  	c.Assert(got, jc.DeepEquals, params.ErrorResults{
   639  		Results: []params.ErrorResult{
   640  			{
   641  				Error: &params.Error{
   642  					Message: "permission denied",
   643  					Code:    "unauthorized access"}}}})
   644  
   645  	// Make sure it didn't change.
   646  	s.setAPIUser(c, names.NewUserTag("admin"))
   647  	cfg, err := s.api.ModelDefaults()
   648  	c.Assert(err, jc.ErrorIsNil)
   649  	c.Assert(cfg.Config["ftp-proxy"].Controller, gc.IsNil)
   650  }
   651  
   652  func (s *modelManagerSuite) TestUnsetModelDefaultsAsNormalUser(c *gc.C) {
   653  	s.setAPIUser(c, names.NewUserTag("charlie"))
   654  	got, err := s.api.UnsetModelDefaults(params.UnsetModelDefaults{
   655  		Keys: []params.ModelUnsetKeys{{
   656  			Keys: []string{"attr2"}}}})
   657  	c.Assert(err, gc.ErrorMatches, "permission denied")
   658  	c.Assert(got, gc.DeepEquals, params.ErrorResults{
   659  		Results: []params.ErrorResult{{Error: nil}},
   660  	})
   661  
   662  	// Make sure it didn't change.
   663  	s.setAPIUser(c, names.NewUserTag("admin"))
   664  	cfg, err := s.api.ModelDefaults()
   665  	c.Assert(err, jc.ErrorIsNil)
   666  	c.Assert(cfg.Config["attr2"].Controller.(string), gc.Equals, "val3")
   667  }
   668  
   669  func (s *modelManagerSuite) TestDumpModelV2(c *gc.C) {
   670  	api := &modelmanager.ModelManagerAPIV2{
   671  		&modelmanager.ModelManagerAPIV3{
   672  			&modelmanager.ModelManagerAPIV4{
   673  				s.api,
   674  			},
   675  		},
   676  	}
   677  
   678  	results := api.DumpModels(params.Entities{[]params.Entity{{
   679  		Tag: "bad-tag",
   680  	}, {
   681  		Tag: "application-foo",
   682  	}, {
   683  		Tag: s.st.ModelTag().String(),
   684  	}}})
   685  
   686  	c.Assert(results.Results, gc.HasLen, 3)
   687  	bad, notApp, good := results.Results[0], results.Results[1], results.Results[2]
   688  	c.Check(bad.Result, gc.IsNil)
   689  	c.Check(bad.Error.Message, gc.Equals, `"bad-tag" is not a valid tag`)
   690  
   691  	c.Check(notApp.Result, gc.IsNil)
   692  	c.Check(notApp.Error.Message, gc.Equals, `"application-foo" is not a valid model tag`)
   693  
   694  	c.Check(good.Error, gc.IsNil)
   695  	c.Check(good.Result, jc.DeepEquals, map[string]interface{}{
   696  		"model-uuid": "deadbeef-0bad-400d-8000-4b1d0d06f00d",
   697  	})
   698  }
   699  
   700  func (s *modelManagerSuite) TestDumpModel(c *gc.C) {
   701  	results := s.api.DumpModels(params.DumpModelRequest{
   702  		Entities: []params.Entity{{
   703  			Tag: "bad-tag",
   704  		}, {
   705  			Tag: "application-foo",
   706  		}, {
   707  			Tag: s.st.ModelTag().String(),
   708  		}}})
   709  
   710  	c.Assert(results.Results, gc.HasLen, 3)
   711  	bad, notApp, good := results.Results[0], results.Results[1], results.Results[2]
   712  	c.Check(bad.Result, gc.Equals, "")
   713  	c.Check(bad.Error.Message, gc.Equals, `"bad-tag" is not a valid tag`)
   714  
   715  	c.Check(notApp.Result, gc.Equals, "")
   716  	c.Check(notApp.Error.Message, gc.Equals, `"application-foo" is not a valid model tag`)
   717  
   718  	c.Check(good.Error, gc.IsNil)
   719  	c.Check(good.Result, jc.DeepEquals, "model-uuid: deadbeef-0bad-400d-8000-4b1d0d06f00d\n")
   720  }
   721  
   722  func (s *modelManagerSuite) TestDumpModelMissingModel(c *gc.C) {
   723  	s.st.SetErrors(errors.NotFoundf("boom"))
   724  	tag := names.NewModelTag("deadbeef-0bad-400d-8000-4b1d0d06f000")
   725  	models := params.DumpModelRequest{Entities: []params.Entity{{Tag: tag.String()}}}
   726  	results := s.api.DumpModels(models)
   727  	s.st.CheckCalls(c, []gitjujutesting.StubCall{
   728  		{"ControllerTag", nil},
   729  		{"ModelUUID", nil},
   730  		{"GetBackend", []interface{}{tag.Id()}},
   731  	})
   732  	c.Assert(results.Results, gc.HasLen, 1)
   733  	result := results.Results[0]
   734  	c.Assert(result.Result, gc.Equals, "")
   735  	c.Assert(result.Error, gc.NotNil)
   736  	c.Check(result.Error.Code, gc.Equals, `not found`)
   737  	c.Check(result.Error.Message, gc.Equals, `id not found`)
   738  }
   739  
   740  func (s *modelManagerSuite) TestDumpModelUsers(c *gc.C) {
   741  	models := params.DumpModelRequest{Entities: []params.Entity{{Tag: s.st.ModelTag().String()}}}
   742  	for _, user := range []names.UserTag{
   743  		names.NewUserTag("otheruser"),
   744  		names.NewUserTag("unknown"),
   745  	} {
   746  		s.setAPIUser(c, user)
   747  		results := s.api.DumpModels(models)
   748  		c.Assert(results.Results, gc.HasLen, 1)
   749  		result := results.Results[0]
   750  		c.Assert(result.Result, gc.Equals, "")
   751  		c.Assert(result.Error, gc.NotNil)
   752  		c.Check(result.Error.Message, gc.Equals, `permission denied`)
   753  	}
   754  }
   755  
   756  func (s *modelManagerSuite) TestDumpModelsDB(c *gc.C) {
   757  	results := s.api.DumpModelsDB(params.Entities{[]params.Entity{{
   758  		Tag: "bad-tag",
   759  	}, {
   760  		Tag: "application-foo",
   761  	}, {
   762  		Tag: s.st.ModelTag().String(),
   763  	}}})
   764  
   765  	c.Assert(results.Results, gc.HasLen, 3)
   766  	bad, notApp, good := results.Results[0], results.Results[1], results.Results[2]
   767  	c.Check(bad.Result, gc.IsNil)
   768  	c.Check(bad.Error.Message, gc.Equals, `"bad-tag" is not a valid tag`)
   769  
   770  	c.Check(notApp.Result, gc.IsNil)
   771  	c.Check(notApp.Error.Message, gc.Equals, `"application-foo" is not a valid model tag`)
   772  
   773  	c.Check(good.Error, gc.IsNil)
   774  	c.Check(good.Result, jc.DeepEquals, map[string]interface{}{
   775  		"models": "lots of data",
   776  	})
   777  }
   778  
   779  func (s *modelManagerSuite) TestDumpModelsDBMissingModel(c *gc.C) {
   780  	s.st.SetErrors(errors.NotFoundf("boom"))
   781  	tag := names.NewModelTag("deadbeef-0bad-400d-8000-4b1d0d06f000")
   782  	models := params.Entities{[]params.Entity{{Tag: tag.String()}}}
   783  	results := s.api.DumpModelsDB(models)
   784  
   785  	s.st.CheckCalls(c, []gitjujutesting.StubCall{
   786  		{"ControllerTag", nil},
   787  		{"ModelUUID", nil},
   788  		{"ModelTag", nil},
   789  		{"GetBackend", []interface{}{tag.Id()}},
   790  	})
   791  	c.Assert(results.Results, gc.HasLen, 1)
   792  	result := results.Results[0]
   793  	c.Assert(result.Result, gc.IsNil)
   794  	c.Assert(result.Error, gc.NotNil)
   795  	c.Check(result.Error.Code, gc.Equals, `not found`)
   796  	c.Check(result.Error.Message, gc.Equals, `id not found`)
   797  }
   798  
   799  func (s *modelManagerSuite) TestDumpModelsDBUsers(c *gc.C) {
   800  	models := params.Entities{[]params.Entity{{Tag: s.st.ModelTag().String()}}}
   801  	for _, user := range []names.UserTag{
   802  		names.NewUserTag("otheruser"),
   803  		names.NewUserTag("unknown"),
   804  	} {
   805  		s.setAPIUser(c, user)
   806  		results := s.api.DumpModelsDB(models)
   807  		c.Assert(results.Results, gc.HasLen, 1)
   808  		result := results.Results[0]
   809  		c.Assert(result.Result, gc.IsNil)
   810  		c.Assert(result.Error, gc.NotNil)
   811  		c.Check(result.Error.Message, gc.Equals, `permission denied`)
   812  	}
   813  }
   814  
   815  func (s *modelManagerSuite) TestAddModelCanCreateModel(c *gc.C) {
   816  	addModelUser := names.NewUserTag("add-model")
   817  	s.ctlrSt.cloudUsers[addModelUser.Id()] = permission.AddModelAccess
   818  	s.setAPIUser(c, addModelUser)
   819  	_, err := s.api.CreateModel(createArgs(addModelUser))
   820  	c.Assert(err, jc.ErrorIsNil)
   821  }
   822  
   823  func (s *modelManagerSuite) TestAddModelCantCreateModelForSomeoneElse(c *gc.C) {
   824  	addModelUser := names.NewUserTag("add-model")
   825  	s.ctlrSt.cloudUsers[addModelUser.Id()] = permission.AddModelAccess
   826  	s.setAPIUser(c, addModelUser)
   827  	nonAdminUser := names.NewUserTag("non-admin")
   828  	_, err := s.api.CreateModel(createArgs(nonAdminUser))
   829  	c.Assert(err, gc.ErrorMatches, "\"add-model\" permission does not permit creation of models for different owners: permission denied")
   830  }
   831  
   832  func (s *modelManagerSuite) TestDestroyModelsV3(c *gc.C) {
   833  	api := &modelmanager.ModelManagerAPIV3{
   834  		&modelmanager.ModelManagerAPIV4{
   835  			s.api,
   836  		},
   837  	}
   838  	results, err := api.DestroyModels(params.Entities{
   839  		Entities: []params.Entity{{coretesting.ModelTag.String()}},
   840  	})
   841  	c.Assert(err, jc.ErrorIsNil)
   842  	c.Assert(results, jc.DeepEquals, params.ErrorResults{[]params.ErrorResult{{}}})
   843  	s.st.CheckCallNames(c,
   844  		"ControllerTag",
   845  		"ModelUUID",
   846  		"GetBackend",
   847  		"Model",
   848  		"GetBlockForType",
   849  		"GetBlockForType",
   850  		"GetBlockForType",
   851  		"Model",
   852  		"ControllerConfig",
   853  		"ModelConfig",
   854  		"MetricsManager",
   855  	)
   856  	destroyStorage := true
   857  	s.st.model.CheckCalls(c, []gitjujutesting.StubCall{
   858  		{"UUID", nil},
   859  		{"Destroy", []interface{}{state.DestroyModelParams{
   860  			DestroyStorage: &destroyStorage,
   861  		}}},
   862  	})
   863  }
   864  
   865  // modelManagerStateSuite contains end-to-end tests.
   866  // Prefer adding tests to modelManagerSuite above.
   867  type modelManagerStateSuite struct {
   868  	jujutesting.JujuConnSuite
   869  	modelmanager *modelmanager.ModelManagerAPI
   870  	authoriser   apiservertesting.FakeAuthorizer
   871  
   872  	callContext context.ProviderCallContext
   873  }
   874  
   875  var _ = gc.Suite(&modelManagerStateSuite{})
   876  
   877  func (s *modelManagerStateSuite) SetUpSuite(c *gc.C) {
   878  	coretesting.SkipUnlessControllerOS(c)
   879  	s.JujuConnSuite.SetUpSuite(c)
   880  }
   881  
   882  func (s *modelManagerStateSuite) SetUpTest(c *gc.C) {
   883  	s.JujuConnSuite.SetUpTest(c)
   884  	s.authoriser = apiservertesting.FakeAuthorizer{
   885  		Tag: s.AdminUserTag(c),
   886  	}
   887  	s.callContext = context.NewCloudCallContext()
   888  	loggo.GetLogger("juju.apiserver.modelmanager").SetLogLevel(loggo.TRACE)
   889  }
   890  
   891  func (s *modelManagerStateSuite) setAPIUser(c *gc.C, user names.UserTag) {
   892  	s.authoriser.Tag = user
   893  	modelmanager, err := modelmanager.NewModelManagerAPI(
   894  		common.NewModelManagerBackend(s.Model, s.StatePool),
   895  		common.NewModelManagerBackend(s.Model, s.StatePool),
   896  		stateenvirons.EnvironConfigGetter{s.State, s.Model},
   897  		nil,
   898  		s.authoriser,
   899  		s.Model,
   900  		s.callContext,
   901  	)
   902  	c.Assert(err, jc.ErrorIsNil)
   903  	s.modelmanager = modelmanager
   904  }
   905  
   906  func (s *modelManagerStateSuite) TestNewAPIAcceptsClient(c *gc.C) {
   907  	anAuthoriser := s.authoriser
   908  	anAuthoriser.Tag = names.NewUserTag("external@remote")
   909  	endPoint, err := modelmanager.NewModelManagerAPI(
   910  		common.NewModelManagerBackend(s.Model, s.StatePool),
   911  		common.NewModelManagerBackend(s.Model, s.StatePool),
   912  		nil, nil, anAuthoriser,
   913  		s.Model,
   914  		s.callContext,
   915  	)
   916  	c.Assert(err, jc.ErrorIsNil)
   917  	c.Assert(endPoint, gc.NotNil)
   918  }
   919  
   920  func (s *modelManagerStateSuite) TestNewAPIRefusesNonClient(c *gc.C) {
   921  	anAuthoriser := s.authoriser
   922  	anAuthoriser.Tag = names.NewUnitTag("mysql/0")
   923  	endPoint, err := modelmanager.NewModelManagerAPI(
   924  		common.NewModelManagerBackend(s.Model, s.StatePool),
   925  		common.NewModelManagerBackend(s.Model, s.StatePool),
   926  		nil, nil, anAuthoriser, s.Model,
   927  		s.callContext,
   928  	)
   929  	c.Assert(endPoint, gc.IsNil)
   930  	c.Assert(err, gc.ErrorMatches, "permission denied")
   931  }
   932  
   933  func (s *modelManagerStateSuite) createArgsForVersion(c *gc.C, owner names.UserTag, ver interface{}) params.ModelCreateArgs {
   934  	params := createArgs(owner)
   935  	params.Config["agent-version"] = ver
   936  	return params
   937  }
   938  
   939  func (s *modelManagerStateSuite) TestUserCanCreateModel(c *gc.C) {
   940  	owner := names.NewUserTag("admin")
   941  	s.setAPIUser(c, owner)
   942  	model, err := s.modelmanager.CreateModel(createArgs(owner))
   943  	c.Assert(err, jc.ErrorIsNil)
   944  	c.Assert(model.OwnerTag, gc.Equals, owner.String())
   945  	c.Assert(model.Name, gc.Equals, "test-model")
   946  	c.Assert(model.Type, gc.Equals, "iaas")
   947  }
   948  
   949  func (s *modelManagerStateSuite) TestAdminCanCreateModelForSomeoneElse(c *gc.C) {
   950  	s.setAPIUser(c, s.AdminUserTag(c))
   951  	owner := names.NewUserTag("external@remote")
   952  
   953  	model, err := s.modelmanager.CreateModel(createArgs(owner))
   954  	c.Assert(err, jc.ErrorIsNil)
   955  	c.Assert(model.OwnerTag, gc.Equals, owner.String())
   956  	c.Assert(model.Name, gc.Equals, "test-model")
   957  	c.Assert(model.Type, gc.Equals, "iaas")
   958  	// Make sure that the environment created does actually have the correct
   959  	// owner, and that owner is actually allowed to use the environment.
   960  	newState, err := s.StatePool.Get(model.UUID)
   961  	c.Assert(err, jc.ErrorIsNil)
   962  	defer newState.Release()
   963  
   964  	newModel, err := newState.Model()
   965  	c.Assert(err, jc.ErrorIsNil)
   966  	c.Assert(newModel.Owner(), gc.Equals, owner)
   967  	_, err = newState.UserAccess(owner, newModel.ModelTag())
   968  	c.Assert(err, jc.ErrorIsNil)
   969  }
   970  
   971  func (s *modelManagerStateSuite) TestNonAdminCannotCreateModelForSomeoneElse(c *gc.C) {
   972  	s.setAPIUser(c, names.NewUserTag("non-admin@remote"))
   973  	owner := names.NewUserTag("external@remote")
   974  	_, err := s.modelmanager.CreateModel(createArgs(owner))
   975  	c.Assert(err, gc.ErrorMatches, "permission denied")
   976  }
   977  
   978  func (s *modelManagerStateSuite) TestNonAdminCannotCreateModelForSelf(c *gc.C) {
   979  	owner := names.NewUserTag("non-admin@remote")
   980  	s.setAPIUser(c, owner)
   981  	_, err := s.modelmanager.CreateModel(createArgs(owner))
   982  	c.Assert(err, gc.ErrorMatches, "permission denied")
   983  }
   984  
   985  func (s *modelManagerStateSuite) TestCreateModelValidatesConfig(c *gc.C) {
   986  	admin := s.AdminUserTag(c)
   987  	s.setAPIUser(c, admin)
   988  	args := createArgs(admin)
   989  	args.Config["controller"] = "maybe"
   990  	_, err := s.modelmanager.CreateModel(args)
   991  	c.Assert(err, gc.ErrorMatches,
   992  		"failed to create config: provider config preparation failed: controller: expected bool, got string\\(\"maybe\"\\)",
   993  	)
   994  }
   995  
   996  func (s *modelManagerStateSuite) TestCreateModelBadConfig(c *gc.C) {
   997  	owner := names.NewUserTag("admin")
   998  	s.setAPIUser(c, owner)
   999  	for i, test := range []struct {
  1000  		key      string
  1001  		value    interface{}
  1002  		errMatch string
  1003  	}{
  1004  		{
  1005  			key:      "uuid",
  1006  			value:    "anything",
  1007  			errMatch: `failed to create config: uuid is generated, you cannot specify one`,
  1008  		},
  1009  	} {
  1010  		c.Logf("%d: %s", i, test.key)
  1011  		args := createArgs(owner)
  1012  		args.Config[test.key] = test.value
  1013  		_, err := s.modelmanager.CreateModel(args)
  1014  		c.Assert(err, gc.ErrorMatches, test.errMatch)
  1015  
  1016  	}
  1017  }
  1018  
  1019  func (s *modelManagerStateSuite) TestCreateModelSameAgentVersion(c *gc.C) {
  1020  	admin := s.AdminUserTag(c)
  1021  	s.setAPIUser(c, admin)
  1022  	args := s.createArgsForVersion(c, admin, jujuversion.Current.String())
  1023  	_, err := s.modelmanager.CreateModel(args)
  1024  	c.Assert(err, jc.ErrorIsNil)
  1025  }
  1026  
  1027  func (s *modelManagerStateSuite) TestCreateModelBadAgentVersion(c *gc.C) {
  1028  	err := s.BackingState.SetModelAgentVersion(coretesting.FakeVersionNumber, false)
  1029  	c.Assert(err, jc.ErrorIsNil)
  1030  
  1031  	admin := s.AdminUserTag(c)
  1032  	s.setAPIUser(c, admin)
  1033  
  1034  	bigger := coretesting.FakeVersionNumber
  1035  	bigger.Minor += 1
  1036  
  1037  	smaller := coretesting.FakeVersionNumber
  1038  	smaller.Minor -= 1
  1039  
  1040  	for i, test := range []struct {
  1041  		value    interface{}
  1042  		errMatch string
  1043  	}{
  1044  		{
  1045  			value:    42,
  1046  			errMatch: `failed to create config: agent-version must be a string but has type 'int'`,
  1047  		}, {
  1048  			value:    "not a number",
  1049  			errMatch: `failed to create config: invalid version \"not a number\"`,
  1050  		}, {
  1051  			value:    bigger.String(),
  1052  			errMatch: "failed to create config: agent-version .* cannot be greater than the controller .*",
  1053  		}, {
  1054  			value:    smaller.String(),
  1055  			errMatch: "failed to create config: no agent binaries found for version .*",
  1056  		},
  1057  	} {
  1058  		c.Logf("test %d", i)
  1059  		args := s.createArgsForVersion(c, admin, test.value)
  1060  		_, err := s.modelmanager.CreateModel(args)
  1061  		c.Check(err, gc.ErrorMatches, test.errMatch)
  1062  	}
  1063  }
  1064  
  1065  func (s *modelManagerStateSuite) checkModelMatches(c *gc.C, model params.Model, expected *state.Model) {
  1066  	c.Check(model.Name, gc.Equals, expected.Name())
  1067  	c.Check(model.UUID, gc.Equals, expected.UUID())
  1068  	c.Check(model.OwnerTag, gc.Equals, expected.Owner().String())
  1069  }
  1070  
  1071  func (s *modelManagerStateSuite) TestListModelsAdminSelf(c *gc.C) {
  1072  	user := s.AdminUserTag(c)
  1073  	s.setAPIUser(c, user)
  1074  	result, err := s.modelmanager.ListModels(params.Entity{Tag: user.String()})
  1075  	c.Assert(err, jc.ErrorIsNil)
  1076  	c.Assert(result.UserModels, gc.HasLen, 1)
  1077  	expected, err := s.State.Model()
  1078  	c.Assert(err, jc.ErrorIsNil)
  1079  	s.checkModelMatches(c, result.UserModels[0].Model, expected)
  1080  }
  1081  
  1082  func (s *modelManagerStateSuite) TestListModelsAdminListsOther(c *gc.C) {
  1083  	user := s.AdminUserTag(c)
  1084  	s.setAPIUser(c, user)
  1085  	other := names.NewUserTag("admin")
  1086  	result, err := s.modelmanager.ListModels(params.Entity{Tag: other.String()})
  1087  	c.Assert(err, jc.ErrorIsNil)
  1088  	c.Assert(result.UserModels, gc.HasLen, 1)
  1089  }
  1090  
  1091  func (s *modelManagerStateSuite) TestListModelsDenied(c *gc.C) {
  1092  	user := names.NewUserTag("external@remote")
  1093  	s.setAPIUser(c, user)
  1094  	other := names.NewUserTag("other@remote")
  1095  	_, err := s.modelmanager.ListModels(params.Entity{Tag: other.String()})
  1096  	c.Assert(err, gc.ErrorMatches, "permission denied")
  1097  }
  1098  
  1099  func (s *modelManagerStateSuite) TestAdminModelManager(c *gc.C) {
  1100  	user := s.AdminUserTag(c)
  1101  	s.setAPIUser(c, user)
  1102  	c.Assert(modelmanager.AuthCheck(c, s.modelmanager, user), jc.IsTrue)
  1103  }
  1104  
  1105  func (s *modelManagerStateSuite) TestNonAdminModelManager(c *gc.C) {
  1106  	user := names.NewUserTag("external@remote")
  1107  	s.setAPIUser(c, user)
  1108  	c.Assert(modelmanager.AuthCheck(c, s.modelmanager, user), jc.IsFalse)
  1109  }
  1110  
  1111  func (s *modelManagerStateSuite) TestDestroyOwnModel(c *gc.C) {
  1112  	// TODO(perrito666) this test is not valid until we have
  1113  	// proper controller permission since the only users that
  1114  	// can create models are controller admins.
  1115  	owner := names.NewUserTag("admin")
  1116  	s.setAPIUser(c, owner)
  1117  	m, err := s.modelmanager.CreateModel(createArgs(owner))
  1118  	c.Assert(err, jc.ErrorIsNil)
  1119  
  1120  	st, err := s.StatePool.Get(m.UUID)
  1121  	c.Assert(err, jc.ErrorIsNil)
  1122  	defer st.Release()
  1123  	model, err := st.Model()
  1124  	c.Assert(err, jc.ErrorIsNil)
  1125  
  1126  	s.modelmanager, err = modelmanager.NewModelManagerAPI(
  1127  		common.NewModelManagerBackend(model, s.StatePool),
  1128  		common.NewModelManagerBackend(s.Model, s.StatePool),
  1129  		nil, nil, s.authoriser,
  1130  		s.Model,
  1131  		s.callContext,
  1132  	)
  1133  	c.Assert(err, jc.ErrorIsNil)
  1134  
  1135  	results, err := s.modelmanager.DestroyModels(params.DestroyModelsParams{
  1136  		Models: []params.DestroyModelParams{{
  1137  			ModelTag: "model-" + m.UUID,
  1138  		}},
  1139  	})
  1140  	c.Assert(err, jc.ErrorIsNil)
  1141  	c.Assert(results.Results, gc.HasLen, 1)
  1142  	c.Assert(results.Results[0].Error, gc.IsNil)
  1143  
  1144  	model, err = st.Model()
  1145  	c.Assert(err, jc.ErrorIsNil)
  1146  	c.Assert(model.Life(), gc.Not(gc.Equals), state.Alive)
  1147  }
  1148  
  1149  func (s *modelManagerStateSuite) TestAdminDestroysOtherModel(c *gc.C) {
  1150  	// TODO(perrito666) Both users are admins in this case, this tesst is of dubious
  1151  	// usefulness until proper controller permissions are in place.
  1152  	owner := names.NewUserTag("admin")
  1153  	s.setAPIUser(c, owner)
  1154  	m, err := s.modelmanager.CreateModel(createArgs(owner))
  1155  	c.Assert(err, jc.ErrorIsNil)
  1156  
  1157  	st, err := s.StatePool.Get(m.UUID)
  1158  	c.Assert(err, jc.ErrorIsNil)
  1159  	defer st.Release()
  1160  	model, err := st.Model()
  1161  	c.Assert(err, jc.ErrorIsNil)
  1162  
  1163  	s.authoriser.Tag = s.AdminUserTag(c)
  1164  	s.modelmanager, err = modelmanager.NewModelManagerAPI(
  1165  		common.NewModelManagerBackend(model, s.StatePool),
  1166  		common.NewModelManagerBackend(s.Model, s.StatePool),
  1167  		nil, nil, s.authoriser,
  1168  		s.Model,
  1169  		s.callContext,
  1170  	)
  1171  	c.Assert(err, jc.ErrorIsNil)
  1172  
  1173  	results, err := s.modelmanager.DestroyModels(params.DestroyModelsParams{
  1174  		Models: []params.DestroyModelParams{{
  1175  			ModelTag: "model-" + m.UUID,
  1176  		}},
  1177  	})
  1178  	c.Assert(err, jc.ErrorIsNil)
  1179  	c.Assert(results.Results, gc.HasLen, 1)
  1180  	c.Assert(results.Results[0].Error, gc.IsNil)
  1181  
  1182  	s.authoriser.Tag = owner
  1183  	model, err = st.Model()
  1184  	c.Assert(err, jc.ErrorIsNil)
  1185  	c.Assert(model.Life(), gc.Not(gc.Equals), state.Alive)
  1186  }
  1187  
  1188  func (s *modelManagerStateSuite) TestDestroyModelErrors(c *gc.C) {
  1189  	owner := names.NewUserTag("admin")
  1190  	s.setAPIUser(c, owner)
  1191  	m, err := s.modelmanager.CreateModel(createArgs(owner))
  1192  	c.Assert(err, jc.ErrorIsNil)
  1193  
  1194  	st, err := s.StatePool.Get(m.UUID)
  1195  	c.Assert(err, jc.ErrorIsNil)
  1196  	defer st.Release()
  1197  	model, err := st.Model()
  1198  	c.Assert(err, jc.ErrorIsNil)
  1199  
  1200  	s.modelmanager, err = modelmanager.NewModelManagerAPI(
  1201  		common.NewModelManagerBackend(model, s.StatePool),
  1202  		common.NewModelManagerBackend(s.Model, s.StatePool),
  1203  		nil, nil, s.authoriser, s.Model,
  1204  		s.callContext,
  1205  	)
  1206  	c.Assert(err, jc.ErrorIsNil)
  1207  
  1208  	user := names.NewUserTag("other@remote")
  1209  	s.setAPIUser(c, user)
  1210  
  1211  	results, err := s.modelmanager.DestroyModels(params.DestroyModelsParams{
  1212  		Models: []params.DestroyModelParams{
  1213  			{ModelTag: "model-" + m.UUID},
  1214  			{ModelTag: "model-9f484882-2f18-4fd2-967d-db9663db7bea"},
  1215  			{ModelTag: "machine-42"},
  1216  		},
  1217  	})
  1218  	c.Assert(err, jc.ErrorIsNil)
  1219  	c.Assert(results.Results, jc.DeepEquals, []params.ErrorResult{{
  1220  		// we don't have admin access to the model
  1221  		&params.Error{
  1222  			Message: "permission denied",
  1223  			Code:    params.CodeUnauthorized,
  1224  		},
  1225  	}, {
  1226  		&params.Error{
  1227  			Message: `model "9f484882-2f18-4fd2-967d-db9663db7bea" not found`,
  1228  			Code:    params.CodeNotFound,
  1229  		},
  1230  	}, {
  1231  		&params.Error{
  1232  			Message: `"machine-42" is not a valid model tag`,
  1233  		},
  1234  	}})
  1235  
  1236  	s.setAPIUser(c, owner)
  1237  	model, err = st.Model()
  1238  	c.Assert(err, jc.ErrorIsNil)
  1239  	c.Assert(model.Life(), gc.Equals, state.Alive)
  1240  }
  1241  
  1242  func (s *modelManagerStateSuite) modifyAccess(c *gc.C, user names.UserTag, action params.ModelAction, access params.UserAccessPermission, model names.ModelTag) error {
  1243  	args := params.ModifyModelAccessRequest{
  1244  		Changes: []params.ModifyModelAccess{{
  1245  			UserTag:  user.String(),
  1246  			Action:   action,
  1247  			Access:   access,
  1248  			ModelTag: model.String(),
  1249  		}}}
  1250  
  1251  	result, err := s.modelmanager.ModifyModelAccess(args)
  1252  	if err != nil {
  1253  		return err
  1254  	}
  1255  	return result.OneError()
  1256  }
  1257  
  1258  func (s *modelManagerStateSuite) grant(c *gc.C, user names.UserTag, access params.UserAccessPermission, model names.ModelTag) error {
  1259  	return s.modifyAccess(c, user, params.GrantModelAccess, access, model)
  1260  }
  1261  
  1262  func (s *modelManagerStateSuite) revoke(c *gc.C, user names.UserTag, access params.UserAccessPermission, model names.ModelTag) error {
  1263  	return s.modifyAccess(c, user, params.RevokeModelAccess, access, model)
  1264  }
  1265  
  1266  func (s *modelManagerStateSuite) TestGrantMissingUserFails(c *gc.C) {
  1267  	s.setAPIUser(c, s.AdminUserTag(c))
  1268  	st := s.Factory.MakeModel(c, nil)
  1269  	defer st.Close()
  1270  
  1271  	m, err := st.Model()
  1272  	c.Assert(err, jc.ErrorIsNil)
  1273  
  1274  	user := names.NewLocalUserTag("foobar")
  1275  	err = s.grant(c, user, params.ModelReadAccess, m.ModelTag())
  1276  	expectedErr := `could not grant model access: user "foobar" does not exist locally: user "foobar" not found`
  1277  	c.Assert(err, gc.ErrorMatches, expectedErr)
  1278  }
  1279  
  1280  func (s *modelManagerStateSuite) TestGrantMissingModelFails(c *gc.C) {
  1281  	s.setAPIUser(c, s.AdminUserTag(c))
  1282  	user := s.Factory.MakeModelUser(c, nil)
  1283  	model := names.NewModelTag("17e4bd2d-3e08-4f3d-b945-087be7ebdce4")
  1284  	err := s.grant(c, user.UserTag, params.ModelReadAccess, model)
  1285  	expectedErr := `.*model "17e4bd2d-3e08-4f3d-b945-087be7ebdce4" not found`
  1286  	c.Assert(err, gc.ErrorMatches, expectedErr)
  1287  }
  1288  
  1289  func (s *modelManagerStateSuite) TestRevokeAdminLeavesReadAccess(c *gc.C) {
  1290  	s.setAPIUser(c, s.AdminUserTag(c))
  1291  	user := s.Factory.MakeModelUser(c, &factory.ModelUserParams{Access: permission.WriteAccess})
  1292  
  1293  	err := s.revoke(c, user.UserTag, params.ModelWriteAccess, user.Object.(names.ModelTag))
  1294  	c.Assert(err, gc.IsNil)
  1295  
  1296  	modelUser, err := s.State.UserAccess(user.UserTag, user.Object)
  1297  	c.Assert(err, jc.ErrorIsNil)
  1298  	c.Assert(modelUser.Access, gc.Equals, permission.ReadAccess)
  1299  }
  1300  
  1301  func (s *modelManagerStateSuite) TestRevokeReadRemovesModelUser(c *gc.C) {
  1302  	s.setAPIUser(c, s.AdminUserTag(c))
  1303  	user := s.Factory.MakeModelUser(c, nil)
  1304  
  1305  	err := s.revoke(c, user.UserTag, params.ModelReadAccess, user.Object.(names.ModelTag))
  1306  	c.Assert(err, gc.IsNil)
  1307  
  1308  	_, err = s.State.UserAccess(user.UserTag, user.Object)
  1309  	c.Assert(errors.IsNotFound(err), jc.IsTrue)
  1310  }
  1311  
  1312  func (s *modelManagerStateSuite) TestRevokeModelMissingUser(c *gc.C) {
  1313  	s.setAPIUser(c, s.AdminUserTag(c))
  1314  	st := s.Factory.MakeModel(c, nil)
  1315  	defer st.Close()
  1316  
  1317  	m, err := st.Model()
  1318  	c.Assert(err, jc.ErrorIsNil)
  1319  
  1320  	user := names.NewUserTag("bob")
  1321  	err = s.revoke(c, user, params.ModelReadAccess, m.ModelTag())
  1322  	c.Assert(err, gc.ErrorMatches, `could not revoke model access: model user "bob" does not exist`)
  1323  
  1324  	_, err = st.UserAccess(user, m.ModelTag())
  1325  	c.Assert(errors.IsNotFound(err), jc.IsTrue)
  1326  }
  1327  
  1328  func (s *modelManagerStateSuite) TestGrantOnlyGreaterAccess(c *gc.C) {
  1329  	user := s.Factory.MakeUser(c, &factory.UserParams{Name: "foobar", NoModelUser: true})
  1330  	s.setAPIUser(c, s.AdminUserTag(c))
  1331  	st := s.Factory.MakeModel(c, nil)
  1332  	defer st.Close()
  1333  
  1334  	m, err := st.Model()
  1335  	c.Assert(err, jc.ErrorIsNil)
  1336  
  1337  	err = s.grant(c, user.UserTag(), params.ModelReadAccess, m.ModelTag())
  1338  	c.Assert(err, jc.ErrorIsNil)
  1339  
  1340  	err = s.grant(c, user.UserTag(), params.ModelReadAccess, m.ModelTag())
  1341  	c.Assert(err, gc.ErrorMatches, `user already has "read" access or greater`)
  1342  }
  1343  
  1344  func (s *modelManagerStateSuite) assertNewUser(c *gc.C, modelUser permission.UserAccess, userTag, creatorTag names.UserTag) {
  1345  	c.Assert(modelUser.UserTag, gc.Equals, userTag)
  1346  	c.Assert(modelUser.CreatedBy, gc.Equals, creatorTag)
  1347  	_, err := s.Model.LastModelConnection(modelUser.UserTag)
  1348  	c.Assert(err, jc.Satisfies, state.IsNeverConnectedError)
  1349  }
  1350  
  1351  func (s *modelManagerStateSuite) assertModelAccess(c *gc.C, st *state.State) {
  1352  	m, err := st.Model()
  1353  	c.Assert(err, jc.ErrorIsNil)
  1354  
  1355  	result, err := s.modelmanager.ModelInfo(params.Entities{Entities: []params.Entity{{Tag: m.ModelTag().String()}}})
  1356  	c.Assert(err, jc.ErrorIsNil)
  1357  	c.Assert(result.Results, gc.HasLen, 1)
  1358  	c.Assert(result.Results[0].Error, gc.IsNil)
  1359  }
  1360  
  1361  func (s *modelManagerStateSuite) TestGrantModelAddLocalUser(c *gc.C) {
  1362  	user := s.Factory.MakeUser(c, &factory.UserParams{Name: "foobar", NoModelUser: true})
  1363  	apiUser := s.AdminUserTag(c)
  1364  	s.setAPIUser(c, apiUser)
  1365  	st := s.Factory.MakeModel(c, nil)
  1366  	defer st.Close()
  1367  
  1368  	m, err := st.Model()
  1369  	c.Assert(err, jc.ErrorIsNil)
  1370  
  1371  	err = s.grant(c, user.UserTag(), params.ModelReadAccess, m.ModelTag())
  1372  	c.Assert(err, jc.ErrorIsNil)
  1373  
  1374  	modelUser, err := st.UserAccess(user.UserTag(), m.ModelTag())
  1375  	c.Assert(err, jc.ErrorIsNil)
  1376  	s.assertNewUser(c, modelUser, user.UserTag(), apiUser)
  1377  	c.Assert(modelUser.Access, gc.Equals, permission.ReadAccess)
  1378  	s.setAPIUser(c, user.UserTag())
  1379  	s.assertModelAccess(c, st)
  1380  }
  1381  
  1382  func (s *modelManagerStateSuite) TestGrantModelAddRemoteUser(c *gc.C) {
  1383  	userTag := names.NewUserTag("foobar@ubuntuone")
  1384  	apiUser := s.AdminUserTag(c)
  1385  	s.setAPIUser(c, apiUser)
  1386  	st := s.Factory.MakeModel(c, nil)
  1387  	defer st.Close()
  1388  
  1389  	m, err := st.Model()
  1390  	c.Assert(err, jc.ErrorIsNil)
  1391  
  1392  	err = s.grant(c, userTag, params.ModelReadAccess, m.ModelTag())
  1393  	c.Assert(err, jc.ErrorIsNil)
  1394  
  1395  	modelUser, err := st.UserAccess(userTag, m.ModelTag())
  1396  	c.Assert(err, jc.ErrorIsNil)
  1397  
  1398  	s.assertNewUser(c, modelUser, userTag, apiUser)
  1399  	c.Assert(modelUser.Access, gc.Equals, permission.ReadAccess)
  1400  	s.setAPIUser(c, userTag)
  1401  	s.assertModelAccess(c, st)
  1402  }
  1403  
  1404  func (s *modelManagerStateSuite) TestGrantModelAddAdminUser(c *gc.C) {
  1405  	user := s.Factory.MakeUser(c, &factory.UserParams{Name: "foobar", NoModelUser: true})
  1406  	apiUser := s.AdminUserTag(c)
  1407  	s.setAPIUser(c, apiUser)
  1408  	st := s.Factory.MakeModel(c, nil)
  1409  	defer st.Close()
  1410  
  1411  	m, err := st.Model()
  1412  	c.Assert(err, jc.ErrorIsNil)
  1413  
  1414  	err = s.grant(c, user.UserTag(), params.ModelWriteAccess, m.ModelTag())
  1415  
  1416  	modelUser, err := st.UserAccess(user.UserTag(), m.ModelTag())
  1417  	c.Assert(err, jc.ErrorIsNil)
  1418  	s.assertNewUser(c, modelUser, user.UserTag(), apiUser)
  1419  	c.Assert(modelUser.Access, gc.Equals, permission.WriteAccess)
  1420  	s.setAPIUser(c, user.UserTag())
  1421  	s.assertModelAccess(c, st)
  1422  }
  1423  
  1424  func (s *modelManagerStateSuite) TestGrantModelIncreaseAccess(c *gc.C) {
  1425  	s.setAPIUser(c, s.AdminUserTag(c))
  1426  	st := s.Factory.MakeModel(c, nil)
  1427  	defer st.Close()
  1428  	stFactory := factory.NewFactory(st, s.StatePool)
  1429  	user := stFactory.MakeModelUser(c, &factory.ModelUserParams{Access: permission.ReadAccess})
  1430  
  1431  	m, err := st.Model()
  1432  	c.Assert(err, jc.ErrorIsNil)
  1433  
  1434  	err = s.grant(c, user.UserTag, params.ModelWriteAccess, m.ModelTag())
  1435  	c.Assert(err, jc.ErrorIsNil)
  1436  
  1437  	modelUser, err := st.UserAccess(user.UserTag, m.ModelTag())
  1438  	c.Assert(err, jc.ErrorIsNil)
  1439  	c.Assert(modelUser.Access, gc.Equals, permission.WriteAccess)
  1440  }
  1441  
  1442  func (s *modelManagerStateSuite) TestGrantToModelNoAccess(c *gc.C) {
  1443  	s.setAPIUser(c, s.AdminUserTag(c))
  1444  	st := s.Factory.MakeModel(c, nil)
  1445  	defer st.Close()
  1446  
  1447  	m, err := st.Model()
  1448  	c.Assert(err, jc.ErrorIsNil)
  1449  
  1450  	apiUser := names.NewUserTag("bob@remote")
  1451  	s.setAPIUser(c, apiUser)
  1452  
  1453  	other := names.NewUserTag("other@remote")
  1454  	err = s.grant(c, other, params.ModelReadAccess, m.ModelTag())
  1455  	c.Assert(err, gc.ErrorMatches, "permission denied")
  1456  }
  1457  
  1458  func (s *modelManagerStateSuite) TestGrantToModelReadAccess(c *gc.C) {
  1459  	s.setAPIUser(c, s.AdminUserTag(c))
  1460  	st := s.Factory.MakeModel(c, nil)
  1461  	defer st.Close()
  1462  
  1463  	apiUser := names.NewUserTag("bob@remote")
  1464  	s.setAPIUser(c, apiUser)
  1465  
  1466  	stFactory := factory.NewFactory(st, s.StatePool)
  1467  	stFactory.MakeModelUser(c, &factory.ModelUserParams{
  1468  		User: apiUser.Id(), Access: permission.ReadAccess})
  1469  
  1470  	other := names.NewUserTag("other@remote")
  1471  	m, err := st.Model()
  1472  	c.Assert(err, jc.ErrorIsNil)
  1473  
  1474  	err = s.grant(c, other, params.ModelReadAccess, m.ModelTag())
  1475  	c.Assert(err, gc.ErrorMatches, "permission denied")
  1476  }
  1477  
  1478  func (s *modelManagerStateSuite) TestGrantToModelWriteAccess(c *gc.C) {
  1479  	s.setAPIUser(c, s.AdminUserTag(c))
  1480  	st := s.Factory.MakeModel(c, nil)
  1481  	defer st.Close()
  1482  
  1483  	apiUser := names.NewUserTag("admin@remote")
  1484  	s.setAPIUser(c, apiUser)
  1485  	stFactory := factory.NewFactory(st, s.StatePool)
  1486  	stFactory.MakeModelUser(c, &factory.ModelUserParams{
  1487  		User: apiUser.Id(), Access: permission.AdminAccess})
  1488  
  1489  	other := names.NewUserTag("other@remote")
  1490  	m, err := st.Model()
  1491  	c.Assert(err, jc.ErrorIsNil)
  1492  
  1493  	err = s.grant(c, other, params.ModelReadAccess, m.ModelTag())
  1494  	c.Assert(err, jc.ErrorIsNil)
  1495  
  1496  	modelUser, err := st.UserAccess(other, m.ModelTag())
  1497  	c.Assert(err, jc.ErrorIsNil)
  1498  	s.assertNewUser(c, modelUser, other, apiUser)
  1499  	c.Assert(modelUser.Access, gc.Equals, permission.ReadAccess)
  1500  }
  1501  
  1502  func (s *modelManagerStateSuite) TestGrantModelInvalidUserTag(c *gc.C) {
  1503  	s.setAPIUser(c, s.AdminUserTag(c))
  1504  	for _, testParam := range []struct {
  1505  		tag      string
  1506  		validTag bool
  1507  	}{{
  1508  		tag:      "unit-foo/0",
  1509  		validTag: true,
  1510  	}, {
  1511  		tag:      "application-foo",
  1512  		validTag: true,
  1513  	}, {
  1514  		tag:      "relation-wordpress:db mysql:db",
  1515  		validTag: true,
  1516  	}, {
  1517  		tag:      "machine-0",
  1518  		validTag: true,
  1519  	}, {
  1520  		tag:      "user",
  1521  		validTag: false,
  1522  	}, {
  1523  		tag:      "user-Mua^h^h^h^arh",
  1524  		validTag: true,
  1525  	}, {
  1526  		tag:      "user@",
  1527  		validTag: false,
  1528  	}, {
  1529  		tag:      "user@ubuntuone",
  1530  		validTag: false,
  1531  	}, {
  1532  		tag:      "user@ubuntuone",
  1533  		validTag: false,
  1534  	}, {
  1535  		tag:      "@ubuntuone",
  1536  		validTag: false,
  1537  	}, {
  1538  		tag:      "in^valid.",
  1539  		validTag: false,
  1540  	}, {
  1541  		tag:      "",
  1542  		validTag: false,
  1543  	},
  1544  	} {
  1545  		var expectedErr string
  1546  		errPart := `could not modify model access: "` + regexp.QuoteMeta(testParam.tag) + `" is not a valid `
  1547  
  1548  		if testParam.validTag {
  1549  			// The string is a valid tag, but not a user tag.
  1550  			expectedErr = errPart + `user tag`
  1551  		} else {
  1552  			// The string is not a valid tag of any kind.
  1553  			expectedErr = errPart + `tag`
  1554  		}
  1555  
  1556  		args := params.ModifyModelAccessRequest{
  1557  			Changes: []params.ModifyModelAccess{{
  1558  				ModelTag: "model-deadbeef-0bad-400d-8000-4b1d0d06f00d",
  1559  				UserTag:  testParam.tag,
  1560  				Action:   params.GrantModelAccess,
  1561  				Access:   params.ModelReadAccess,
  1562  			}}}
  1563  
  1564  		result, err := s.modelmanager.ModifyModelAccess(args)
  1565  		c.Assert(err, jc.ErrorIsNil)
  1566  		c.Assert(result.OneError(), gc.ErrorMatches, expectedErr)
  1567  	}
  1568  }
  1569  
  1570  func (s *modelManagerStateSuite) TestModifyModelAccessEmptyArgs(c *gc.C) {
  1571  	s.setAPIUser(c, s.AdminUserTag(c))
  1572  	args := params.ModifyModelAccessRequest{Changes: []params.ModifyModelAccess{{}}}
  1573  
  1574  	result, err := s.modelmanager.ModifyModelAccess(args)
  1575  	c.Assert(err, jc.ErrorIsNil)
  1576  	expectedErr := `could not modify model access: "" model access not valid`
  1577  	c.Assert(result.OneError(), gc.ErrorMatches, expectedErr)
  1578  }
  1579  
  1580  func (s *modelManagerStateSuite) TestModifyModelAccessInvalidAction(c *gc.C) {
  1581  	s.setAPIUser(c, s.AdminUserTag(c))
  1582  	var dance params.ModelAction = "dance"
  1583  	args := params.ModifyModelAccessRequest{
  1584  		Changes: []params.ModifyModelAccess{{
  1585  			UserTag:  "user-user",
  1586  			Action:   dance,
  1587  			Access:   params.ModelReadAccess,
  1588  			ModelTag: s.Model.ModelTag().String(),
  1589  		}}}
  1590  
  1591  	result, err := s.modelmanager.ModifyModelAccess(args)
  1592  	c.Assert(err, jc.ErrorIsNil)
  1593  	expectedErr := `unknown action "dance"`
  1594  	c.Assert(result.OneError(), gc.ErrorMatches, expectedErr)
  1595  }
  1596  
  1597  func (s *modelManagerSuite) TestModelStatusV2(c *gc.C) {
  1598  	api := &modelmanager.ModelManagerAPIV2{
  1599  		&modelmanager.ModelManagerAPIV3{
  1600  			&modelmanager.ModelManagerAPIV4{
  1601  				s.api,
  1602  			},
  1603  		},
  1604  	}
  1605  	// Check that we err out immediately if a model errs.
  1606  	results, err := api.ModelStatus(params.Entities{[]params.Entity{{
  1607  		Tag: "bad-tag",
  1608  	}, {
  1609  		Tag: s.st.ModelTag().String(),
  1610  	}}})
  1611  	c.Assert(err, gc.ErrorMatches, `"bad-tag" is not a valid tag`)
  1612  	c.Assert(results, gc.DeepEquals, params.ModelStatusResults{Results: make([]params.ModelStatus, 2)})
  1613  
  1614  	// Check that we err out if a model errs even if some firsts in collection pass.
  1615  	results, err = api.ModelStatus(params.Entities{[]params.Entity{{
  1616  		Tag: s.st.ModelTag().String(),
  1617  	}, {
  1618  		Tag: "bad-tag",
  1619  	}}})
  1620  	c.Assert(err, gc.ErrorMatches, `"bad-tag" is not a valid tag`)
  1621  	c.Assert(results, gc.DeepEquals, params.ModelStatusResults{Results: make([]params.ModelStatus, 2)})
  1622  
  1623  	// Check that we return successfully if no errors.
  1624  	results, err = api.ModelStatus(params.Entities{[]params.Entity{{
  1625  		Tag: s.st.ModelTag().String(),
  1626  	}}})
  1627  	c.Assert(err, jc.ErrorIsNil)
  1628  	c.Assert(results.Results, gc.HasLen, 1)
  1629  }
  1630  
  1631  func (s *modelManagerSuite) TestModelStatusV3(c *gc.C) {
  1632  	api := &modelmanager.ModelManagerAPIV3{
  1633  		&modelmanager.ModelManagerAPIV4{
  1634  			s.api,
  1635  		},
  1636  	}
  1637  
  1638  	// Check that we err out immediately if a model errs.
  1639  	results, err := api.ModelStatus(params.Entities{[]params.Entity{{
  1640  		Tag: "bad-tag",
  1641  	}, {
  1642  		Tag: s.st.ModelTag().String(),
  1643  	}}})
  1644  	c.Assert(err, gc.ErrorMatches, `"bad-tag" is not a valid tag`)
  1645  	c.Assert(results, gc.DeepEquals, params.ModelStatusResults{Results: make([]params.ModelStatus, 2)})
  1646  
  1647  	// Check that we err out if a model errs even if some firsts in collection pass.
  1648  	results, err = api.ModelStatus(params.Entities{[]params.Entity{{
  1649  		Tag: s.st.ModelTag().String(),
  1650  	}, {
  1651  		Tag: "bad-tag",
  1652  	}}})
  1653  	c.Assert(err, gc.ErrorMatches, `"bad-tag" is not a valid tag`)
  1654  	c.Assert(results, gc.DeepEquals, params.ModelStatusResults{Results: make([]params.ModelStatus, 2)})
  1655  
  1656  	// Check that we return successfully if no errors.
  1657  	results, err = api.ModelStatus(params.Entities{[]params.Entity{{
  1658  		Tag: s.st.ModelTag().String(),
  1659  	}}})
  1660  	c.Assert(err, jc.ErrorIsNil)
  1661  	c.Assert(results.Results, gc.HasLen, 1)
  1662  }
  1663  
  1664  func (s *modelManagerSuite) TestModelStatus(c *gc.C) {
  1665  	// Check that we don't err out immediately if a model errs.
  1666  	results, err := s.api.ModelStatus(params.Entities{[]params.Entity{{
  1667  		Tag: "bad-tag",
  1668  	}, {
  1669  		Tag: s.st.ModelTag().String(),
  1670  	}}})
  1671  	c.Assert(err, jc.ErrorIsNil)
  1672  	c.Assert(results.Results, gc.HasLen, 2)
  1673  	c.Assert(results.Results[0].Error, gc.ErrorMatches, `"bad-tag" is not a valid tag`)
  1674  
  1675  	// Check that we don't err out if a model errs even if some firsts in collection pass.
  1676  	results, err = s.api.ModelStatus(params.Entities{[]params.Entity{{
  1677  		Tag: s.st.ModelTag().String(),
  1678  	}, {
  1679  		Tag: "bad-tag",
  1680  	}}})
  1681  	c.Assert(err, jc.ErrorIsNil)
  1682  	c.Assert(results.Results, gc.HasLen, 2)
  1683  	c.Assert(results.Results[1].Error, gc.ErrorMatches, `"bad-tag" is not a valid tag`)
  1684  
  1685  	// Check that we return successfully if no errors.
  1686  	results, err = s.api.ModelStatus(params.Entities{[]params.Entity{{
  1687  		Tag: s.st.ModelTag().String(),
  1688  	}}})
  1689  	c.Assert(err, jc.ErrorIsNil)
  1690  	c.Assert(results.Results, gc.HasLen, 1)
  1691  }
  1692  
  1693  func (s *modelManagerSuite) TestChangeModelCredential(c *gc.C) {
  1694  	s.st.model.setCloudCredentialF = func(tag names.CloudCredentialTag) (bool, error) { return true, nil }
  1695  	credentialTag := names.NewCloudCredentialTag("foo/bob/bar").String()
  1696  	results, err := s.api.ChangeModelCredential(params.ChangeModelCredentialsParams{
  1697  		[]params.ChangeModelCredentialParams{
  1698  			{ModelTag: s.st.ModelTag().String(), CloudCredentialTag: credentialTag},
  1699  		},
  1700  	})
  1701  	c.Assert(err, jc.ErrorIsNil)
  1702  	c.Assert(results.Results, gc.HasLen, 1)
  1703  	c.Assert(results.Results[0].Error, gc.IsNil)
  1704  }
  1705  
  1706  func (s *modelManagerSuite) TestChangeModelCredentialBulkUninterrupted(c *gc.C) {
  1707  	s.st.model.setCloudCredentialF = func(tag names.CloudCredentialTag) (bool, error) { return true, nil }
  1708  	credentialTag := names.NewCloudCredentialTag("foo/bob/bar").String()
  1709  	// Check that we don't err out immediately if a model errs.
  1710  	results, err := s.api.ChangeModelCredential(params.ChangeModelCredentialsParams{
  1711  		[]params.ChangeModelCredentialParams{
  1712  			{ModelTag: "bad-model-tag"},
  1713  			{ModelTag: s.st.ModelTag().String(), CloudCredentialTag: credentialTag},
  1714  		},
  1715  	})
  1716  
  1717  	c.Assert(err, jc.ErrorIsNil)
  1718  	c.Assert(results.Results, gc.HasLen, 2)
  1719  	c.Assert(results.Results[0].Error, gc.ErrorMatches, `"bad-model-tag" is not a valid tag`)
  1720  	c.Assert(results.Results[1].Error, gc.IsNil)
  1721  
  1722  	// Check that we don't err out if a model errs even if some firsts in collection pass.
  1723  	results, err = s.api.ChangeModelCredential(params.ChangeModelCredentialsParams{
  1724  		[]params.ChangeModelCredentialParams{
  1725  			{ModelTag: s.st.ModelTag().String()},
  1726  			{ModelTag: s.st.ModelTag().String(), CloudCredentialTag: "bad-credential-tag"},
  1727  		},
  1728  	})
  1729  	c.Assert(err, jc.ErrorIsNil)
  1730  	c.Assert(results.Results, gc.HasLen, 2)
  1731  	c.Assert(results.Results[1].Error, gc.ErrorMatches, `"bad-credential-tag" is not a valid tag`)
  1732  }
  1733  
  1734  func (s *modelManagerSuite) TestChangeModelCredentialUnauthorisedUser(c *gc.C) {
  1735  	credentialTag := names.NewCloudCredentialTag("foo/bob/bar").String()
  1736  	apiUser := names.NewUserTag("bob@remote")
  1737  	s.setAPIUser(c, apiUser)
  1738  
  1739  	results, err := s.api.ChangeModelCredential(params.ChangeModelCredentialsParams{
  1740  		[]params.ChangeModelCredentialParams{
  1741  			{ModelTag: s.st.ModelTag().String(), CloudCredentialTag: credentialTag},
  1742  		},
  1743  	})
  1744  
  1745  	c.Assert(err, jc.ErrorIsNil)
  1746  	c.Assert(results.Results[0].Error, gc.ErrorMatches, `permission denied`)
  1747  }
  1748  
  1749  func (s *modelManagerSuite) TestChangeModelCredentialGetModelFail(c *gc.C) {
  1750  	s.st.SetErrors(errors.New("getting model"))
  1751  	credentialTag := names.NewCloudCredentialTag("foo/bob/bar").String()
  1752  
  1753  	results, err := s.api.ChangeModelCredential(params.ChangeModelCredentialsParams{
  1754  		[]params.ChangeModelCredentialParams{
  1755  			{ModelTag: s.st.ModelTag().String(), CloudCredentialTag: credentialTag},
  1756  		},
  1757  	})
  1758  
  1759  	c.Assert(err, jc.ErrorIsNil)
  1760  	c.Assert(results.Results[0].Error, gc.ErrorMatches, `getting model`)
  1761  	s.st.CheckCallNames(c, "ControllerTag", "ModelUUID", "ModelTag", "GetBlockForType", "ControllerTag", "GetModel")
  1762  }
  1763  
  1764  func (s *modelManagerSuite) TestChangeModelCredentialNotUpdated(c *gc.C) {
  1765  	s.st.model.setCloudCredentialF = func(tag names.CloudCredentialTag) (bool, error) { return false, nil }
  1766  	credentialTag := names.NewCloudCredentialTag("foo/bob/bar").String()
  1767  	results, err := s.api.ChangeModelCredential(params.ChangeModelCredentialsParams{
  1768  		[]params.ChangeModelCredentialParams{
  1769  			{ModelTag: s.st.ModelTag().String(), CloudCredentialTag: credentialTag},
  1770  		},
  1771  	})
  1772  	c.Assert(err, jc.ErrorIsNil)
  1773  	c.Assert(results.Results, gc.HasLen, 1)
  1774  	c.Assert(results.Results[0].Error, gc.ErrorMatches, `model deadbeef-0bad-400d-8000-4b1d0d06f00d already uses credential foo/bob/bar`)
  1775  }
  1776  
  1777  type fakeProvider struct {
  1778  	environs.CloudEnvironProvider
  1779  }
  1780  
  1781  func (*fakeProvider) Validate(cfg, old *config.Config) (*config.Config, error) {
  1782  	return cfg, nil
  1783  }
  1784  
  1785  func (*fakeProvider) PrepareForCreateEnvironment(controllerUUID string, cfg *config.Config) (*config.Config, error) {
  1786  	return cfg, nil
  1787  }
  1788  
  1789  func init() {
  1790  	environs.RegisterProvider("fake", &fakeProvider{})
  1791  }