github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/common/credentialcommon/modelcredential_test.go (about)

     1  // Copyright 2018 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package credentialcommon_test
     5  
     6  import (
     7  	stdcontext "context"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/names/v5"
    11  	"github.com/juju/testing"
    12  	jc "github.com/juju/testing/checkers"
    13  	gc "gopkg.in/check.v1"
    14  
    15  	"github.com/juju/juju/apiserver/common/credentialcommon"
    16  	apiservererrors "github.com/juju/juju/apiserver/errors"
    17  	"github.com/juju/juju/caas"
    18  	"github.com/juju/juju/cloud"
    19  	"github.com/juju/juju/core/instance"
    20  	"github.com/juju/juju/environs"
    21  	"github.com/juju/juju/environs/config"
    22  	"github.com/juju/juju/environs/context"
    23  	"github.com/juju/juju/environs/instances"
    24  	"github.com/juju/juju/rpc/params"
    25  	"github.com/juju/juju/state"
    26  	statetesting "github.com/juju/juju/state/testing"
    27  	jujuesting "github.com/juju/juju/testing"
    28  )
    29  
    30  var _ = gc.Suite(&CheckMachinesSuite{})
    31  var _ = gc.Suite(&ModelCredentialSuite{})
    32  
    33  type CheckMachinesSuite struct {
    34  	testing.IsolationSuite
    35  
    36  	provider    *mockProvider
    37  	instance    *mockInstance
    38  	callContext context.ProviderCallContext
    39  
    40  	backend *mockPersistedBackend
    41  	machine *mockMachine
    42  }
    43  
    44  func (s *CheckMachinesSuite) SetUpTest(c *gc.C) {
    45  	s.IsolationSuite.SetUpTest(c)
    46  	s.backend = createModelBackend()
    47  
    48  	// This is what the test gets from the state.
    49  	s.machine = createTestMachine("1", "wind-up")
    50  	s.backend.allMachinesFunc = func() ([]credentialcommon.Machine, error) {
    51  		return []credentialcommon.Machine{s.machine}, nil
    52  	}
    53  
    54  	// This is what the test gets from the cloud.
    55  	s.instance = &mockInstance{id: "wind-up"}
    56  	s.provider = &mockProvider{
    57  		Stub: &testing.Stub{},
    58  		allInstancesFunc: func(ctx context.ProviderCallContext) ([]instances.Instance, error) {
    59  			return []instances.Instance{s.instance}, nil
    60  		},
    61  	}
    62  	s.callContext = context.NewEmptyCloudCallContext()
    63  }
    64  
    65  func (s *CheckMachinesSuite) TestCheckMachinesSuccess(c *gc.C) {
    66  	results, err := credentialcommon.CheckMachineInstances(s.backend, false, []instances.Instance{s.instance})
    67  	c.Assert(err, jc.ErrorIsNil)
    68  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
    69  }
    70  
    71  func (s *CheckMachinesSuite) TestCheckMachinesInstancesMissing(c *gc.C) {
    72  	machine1 := createTestMachine("2", "birds")
    73  	s.backend.allMachinesFunc = func() ([]credentialcommon.Machine, error) {
    74  		return []credentialcommon.Machine{s.machine, machine1}, nil
    75  	}
    76  
    77  	results, err := credentialcommon.CheckMachineInstances(s.backend, false, []instances.Instance{s.instance})
    78  	c.Assert(err, jc.ErrorIsNil)
    79  
    80  	c.Assert(results.Results, gc.HasLen, 1)
    81  	c.Assert(results.Results[0].Error, gc.ErrorMatches, `couldn't find instance "birds" for machine 2`)
    82  }
    83  
    84  func (s *CheckMachinesSuite) TestCheckMachinesExtraInstances(c *gc.C) {
    85  	instance2 := &mockInstance{id: "analyse"}
    86  	results, err := credentialcommon.CheckMachineInstances(s.backend, false, []instances.Instance{s.instance, instance2})
    87  	c.Assert(err, jc.ErrorIsNil)
    88  	c.Assert(results.Results, gc.IsNil)
    89  }
    90  
    91  func (s *CheckMachinesSuite) TestCheckMachinesExtraInstancesWhenMigrating(c *gc.C) {
    92  	instance2 := &mockInstance{id: "analyse"}
    93  	results, err := credentialcommon.CheckMachineInstances(s.backend, true, []instances.Instance{s.instance, instance2})
    94  	c.Assert(err, jc.ErrorIsNil)
    95  
    96  	c.Assert(results.Results, gc.HasLen, 1)
    97  	c.Assert(results.Results[0].Error, gc.ErrorMatches, `no machine with instance "analyse"`)
    98  }
    99  
   100  func (s *CheckMachinesSuite) TestCheckMachinesErrorGettingMachines(c *gc.C) {
   101  	s.backend.allMachinesFunc = func() ([]credentialcommon.Machine, error) {
   102  		return nil, errors.New("boom")
   103  	}
   104  
   105  	results, err := credentialcommon.CheckMachineInstances(s.backend, false, nil)
   106  	c.Assert(err, gc.ErrorMatches, "boom")
   107  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   108  }
   109  
   110  func (s *CheckMachinesSuite) TestCheckMachinesHandlesContainers(c *gc.C) {
   111  	machine1 := createTestMachine("1", "")
   112  	machine1.container = true
   113  	s.backend.allMachinesFunc = func() ([]credentialcommon.Machine, error) {
   114  		return []credentialcommon.Machine{s.machine, machine1}, nil
   115  	}
   116  
   117  	results, err := credentialcommon.CheckMachineInstances(s.backend, false, []instances.Instance{s.instance})
   118  	c.Assert(err, jc.ErrorIsNil)
   119  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   120  }
   121  
   122  func (s *CheckMachinesSuite) TestCheckMachinesHandlesManual(c *gc.C) {
   123  	machine1 := createTestMachine("2", "")
   124  	machine1.manualFunc = func() (bool, error) { return false, errors.New("manual retrieval failure") }
   125  	s.backend.allMachinesFunc = func() ([]credentialcommon.Machine, error) {
   126  		return []credentialcommon.Machine{s.machine, machine1}, nil
   127  	}
   128  
   129  	results, err := credentialcommon.CheckMachineInstances(s.backend, false, []instances.Instance{s.instance})
   130  	c.Assert(err, gc.ErrorMatches, "manual retrieval failure")
   131  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   132  
   133  	machine1.manualFunc = func() (bool, error) { return true, nil }
   134  	results, err = credentialcommon.CheckMachineInstances(s.backend, false, []instances.Instance{s.instance})
   135  	c.Assert(err, jc.ErrorIsNil)
   136  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   137  }
   138  
   139  func (s *CheckMachinesSuite) TestCheckMachinesErrorGettingMachineInstanceId(c *gc.C) {
   140  	machine1 := createTestMachine("2", "")
   141  	machine1.instanceIdFunc = func() (instance.Id, error) { return "", errors.New("retrieval failure") }
   142  	s.backend.allMachinesFunc = func() ([]credentialcommon.Machine, error) {
   143  		return []credentialcommon.Machine{s.machine, machine1}, nil
   144  	}
   145  
   146  	results, err := credentialcommon.CheckMachineInstances(s.backend, false, []instances.Instance{s.instance})
   147  	c.Assert(err, jc.ErrorIsNil)
   148  	c.Assert(results, gc.DeepEquals, params.ErrorResults{
   149  		Results: []params.ErrorResult{
   150  			{Error: apiservererrors.ServerError(errors.Errorf("getting instance id for machine 2: retrieval failure"))},
   151  		},
   152  	})
   153  }
   154  
   155  func (s *CheckMachinesSuite) TestCheckMachinesErrorGettingMachineInstanceIdNonFatal(c *gc.C) {
   156  	machine1 := createTestMachine("2", "")
   157  	machine1.instanceIdFunc = func() (instance.Id, error) { return "", errors.New("retrieval failure") }
   158  	s.machine.instanceIdFunc = machine1.instanceIdFunc
   159  	s.backend.allMachinesFunc = func() ([]credentialcommon.Machine, error) {
   160  		return []credentialcommon.Machine{s.machine, machine1}, nil
   161  	}
   162  
   163  	results, err := credentialcommon.CheckMachineInstances(s.backend, false, nil)
   164  	c.Assert(err, jc.ErrorIsNil)
   165  	c.Assert(results, gc.DeepEquals, params.ErrorResults{
   166  		Results: []params.ErrorResult{
   167  			{Error: apiservererrors.ServerError(errors.New("getting instance id for machine 1: retrieval failure"))},
   168  			{Error: apiservererrors.ServerError(errors.New("getting instance id for machine 2: retrieval failure"))},
   169  		},
   170  	})
   171  }
   172  
   173  func (s *CheckMachinesSuite) TestCheckMachinesErrorGettingMachineInstanceIdNonFatalWhenMigrating(c *gc.C) {
   174  	machine1 := createTestMachine("2", "")
   175  	machine1.instanceIdFunc = func() (instance.Id, error) { return "", errors.New("retrieval failure") }
   176  	s.machine.instanceIdFunc = machine1.instanceIdFunc
   177  	s.backend.allMachinesFunc = func() ([]credentialcommon.Machine, error) {
   178  		return []credentialcommon.Machine{s.machine, machine1}, nil
   179  	}
   180  
   181  	results, err := credentialcommon.CheckMachineInstances(s.backend, true, []instances.Instance{s.instance})
   182  	c.Assert(err, jc.ErrorIsNil)
   183  	// There should be 3 errors here:
   184  	// * 2 of them because failing to get an instance id from one machine should not stop the processing the rest of the machines;
   185  	// * 1 because we no longer can link test instance (s.instance) to a test machine (s.machine).
   186  	c.Assert(results, gc.DeepEquals, params.ErrorResults{
   187  		Results: []params.ErrorResult{
   188  			{Error: apiservererrors.ServerError(errors.New("getting instance id for machine 1: retrieval failure"))},
   189  			{Error: apiservererrors.ServerError(errors.New("getting instance id for machine 2: retrieval failure"))},
   190  			{Error: apiservererrors.ServerError(errors.New(`no machine with instance "wind-up"`))},
   191  		},
   192  	})
   193  }
   194  
   195  func (s *CheckMachinesSuite) TestCheckMachinesNotProvisionedError(c *gc.C) {
   196  	machine2 := createTestMachine("2", "")
   197  	machine2.instanceIdFunc = func() (instance.Id, error) { return "", errors.NotProvisionedf("machine 2") }
   198  	s.backend.allMachinesFunc = func() ([]credentialcommon.Machine, error) {
   199  		return []credentialcommon.Machine{s.machine, machine2}, nil
   200  	}
   201  
   202  	// We should ignore the unprovisioned machine - we wouldn't expect
   203  	// the cloud to know about it.
   204  	results, err := credentialcommon.CheckMachineInstances(s.backend, false, []instances.Instance{s.instance})
   205  	c.Assert(err, jc.ErrorIsNil)
   206  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   207  }
   208  
   209  type ModelCredentialSuite struct {
   210  	testing.IsolationSuite
   211  
   212  	backend     *mockPersistedBackend
   213  	callContext context.ProviderCallContext
   214  }
   215  
   216  func (s *ModelCredentialSuite) SetUpTest(c *gc.C) {
   217  	s.IsolationSuite.SetUpTest(c)
   218  	s.backend = createModelBackend()
   219  	s.callContext = context.NewEmptyCloudCallContext()
   220  }
   221  
   222  func (s *ModelCredentialSuite) TestValidateNewModelCredentialUnknownModelType(c *gc.C) {
   223  	unknownModel := createTestModel()
   224  	unknownModel.modelType = state.ModelType("unknown")
   225  	s.backend.modelFunc = func() (credentialcommon.Model, error) {
   226  		return unknownModel, nil
   227  	}
   228  
   229  	results, err := credentialcommon.ValidateNewModelCredential(s.backend, s.callContext, names.CloudCredentialTag{}, &testCredential, false, false)
   230  	c.Assert(err, gc.ErrorMatches, `model type "unknown" not supported`)
   231  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   232  }
   233  
   234  func (s *ModelCredentialSuite) TestBuildingOpenParamsErrorGettingModel(c *gc.C) {
   235  	s.backend.SetErrors(errors.New("get model error"))
   236  	results, err := credentialcommon.ValidateNewModelCredential(s.backend, s.callContext, names.CloudCredentialTag{}, nil, false, false)
   237  	c.Assert(err, gc.ErrorMatches, "get model error")
   238  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   239  	s.backend.CheckCallNames(c, "Model")
   240  }
   241  
   242  func (s *ModelCredentialSuite) TestBuildingOpenParamsErrorGettingCloud(c *gc.C) {
   243  	s.backend.SetErrors(
   244  		nil, // getting model
   245  		errors.New("get cloud error"),
   246  	)
   247  	results, err := credentialcommon.ValidateNewModelCredential(s.backend, s.callContext, names.CloudCredentialTag{}, nil, false, false)
   248  	s.backend.CheckCallNames(c, "Model", "Cloud")
   249  	c.Assert(err, gc.ErrorMatches, "get cloud error")
   250  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   251  }
   252  
   253  func (s *ModelCredentialSuite) TestBuildingOpenParamsErrorGettingModelConfig(c *gc.C) {
   254  	model := createTestModel()
   255  	model.configFunc = func() (*config.Config, error) {
   256  		return nil, errors.New("get model config error")
   257  	}
   258  
   259  	s.backend.modelFunc = func() (credentialcommon.Model, error) {
   260  		return model, nil
   261  	}
   262  
   263  	results, err := credentialcommon.ValidateNewModelCredential(s.backend, s.callContext, names.CloudCredentialTag{}, &testCredential, false, false)
   264  	c.Assert(err, gc.ErrorMatches, "get model config error")
   265  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   266  	s.backend.CheckCallNames(c, "Model", "Cloud")
   267  }
   268  
   269  func (s *ModelCredentialSuite) TestBuildingOpenParamsErrorValidateCredentialForModelCloud(c *gc.C) {
   270  	model := createTestModel()
   271  	model.validateCredentialFunc = func(tag names.CloudCredentialTag, credential cloud.Credential) error {
   272  		return errors.New("credential not for model cloud error")
   273  	}
   274  
   275  	s.backend.modelFunc = func() (credentialcommon.Model, error) {
   276  		return model, nil
   277  	}
   278  
   279  	results, err := credentialcommon.ValidateNewModelCredential(s.backend, s.callContext, names.CloudCredentialTag{}, &testCredential, false, false)
   280  	c.Assert(err, gc.ErrorMatches, "credential not for model cloud error")
   281  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   282  	s.backend.CheckCallNames(c, "Model", "Cloud")
   283  }
   284  
   285  func (s *ModelCredentialSuite) TestValidateExistingModelCredentialErrorGettingModel(c *gc.C) {
   286  	s.backend.SetErrors(errors.New("get model error"))
   287  	results, err := credentialcommon.ValidateExistingModelCredential(s.backend, s.callContext, false, false)
   288  	c.Assert(err, gc.ErrorMatches, "get model error")
   289  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   290  	s.backend.CheckCallNames(c, "Model")
   291  }
   292  
   293  func (s *ModelCredentialSuite) TestValidateExistingModelCredentialUnsetCloudCredential(c *gc.C) {
   294  	model := createTestModel()
   295  	model.cloudCredentialTagFunc = func() (names.CloudCredentialTag, bool) {
   296  		return names.CloudCredentialTag{}, false
   297  	}
   298  
   299  	s.backend.modelFunc = func() (credentialcommon.Model, error) {
   300  		return model, nil
   301  	}
   302  
   303  	results, err := credentialcommon.ValidateExistingModelCredential(s.backend, s.callContext, false, false)
   304  	c.Assert(err, jc.ErrorIsNil)
   305  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   306  	s.backend.CheckCallNames(c, "Model")
   307  }
   308  
   309  func (s *ModelCredentialSuite) TestValidateExistingModelCredentialErrorGettingCredential(c *gc.C) {
   310  	s.backend.cloudCredentialFunc = func(tag names.CloudCredentialTag) (state.Credential, error) {
   311  		return state.Credential{}, errors.New("no nope niet")
   312  	}
   313  
   314  	results, err := credentialcommon.ValidateExistingModelCredential(s.backend, s.callContext, false, false)
   315  	c.Assert(err, gc.ErrorMatches, "no nope niet")
   316  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   317  	s.backend.CheckCallNames(c, "Model", "CloudCredential")
   318  }
   319  
   320  func (s *ModelCredentialSuite) TestValidateExistingModelCredentialInvalidCredential(c *gc.C) {
   321  	s.backend.cloudCredentialFunc = func(tag names.CloudCredentialTag) (state.Credential, error) {
   322  		cred := statetesting.NewEmptyCredential()
   323  		cred.Name = "cred"
   324  		cred.Invalid = true
   325  		return cred, nil
   326  	}
   327  
   328  	results, err := credentialcommon.ValidateExistingModelCredential(s.backend, s.callContext, false, false)
   329  	c.Assert(err, gc.ErrorMatches, `credential "cred" not valid`)
   330  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   331  	s.backend.CheckCallNames(c, "Model", "CloudCredential")
   332  }
   333  
   334  func (s *ModelCredentialSuite) TestOpeningProviderFails(c *gc.C) {
   335  	s.PatchValue(credentialcommon.NewEnv, func(stdcontext.Context, environs.OpenParams) (environs.Environ, error) {
   336  		return nil, errors.New("explosive")
   337  	})
   338  	results, err := credentialcommon.CheckIAASModelCredential(environs.OpenParams{}, s.backend, s.callContext, false, false)
   339  	c.Assert(err, gc.ErrorMatches, "explosive")
   340  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   341  }
   342  
   343  func (s *ModelCredentialSuite) TestValidateNewModelCredentialForIAASModel(c *gc.C) {
   344  	s.ensureEnvForIAASModel(c)
   345  	results, err := credentialcommon.ValidateNewModelCredential(s.backend, s.callContext, names.CloudCredentialTag{}, &testCredential, false, false)
   346  	c.Assert(err, jc.ErrorIsNil)
   347  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   348  }
   349  
   350  func (s *ModelCredentialSuite) TestValidateExistingModelCredentialForIAASModel(c *gc.C) {
   351  	s.ensureEnvForIAASModel(c)
   352  	results, err := credentialcommon.ValidateExistingModelCredential(s.backend, s.callContext, false, false)
   353  	c.Assert(err, jc.ErrorIsNil)
   354  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   355  }
   356  
   357  func (s *ModelCredentialSuite) TestOpeningCAASBrokerFails(c *gc.C) {
   358  	s.PatchValue(credentialcommon.NewCAASBroker, func(stdcontext.Context, environs.OpenParams) (caas.Broker, error) {
   359  		return nil, errors.New("explosive")
   360  	})
   361  	results, err := credentialcommon.CheckCAASModelCredential(environs.OpenParams{})
   362  	c.Assert(err, gc.ErrorMatches, "explosive")
   363  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   364  }
   365  
   366  func (s *ModelCredentialSuite) TestCAASCredentialCheckFailed(c *gc.C) {
   367  	s.PatchValue(credentialcommon.NewCAASBroker, func(stdcontext.Context, environs.OpenParams) (caas.Broker, error) {
   368  		return &mockCaasBroker{
   369  			namespacesFunc: func() ([]string, error) { return nil, errors.New("fail auth") },
   370  		}, nil
   371  	})
   372  	results, err := credentialcommon.CheckCAASModelCredential(environs.OpenParams{})
   373  	c.Assert(err, gc.ErrorMatches, "fail auth")
   374  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   375  }
   376  
   377  func (s *ModelCredentialSuite) TestCAASCredentialCheckSucceeds(c *gc.C) {
   378  	s.PatchValue(credentialcommon.NewCAASBroker, func(stdcontext.Context, environs.OpenParams) (caas.Broker, error) {
   379  		return &mockCaasBroker{
   380  			namespacesFunc: func() ([]string, error) { return []string{}, nil },
   381  		}, nil
   382  	})
   383  	results, err := credentialcommon.CheckCAASModelCredential(environs.OpenParams{})
   384  	c.Assert(err, jc.ErrorIsNil)
   385  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   386  }
   387  
   388  func (s *ModelCredentialSuite) TestValidateNewModelCredentialForCAASModel(c *gc.C) {
   389  	s.ensureEnvForCAASModel(c)
   390  	results, err := credentialcommon.ValidateNewModelCredential(s.backend, s.callContext, names.CloudCredentialTag{}, &testCredential, false, false)
   391  	c.Assert(err, jc.ErrorIsNil)
   392  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   393  }
   394  
   395  func (s *ModelCredentialSuite) TestValidateExistingModelCredentialForCAASSuccess(c *gc.C) {
   396  	s.ensureEnvForCAASModel(c)
   397  	results, err := credentialcommon.ValidateExistingModelCredential(s.backend, s.callContext, false, false)
   398  	c.Assert(err, jc.ErrorIsNil)
   399  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   400  }
   401  
   402  func (s *ModelCredentialSuite) ensureEnvForCAASModel(c *gc.C) {
   403  	caasModel := createTestModel()
   404  	caasModel.modelType = state.ModelTypeCAAS
   405  	s.backend.modelFunc = func() (credentialcommon.Model, error) {
   406  		return caasModel, nil
   407  	}
   408  	s.PatchValue(credentialcommon.NewCAASBroker, func(stdcontext.Context, environs.OpenParams) (caas.Broker, error) {
   409  		return &mockCaasBroker{
   410  			namespacesFunc: func() ([]string, error) { return []string{}, nil },
   411  		}, nil
   412  	})
   413  }
   414  
   415  func (s *ModelCredentialSuite) ensureEnvForIAASModel(c *gc.C) {
   416  	s.PatchValue(credentialcommon.NewEnv, func(stdcontext.Context, environs.OpenParams) (environs.Environ, error) {
   417  		return &mockEnviron{
   418  			mockProvider: &mockProvider{
   419  				Stub: &testing.Stub{},
   420  				allInstancesFunc: func(ctx context.ProviderCallContext) ([]instances.Instance, error) {
   421  					return []instances.Instance{}, nil
   422  				},
   423  			},
   424  		}, nil
   425  	})
   426  }
   427  
   428  func createModelBackend() *mockPersistedBackend {
   429  	backend := mockPersistedBackend{Stub: &testing.Stub{}}
   430  	backend.allMachinesFunc = func() ([]credentialcommon.Machine, error) {
   431  		return []credentialcommon.Machine{}, backend.NextErr()
   432  	}
   433  	backend.modelFunc = func() (credentialcommon.Model, error) {
   434  		return createTestModel(), backend.NextErr()
   435  	}
   436  	backend.controllerConfigFunc = func() (credentialcommon.ControllerConfig, error) {
   437  		return testControllerConfig, backend.NextErr()
   438  	}
   439  
   440  	backend.cloudFunc = func(name string) (cloud.Cloud, error) {
   441  		return cloud.Cloud{
   442  			Name:      "nuage",
   443  			Type:      "dummy",
   444  			AuthTypes: []cloud.AuthType{cloud.EmptyAuthType, cloud.UserPassAuthType},
   445  			Regions:   []cloud.Region{{Name: "nine", Endpoint: "endpoint"}},
   446  		}, backend.NextErr()
   447  	}
   448  	backend.cloudCredentialFunc = func(tag names.CloudCredentialTag) (state.Credential, error) {
   449  		return statetesting.NewEmptyCredential(), backend.NextErr()
   450  	}
   451  	return &backend
   452  }
   453  
   454  type mockProvider struct {
   455  	*testing.Stub
   456  	allInstancesFunc func(ctx context.ProviderCallContext) ([]instances.Instance, error)
   457  }
   458  
   459  func (m *mockProvider) AllInstances(ctx context.ProviderCallContext) ([]instances.Instance, error) {
   460  	m.MethodCall(m, "AllInstances", ctx)
   461  	return m.allInstancesFunc(ctx)
   462  }
   463  
   464  type mockInstance struct {
   465  	instances.Instance
   466  	id string
   467  }
   468  
   469  func (i *mockInstance) Id() instance.Id {
   470  	return instance.Id(i.id)
   471  }
   472  
   473  type mockMachine struct {
   474  	id             string
   475  	container      bool
   476  	manualFunc     func() (bool, error)
   477  	instanceIdFunc func() (instance.Id, error)
   478  }
   479  
   480  func (m *mockMachine) IsManual() (bool, error) {
   481  	return m.manualFunc()
   482  }
   483  
   484  func (m *mockMachine) IsContainer() bool {
   485  	return m.container
   486  }
   487  
   488  func (m *mockMachine) InstanceId() (instance.Id, error) {
   489  	return m.instanceIdFunc()
   490  }
   491  
   492  func (m *mockMachine) InstanceNames() (instance.Id, string, error) {
   493  	instId, err := m.instanceIdFunc()
   494  	return instId, "", err
   495  }
   496  
   497  func (m *mockMachine) Id() string {
   498  	return m.id
   499  }
   500  
   501  func createTestMachine(id, instanceId string) *mockMachine {
   502  	return &mockMachine{
   503  		id:             id,
   504  		manualFunc:     func() (bool, error) { return false, nil },
   505  		instanceIdFunc: func() (instance.Id, error) { return instance.Id(instanceId), nil },
   506  	}
   507  }
   508  
   509  type mockPersistedBackend struct {
   510  	*testing.Stub
   511  	allMachinesFunc func() ([]credentialcommon.Machine, error)
   512  
   513  	modelFunc            func() (credentialcommon.Model, error)
   514  	controllerConfigFunc func() (credentialcommon.ControllerConfig, error)
   515  	cloudFunc            func(name string) (cloud.Cloud, error)
   516  	cloudCredentialFunc  func(tag names.CloudCredentialTag) (state.Credential, error)
   517  }
   518  
   519  func (m *mockPersistedBackend) AllMachines() ([]credentialcommon.Machine, error) {
   520  	m.MethodCall(m, "AllMachines")
   521  	return m.allMachinesFunc()
   522  }
   523  
   524  func (m *mockPersistedBackend) Model() (credentialcommon.Model, error) {
   525  	m.MethodCall(m, "Model")
   526  	return m.modelFunc()
   527  }
   528  
   529  func (m *mockPersistedBackend) ControllerConfig() (credentialcommon.ControllerConfig, error) {
   530  	m.MethodCall(m, "ControllerConfig")
   531  	return m.controllerConfigFunc()
   532  }
   533  
   534  func (m *mockPersistedBackend) Cloud(name string) (cloud.Cloud, error) {
   535  	m.MethodCall(m, "Cloud", name)
   536  	return m.cloudFunc(name)
   537  }
   538  
   539  func (m *mockPersistedBackend) CloudCredential(tag names.CloudCredentialTag) (state.Credential, error) {
   540  	m.MethodCall(m, "CloudCredential", tag)
   541  	return m.cloudCredentialFunc(tag)
   542  }
   543  
   544  type mockModel struct {
   545  	modelType              state.ModelType
   546  	cloudNameFunc          func() string
   547  	cloudRegionFunc        func() string
   548  	configFunc             func() (*config.Config, error)
   549  	validateCredentialFunc func(tag names.CloudCredentialTag, credential cloud.Credential) error
   550  	cloudCredentialTagFunc func() (names.CloudCredentialTag, bool)
   551  }
   552  
   553  func (m *mockModel) CloudName() string {
   554  	return m.cloudNameFunc()
   555  }
   556  
   557  func (m *mockModel) CloudRegion() string {
   558  	return m.cloudRegionFunc()
   559  }
   560  
   561  func (m *mockModel) Config() (*config.Config, error) {
   562  	return m.configFunc()
   563  }
   564  
   565  func (m *mockModel) Type() state.ModelType {
   566  	return m.modelType
   567  }
   568  
   569  func (m *mockModel) CloudCredentialTag() (names.CloudCredentialTag, bool) {
   570  	return m.cloudCredentialTagFunc()
   571  }
   572  
   573  func (m *mockModel) ValidateCloudCredential(tag names.CloudCredentialTag, credential cloud.Credential) error {
   574  	return m.validateCredentialFunc(tag, credential)
   575  }
   576  
   577  func createTestModel() *mockModel {
   578  	return &mockModel{
   579  		modelType:       state.ModelTypeIAAS,
   580  		cloudNameFunc:   func() string { return "nuage" },
   581  		cloudRegionFunc: func() string { return "nine" },
   582  		configFunc: func() (*config.Config, error) {
   583  			return nil, nil
   584  		},
   585  		validateCredentialFunc: func(tag names.CloudCredentialTag, credential cloud.Credential) error {
   586  			return nil
   587  		},
   588  		cloudCredentialTagFunc: func() (names.CloudCredentialTag, bool) {
   589  			// return true here since, most of the time, we want to test when the cloud credential is set.
   590  			return names.CloudCredentialTag{}, true
   591  		},
   592  	}
   593  }
   594  
   595  var (
   596  	testCredential = cloud.NewCredential(
   597  		cloud.UserPassAuthType,
   598  		map[string]string{
   599  			"username": "user",
   600  			"password": "password",
   601  		},
   602  	)
   603  	testControllerConfig = jujuesting.FakeControllerConfig()
   604  )
   605  
   606  type mockEnviron struct {
   607  	environs.Environ
   608  	*mockProvider
   609  }
   610  
   611  func (m *mockEnviron) AllInstances(ctx context.ProviderCallContext) ([]instances.Instance, error) {
   612  	return m.mockProvider.AllInstances(ctx)
   613  }
   614  
   615  type mockCaasBroker struct {
   616  	caas.Broker
   617  
   618  	namespacesFunc func() ([]string, error)
   619  }
   620  
   621  func (m *mockCaasBroker) Namespaces() ([]string, error) {
   622  	return m.namespacesFunc()
   623  }
   624  
   625  func (m *mockCaasBroker) CheckCloudCredentials() error {
   626  	// The k8s provider implements this via a list namespaces call to the cluster
   627  	_, err := m.namespacesFunc()
   628  	return err
   629  }