github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/cmd/juju/controller/createmodel_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package controller_test
     5  
     6  import (
     7  	"io/ioutil"
     8  
     9  	"github.com/juju/cmd"
    10  	"github.com/juju/errors"
    11  	jc "github.com/juju/testing/checkers"
    12  	"github.com/juju/utils"
    13  	gc "gopkg.in/check.v1"
    14  	"gopkg.in/yaml.v2"
    15  
    16  	"github.com/juju/juju/apiserver/params"
    17  	"github.com/juju/juju/cloud"
    18  	"github.com/juju/juju/cmd/juju/controller"
    19  	"github.com/juju/juju/cmd/modelcmd"
    20  	"github.com/juju/juju/jujuclient"
    21  	"github.com/juju/juju/jujuclient/jujuclienttesting"
    22  	_ "github.com/juju/juju/provider/ec2"
    23  	"github.com/juju/juju/testing"
    24  )
    25  
    26  type createSuite struct {
    27  	testing.FakeJujuXDGDataHomeSuite
    28  	fake  *fakeCreateClient
    29  	store *jujuclienttesting.MemStore
    30  }
    31  
    32  var _ = gc.Suite(&createSuite{})
    33  
    34  func (s *createSuite) SetUpTest(c *gc.C) {
    35  	s.FakeJujuXDGDataHomeSuite.SetUpTest(c)
    36  	s.fake = &fakeCreateClient{
    37  		model: params.Model{
    38  			Name:     "test",
    39  			UUID:     "fake-model-uuid",
    40  			OwnerTag: "ignored-for-now",
    41  		},
    42  	}
    43  
    44  	// Set up the current controller, and write just enough info
    45  	// so we don't try to refresh
    46  	controllerName := "local.test-master"
    47  	err := modelcmd.WriteCurrentController(controllerName)
    48  	c.Assert(err, jc.ErrorIsNil)
    49  
    50  	s.store = jujuclienttesting.NewMemStore()
    51  	s.store.Controllers["local.test-master"] = jujuclient.ControllerDetails{}
    52  	s.store.Accounts[controllerName] = &jujuclient.ControllerAccounts{
    53  		Accounts: map[string]jujuclient.AccountDetails{
    54  			"bob@local": {User: "bob@local"},
    55  		},
    56  		CurrentAccount: "bob@local",
    57  	}
    58  	s.store.Credentials["aws"] = cloud.CloudCredential{
    59  		AuthCredentials: map[string]cloud.Credential{
    60  			"secrets": cloud.NewCredential(cloud.AccessKeyAuthType, map[string]string{
    61  				"access-key": "key",
    62  				"secret-key": "sekret",
    63  			}),
    64  		},
    65  	}
    66  }
    67  
    68  func (s *createSuite) run(c *gc.C, args ...string) (*cmd.Context, error) {
    69  	command, _ := controller.NewCreateModelCommandForTest(s.fake, s.store, s.store)
    70  	return testing.RunCommand(c, command, args...)
    71  }
    72  
    73  func (s *createSuite) TestInit(c *gc.C) {
    74  
    75  	for i, test := range []struct {
    76  		args   []string
    77  		err    string
    78  		name   string
    79  		owner  string
    80  		values map[string]interface{}
    81  	}{
    82  		{
    83  			err: "model name is required",
    84  		}, {
    85  			args: []string{"new-model"},
    86  			name: "new-model",
    87  		}, {
    88  			args:  []string{"new-model", "--owner", "foo"},
    89  			name:  "new-model",
    90  			owner: "foo",
    91  		}, {
    92  			args: []string{"new-model", "--owner", "not=valid"},
    93  			err:  `"not=valid" is not a valid user`,
    94  		}, {
    95  			args: []string{"new-model", "--credential", "secrets"},
    96  			err:  `invalid cloud credential secrets, expected <cloud>:<credential-name>`,
    97  		}, {
    98  			args:   []string{"new-model", "--config", "key=value", "--config", "key2=value2"},
    99  			name:   "new-model",
   100  			values: map[string]interface{}{"key": "value", "key2": "value2"},
   101  		},
   102  	} {
   103  		c.Logf("test %d", i)
   104  		wrappedCommand, command := controller.NewCreateModelCommandForTest(nil, s.store, s.store)
   105  		err := testing.InitCommand(wrappedCommand, test.args)
   106  		if test.err != "" {
   107  			c.Assert(err, gc.ErrorMatches, test.err)
   108  			continue
   109  		}
   110  
   111  		c.Assert(err, jc.ErrorIsNil)
   112  		c.Assert(command.Name, gc.Equals, test.name)
   113  		c.Assert(command.Owner, gc.Equals, test.owner)
   114  		attrs, err := command.Config.ReadAttrs(nil)
   115  		c.Assert(err, jc.ErrorIsNil)
   116  		if len(test.values) == 0 {
   117  			c.Assert(attrs, gc.HasLen, 0)
   118  		} else {
   119  			c.Assert(attrs, jc.DeepEquals, test.values)
   120  		}
   121  	}
   122  }
   123  
   124  func (s *createSuite) TestCreateExistingName(c *gc.C) {
   125  	// If there's any model details existing, we just overwrite them. The
   126  	// controller will error out if the model already exists. Overwriting
   127  	// means we'll replace any stale details from an previously existing
   128  	// model with the same name.
   129  	err := s.store.UpdateModel("local.test-master", "bob@local", "test", jujuclient.ModelDetails{
   130  		"stale-uuid",
   131  	})
   132  	c.Assert(err, jc.ErrorIsNil)
   133  
   134  	_, err = s.run(c, "test")
   135  	c.Assert(err, jc.ErrorIsNil)
   136  
   137  	details, err := s.store.ModelByName("local.test-master", "bob@local", "test")
   138  	c.Assert(err, jc.ErrorIsNil)
   139  	c.Assert(details, jc.DeepEquals, &jujuclient.ModelDetails{"fake-model-uuid"})
   140  }
   141  
   142  func (s *createSuite) TestCredentialsPassedThrough(c *gc.C) {
   143  	_, err := s.run(c, "test", "--credential", "aws:secrets")
   144  	c.Assert(err, jc.ErrorIsNil)
   145  
   146  	c.Assert(s.fake.config["type"], gc.Equals, "ec2")
   147  	c.Assert(s.fake.account, jc.DeepEquals, map[string]interface{}{
   148  		"access-key": "key",
   149  		"secret-key": "sekret",
   150  	})
   151  }
   152  
   153  func (s *createSuite) TestComandLineConfigPassedThrough(c *gc.C) {
   154  	_, err := s.run(c, "test", "--config", "account=magic", "--config", "cloud=special")
   155  	c.Assert(err, jc.ErrorIsNil)
   156  
   157  	c.Assert(s.fake.config["account"], gc.Equals, "magic")
   158  	c.Assert(s.fake.config["cloud"], gc.Equals, "special")
   159  }
   160  
   161  func (s *createSuite) TestConfigFileValuesPassedThrough(c *gc.C) {
   162  	config := map[string]string{
   163  		"account": "magic",
   164  		"cloud":   "9",
   165  	}
   166  	bytes, err := yaml.Marshal(config)
   167  	c.Assert(err, jc.ErrorIsNil)
   168  	file, err := ioutil.TempFile(c.MkDir(), "")
   169  	c.Assert(err, jc.ErrorIsNil)
   170  	file.Write(bytes)
   171  	file.Close()
   172  
   173  	_, err = s.run(c, "test", "--config", file.Name())
   174  	c.Assert(err, jc.ErrorIsNil)
   175  	c.Assert(s.fake.config["account"], gc.Equals, "magic")
   176  	c.Assert(s.fake.config["cloud"], gc.Equals, "9")
   177  }
   178  
   179  func (s *createSuite) TestConfigFileWithNestedMaps(c *gc.C) {
   180  	nestedConfig := map[string]interface{}{
   181  		"account": "magic",
   182  		"cloud":   "9",
   183  	}
   184  	config := map[string]interface{}{
   185  		"foo":    "bar",
   186  		"nested": nestedConfig,
   187  	}
   188  
   189  	bytes, err := yaml.Marshal(config)
   190  	c.Assert(err, jc.ErrorIsNil)
   191  	file, err := ioutil.TempFile(c.MkDir(), "")
   192  	c.Assert(err, jc.ErrorIsNil)
   193  	file.Write(bytes)
   194  	file.Close()
   195  
   196  	_, err = s.run(c, "test", "--config", file.Name())
   197  	c.Assert(err, jc.ErrorIsNil)
   198  	c.Assert(s.fake.config["foo"], gc.Equals, "bar")
   199  	c.Assert(s.fake.config["nested"], jc.DeepEquals, nestedConfig)
   200  }
   201  
   202  func (s *createSuite) TestConfigFileFailsToConform(c *gc.C) {
   203  	nestedConfig := map[int]interface{}{
   204  		9: "9",
   205  	}
   206  	config := map[string]interface{}{
   207  		"foo":    "bar",
   208  		"nested": nestedConfig,
   209  	}
   210  	bytes, err := yaml.Marshal(config)
   211  	c.Assert(err, jc.ErrorIsNil)
   212  	file, err := ioutil.TempFile(c.MkDir(), "")
   213  	c.Assert(err, jc.ErrorIsNil)
   214  	file.Write(bytes)
   215  	file.Close()
   216  
   217  	_, err = s.run(c, "test", "--config", file.Name())
   218  	c.Assert(err, gc.ErrorMatches, `unable to parse config: map keyed with non-string value`)
   219  }
   220  
   221  func (s *createSuite) TestConfigFileFormatError(c *gc.C) {
   222  	file, err := ioutil.TempFile(c.MkDir(), "")
   223  	c.Assert(err, jc.ErrorIsNil)
   224  	file.Write(([]byte)("not: valid: yaml"))
   225  	file.Close()
   226  
   227  	_, err = s.run(c, "test", "--config", file.Name())
   228  	c.Assert(err, gc.ErrorMatches, `unable to parse config: yaml: .*`)
   229  }
   230  
   231  func (s *createSuite) TestConfigFileDoesntExist(c *gc.C) {
   232  	_, err := s.run(c, "test", "--config", "missing-file")
   233  	errMsg := ".*" + utils.NoSuchFileErrRegexp
   234  	c.Assert(err, gc.ErrorMatches, errMsg)
   235  }
   236  
   237  func (s *createSuite) TestConfigValuePrecedence(c *gc.C) {
   238  	config := map[string]string{
   239  		"account": "magic",
   240  		"cloud":   "9",
   241  	}
   242  	bytes, err := yaml.Marshal(config)
   243  	c.Assert(err, jc.ErrorIsNil)
   244  	file, err := ioutil.TempFile(c.MkDir(), "")
   245  	c.Assert(err, jc.ErrorIsNil)
   246  	file.Write(bytes)
   247  	file.Close()
   248  
   249  	_, err = s.run(c, "test", "--config", file.Name(), "--config", "account=magic", "--config", "cloud=special")
   250  	c.Assert(err, jc.ErrorIsNil)
   251  	c.Assert(s.fake.config["account"], gc.Equals, "magic")
   252  	c.Assert(s.fake.config["cloud"], gc.Equals, "special")
   253  }
   254  
   255  func (s *createSuite) TestCreateErrorRemoveConfigstoreInfo(c *gc.C) {
   256  	s.fake.err = errors.New("bah humbug")
   257  
   258  	_, err := s.run(c, "test")
   259  	c.Assert(err, gc.ErrorMatches, "bah humbug")
   260  
   261  	_, err = s.store.ModelByName("local.test-master", "bob@local", "test")
   262  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   263  }
   264  
   265  func (s *createSuite) TestCreateStoresValues(c *gc.C) {
   266  	_, err := s.run(c, "test")
   267  	c.Assert(err, jc.ErrorIsNil)
   268  
   269  	model, err := s.store.ModelByName("local.test-master", "bob@local", "test")
   270  	c.Assert(err, jc.ErrorIsNil)
   271  	c.Assert(model, jc.DeepEquals, &jujuclient.ModelDetails{"fake-model-uuid"})
   272  }
   273  
   274  func (s *createSuite) TestNoEnvCacheOtherUser(c *gc.C) {
   275  	_, err := s.run(c, "test", "--owner", "zeus")
   276  	c.Assert(err, jc.ErrorIsNil)
   277  
   278  	// Creating a model for another user does not update the model cache.
   279  	_, err = s.store.ModelByName("local.test-master", "bob@local", "test")
   280  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   281  	_, err = s.store.ModelByName("local.test-master", "zeus@local", "test")
   282  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   283  }
   284  
   285  // fakeCreateClient is used to mock out the behavior of the real
   286  //  CreateModel command.
   287  type fakeCreateClient struct {
   288  	owner   string
   289  	account map[string]interface{}
   290  	config  map[string]interface{}
   291  	err     error
   292  	model   params.Model
   293  }
   294  
   295  var _ controller.CreateModelAPI = (*fakeCreateClient)(nil)
   296  
   297  func (*fakeCreateClient) Close() error {
   298  	return nil
   299  }
   300  
   301  func (*fakeCreateClient) ConfigSkeleton(provider, region string) (params.ModelConfig, error) {
   302  	if provider == "" {
   303  		provider = "dummy"
   304  	}
   305  	return params.ModelConfig{
   306  		"type":       provider,
   307  		"controller": false,
   308  	}, nil
   309  }
   310  func (f *fakeCreateClient) CreateModel(owner string, account, config map[string]interface{}) (params.Model, error) {
   311  	if f.err != nil {
   312  		return params.Model{}, f.err
   313  	}
   314  	f.owner = owner
   315  	f.account = account
   316  	f.config = config
   317  	return f.model, nil
   318  }