github.com/mwhudson/juju@v0.0.0-20160512215208-90ff01f3497f/controller/modelmanager/createmodel_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package modelmanager_test
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/testing"
     9  	jc "github.com/juju/testing/checkers"
    10  	"github.com/juju/utils"
    11  	"github.com/juju/version"
    12  	gc "gopkg.in/check.v1"
    13  
    14  	"github.com/juju/juju/cloud"
    15  	"github.com/juju/juju/controller/modelmanager"
    16  	"github.com/juju/juju/environs"
    17  	"github.com/juju/juju/environs/config"
    18  	_ "github.com/juju/juju/provider/all"
    19  	_ "github.com/juju/juju/provider/azure"
    20  	_ "github.com/juju/juju/provider/dummy"
    21  	_ "github.com/juju/juju/provider/ec2"
    22  	_ "github.com/juju/juju/provider/joyent"
    23  	_ "github.com/juju/juju/provider/maas"
    24  	_ "github.com/juju/juju/provider/openstack"
    25  	coretesting "github.com/juju/juju/testing"
    26  	"github.com/juju/juju/tools"
    27  )
    28  
    29  type ModelConfigCreatorSuite struct {
    30  	coretesting.BaseSuite
    31  	creator    modelmanager.ModelConfigCreator
    32  	baseConfig *config.Config
    33  }
    34  
    35  var _ = gc.Suite(&ModelConfigCreatorSuite{})
    36  
    37  func (s *ModelConfigCreatorSuite) SetUpTest(c *gc.C) {
    38  	s.BaseSuite.SetUpTest(c)
    39  	s.creator = modelmanager.ModelConfigCreator{}
    40  	baseConfig, err := config.New(
    41  		config.UseDefaults,
    42  		coretesting.FakeConfig().Merge(coretesting.Attrs{
    43  			"type":          "fake",
    44  			"restricted":    "area51",
    45  			"agent-version": "2.0.0",
    46  		}),
    47  	)
    48  	c.Assert(err, jc.ErrorIsNil)
    49  	s.baseConfig = baseConfig
    50  	fake.Reset()
    51  }
    52  
    53  func (s *ModelConfigCreatorSuite) newModelConfig(attrs map[string]interface{}) (*config.Config, error) {
    54  	return s.creator.NewModelConfig(modelmanager.IsNotAdmin, s.baseConfig, attrs)
    55  }
    56  
    57  func (s *ModelConfigCreatorSuite) newModelConfigAdmin(attrs map[string]interface{}) (*config.Config, error) {
    58  	return s.creator.NewModelConfig(modelmanager.IsAdmin, s.baseConfig, attrs)
    59  }
    60  
    61  func (s *ModelConfigCreatorSuite) TestCreateModelValidatesConfig(c *gc.C) {
    62  	newModelUUID := utils.MustNewUUID().String()
    63  	cfg, err := s.newModelConfig(coretesting.Attrs(
    64  		s.baseConfig.AllAttrs(),
    65  	).Merge(coretesting.Attrs{
    66  		"name":       "new-model",
    67  		"additional": "value",
    68  		"uuid":       newModelUUID,
    69  	}))
    70  	c.Assert(err, jc.ErrorIsNil)
    71  	expected := s.baseConfig.AllAttrs()
    72  	expected["name"] = "new-model"
    73  	expected["additional"] = "value"
    74  	expected["uuid"] = newModelUUID
    75  	c.Assert(cfg.AllAttrs(), jc.DeepEquals, expected)
    76  
    77  	fake.Stub.CheckCallNames(c,
    78  		"RestrictedConfigAttributes",
    79  		"PrepareForCreateEnvironment",
    80  		"Validate",
    81  	)
    82  	validateCall := fake.Stub.Calls()[2]
    83  	c.Assert(validateCall.Args, gc.HasLen, 2)
    84  	c.Assert(validateCall.Args[0], gc.Equals, cfg)
    85  	c.Assert(validateCall.Args[1], gc.IsNil)
    86  }
    87  
    88  func (s *ModelConfigCreatorSuite) TestCreateModelForAdminUserCopiesSecrets(c *gc.C) {
    89  	var err error
    90  	s.baseConfig, err = s.baseConfig.Apply(coretesting.Attrs{
    91  		"username":        "user",
    92  		"password":        "password",
    93  		"authorized-keys": "ssh-key",
    94  	})
    95  	c.Assert(err, jc.ErrorIsNil)
    96  	newModelUUID := utils.MustNewUUID().String()
    97  	newAttrs := coretesting.Attrs{
    98  		"name":       "new-model",
    99  		"additional": "value",
   100  		"uuid":       newModelUUID,
   101  	}
   102  	cfg, err := s.newModelConfigAdmin(newAttrs)
   103  	c.Assert(err, jc.ErrorIsNil)
   104  	expectedCfg, err := config.New(config.UseDefaults, newAttrs)
   105  	c.Assert(err, jc.ErrorIsNil)
   106  	expected := expectedCfg.AllAttrs()
   107  	c.Assert(expected["username"], gc.Equals, "user")
   108  	c.Assert(expected["password"], gc.Equals, "password")
   109  	c.Assert(expected["authorized-keys"], gc.Equals, "ssh-key")
   110  	c.Assert(cfg.AllAttrs(), jc.DeepEquals, expected)
   111  
   112  	fake.Stub.CheckCallNames(c,
   113  		"RestrictedConfigAttributes",
   114  		"PrepareForCreateEnvironment",
   115  		"Validate",
   116  	)
   117  	validateCall := fake.Stub.Calls()[2]
   118  	c.Assert(validateCall.Args, gc.HasLen, 2)
   119  	c.Assert(validateCall.Args[0], gc.Equals, cfg)
   120  	c.Assert(validateCall.Args[1], gc.IsNil)
   121  }
   122  
   123  func (s *ModelConfigCreatorSuite) TestCreateModelEnsuresRequiredFields(c *gc.C) {
   124  	var err error
   125  	s.baseConfig, err = s.baseConfig.Apply(coretesting.Attrs{
   126  		"authorized-keys": "ssh-key",
   127  	})
   128  	c.Assert(err, jc.ErrorIsNil)
   129  	newAttrs := coretesting.Attrs{
   130  		"name": "new-model",
   131  	}
   132  	_, err = s.newModelConfigAdmin(newAttrs)
   133  	c.Assert(err, jc.ErrorIsNil)
   134  	c.Assert(newAttrs["authorized-keys"], gc.Equals, "ssh-key")
   135  }
   136  
   137  func (s *ModelConfigCreatorSuite) TestCreateModelForAdminUserPrefersUserSecrets(c *gc.C) {
   138  	var err error
   139  	s.baseConfig, err = s.baseConfig.Apply(coretesting.Attrs{
   140  		"username":        "user",
   141  		"password":        "password",
   142  		"authorized-keys": "ssh-key",
   143  	})
   144  	c.Assert(err, jc.ErrorIsNil)
   145  	newModelUUID := utils.MustNewUUID().String()
   146  	newAttrs := coretesting.Attrs{
   147  		"name":       "new-model",
   148  		"additional": "value",
   149  		"uuid":       newModelUUID,
   150  		"username":   "anotheruser",
   151  		"password":   "anotherpassword",
   152  	}
   153  	cfg, err := s.newModelConfigAdmin(newAttrs)
   154  	c.Assert(err, jc.ErrorIsNil)
   155  	expectedCfg, err := config.New(config.UseDefaults, newAttrs)
   156  	c.Assert(err, jc.ErrorIsNil)
   157  	expected := expectedCfg.AllAttrs()
   158  	c.Assert(expected["username"], gc.Equals, "anotheruser")
   159  	c.Assert(expected["password"], gc.Equals, "anotherpassword")
   160  	c.Assert(expected["authorized-keys"], gc.Equals, "ssh-key")
   161  	c.Assert(cfg.AllAttrs(), jc.DeepEquals, expected)
   162  
   163  	fake.Stub.CheckCallNames(c,
   164  		"RestrictedConfigAttributes",
   165  		"PrepareForCreateEnvironment",
   166  		"Validate",
   167  	)
   168  	validateCall := fake.Stub.Calls()[2]
   169  	c.Assert(validateCall.Args, gc.HasLen, 2)
   170  	c.Assert(validateCall.Args[0], gc.Equals, cfg)
   171  	c.Assert(validateCall.Args[1], gc.IsNil)
   172  }
   173  
   174  func (s *ModelConfigCreatorSuite) TestCreateModelBadConfig(c *gc.C) {
   175  	for i, test := range []struct {
   176  		key      string
   177  		value    interface{}
   178  		errMatch string
   179  	}{{
   180  		key:      "type",
   181  		value:    "dummy",
   182  		errMatch: `specified type "dummy" does not match controller "fake"`,
   183  	}, {
   184  		key:      "state-port",
   185  		value:    9876,
   186  		errMatch: `specified state-port "9876" does not match controller "19034"`,
   187  	}, {
   188  		key:      "restricted",
   189  		value:    51,
   190  		errMatch: `specified restricted "51" does not match controller "area51"`,
   191  	}} {
   192  		c.Logf("%d: %s", i, test.key)
   193  		_, err := s.newModelConfig(coretesting.Attrs(
   194  			s.baseConfig.AllAttrs(),
   195  		).Merge(coretesting.Attrs{
   196  			test.key: test.value,
   197  		}))
   198  		c.Check(err, gc.ErrorMatches, test.errMatch)
   199  	}
   200  }
   201  
   202  func (s *ModelConfigCreatorSuite) TestCreateModelSameAgentVersion(c *gc.C) {
   203  	cfg, err := s.newModelConfig(coretesting.Attrs(
   204  		s.baseConfig.AllAttrs(),
   205  	).Merge(coretesting.Attrs{
   206  		"name": "new-model",
   207  		"uuid": utils.MustNewUUID().String(),
   208  	}))
   209  	c.Assert(err, jc.ErrorIsNil)
   210  
   211  	baseAgentVersion, ok := s.baseConfig.AgentVersion()
   212  	c.Assert(ok, jc.IsTrue)
   213  	agentVersion, ok := cfg.AgentVersion()
   214  	c.Assert(ok, jc.IsTrue)
   215  	c.Assert(agentVersion, gc.Equals, baseAgentVersion)
   216  }
   217  
   218  func (s *ModelConfigCreatorSuite) TestCreateModelGreaterAgentVersion(c *gc.C) {
   219  	_, err := s.newModelConfig(coretesting.Attrs(
   220  		s.baseConfig.AllAttrs(),
   221  	).Merge(coretesting.Attrs{
   222  		"name":          "new-model",
   223  		"uuid":          utils.MustNewUUID().String(),
   224  		"agent-version": "2.0.1",
   225  	}))
   226  	c.Assert(err, gc.ErrorMatches,
   227  		"agent-version .* cannot be greater than the controller .*")
   228  }
   229  
   230  func (s *ModelConfigCreatorSuite) TestCreateModelLesserAgentVersionNoToolsFinder(c *gc.C) {
   231  	_, err := s.newModelConfig(coretesting.Attrs(
   232  		s.baseConfig.AllAttrs(),
   233  	).Merge(coretesting.Attrs{
   234  		"name":          "new-model",
   235  		"uuid":          utils.MustNewUUID().String(),
   236  		"agent-version": "1.9.9",
   237  	}))
   238  	c.Assert(err, gc.ErrorMatches,
   239  		"agent-version does not match base config, and no tools-finder is supplied")
   240  }
   241  
   242  func (s *ModelConfigCreatorSuite) TestCreateModelLesserAgentVersionToolsFinderFound(c *gc.C) {
   243  	s.creator.FindTools = func(version.Number) (tools.List, error) {
   244  		return tools.List{
   245  			{}, //contents don't matter, just need a non-empty list
   246  		}, nil
   247  	}
   248  	cfg, err := s.newModelConfig(coretesting.Attrs(
   249  		s.baseConfig.AllAttrs(),
   250  	).Merge(coretesting.Attrs{
   251  		"name":          "new-model",
   252  		"uuid":          utils.MustNewUUID().String(),
   253  		"agent-version": "1.9.9",
   254  	}))
   255  	c.Assert(err, jc.ErrorIsNil)
   256  	agentVersion, ok := cfg.AgentVersion()
   257  	c.Assert(ok, jc.IsTrue)
   258  	c.Assert(agentVersion, gc.Equals, version.MustParse("1.9.9"))
   259  }
   260  
   261  func (s *ModelConfigCreatorSuite) TestCreateModelLesserAgentVersionToolsFinderNotFound(c *gc.C) {
   262  	s.creator.FindTools = func(version.Number) (tools.List, error) {
   263  		return tools.List{}, nil
   264  	}
   265  	_, err := s.newModelConfig(coretesting.Attrs(
   266  		s.baseConfig.AllAttrs(),
   267  	).Merge(coretesting.Attrs{
   268  		"name":          "new-model",
   269  		"uuid":          utils.MustNewUUID().String(),
   270  		"agent-version": "1.9.9",
   271  	}))
   272  	c.Assert(err, gc.ErrorMatches, "no tools found for version .*")
   273  }
   274  
   275  type RestrictedProviderFieldsSuite struct {
   276  	coretesting.BaseSuite
   277  }
   278  
   279  var _ = gc.Suite(&RestrictedProviderFieldsSuite{})
   280  
   281  func (*RestrictedProviderFieldsSuite) TestRestrictedProviderFields(c *gc.C) {
   282  	for i, test := range []struct {
   283  		provider string
   284  		expected []string
   285  	}{{
   286  		provider: "azure",
   287  		expected: []string{
   288  			"type", "ca-cert", "state-port", "api-port", "controller-uuid",
   289  			"location", "endpoint", "storage-endpoint",
   290  		},
   291  	}, {
   292  		provider: "dummy",
   293  		expected: []string{
   294  			"type", "ca-cert", "state-port", "api-port", "controller-uuid",
   295  		},
   296  	}, {
   297  		provider: "joyent",
   298  		expected: []string{
   299  			"type", "ca-cert", "state-port", "api-port", "controller-uuid", "sdc-url",
   300  		},
   301  	}, {
   302  		provider: "maas",
   303  		expected: []string{
   304  			"type", "ca-cert", "state-port", "api-port", "controller-uuid",
   305  			"maas-server",
   306  		},
   307  	}, {
   308  		provider: "openstack",
   309  		expected: []string{
   310  			"type", "ca-cert", "state-port", "api-port", "controller-uuid",
   311  			"region", "auth-url", "auth-mode",
   312  		},
   313  	}, {
   314  		provider: "ec2",
   315  		expected: []string{
   316  			"type", "ca-cert", "state-port", "api-port", "controller-uuid",
   317  			"region", "vpc-id", "vpc-id-force",
   318  		},
   319  	}} {
   320  		c.Logf("%d: %s provider", i, test.provider)
   321  		fields, err := modelmanager.RestrictedProviderFields(test.provider)
   322  		c.Check(err, jc.ErrorIsNil)
   323  		c.Check(fields, jc.SameContents, test.expected)
   324  	}
   325  }
   326  
   327  type fakeProvider struct {
   328  	testing.Stub
   329  	environs.EnvironProvider
   330  	restrictedConfigAttributes []string
   331  }
   332  
   333  func (p *fakeProvider) Reset() {
   334  	p.Stub.ResetCalls()
   335  	p.restrictedConfigAttributes = []string{"restricted"}
   336  }
   337  
   338  func (p *fakeProvider) RestrictedConfigAttributes() []string {
   339  	p.MethodCall(p, "RestrictedConfigAttributes")
   340  	return p.restrictedConfigAttributes
   341  }
   342  
   343  func (p *fakeProvider) Validate(cfg, old *config.Config) (*config.Config, error) {
   344  	p.MethodCall(p, "Validate", cfg, old)
   345  	return cfg, p.NextErr()
   346  }
   347  
   348  func (p *fakeProvider) PrepareForCreateEnvironment(cfg *config.Config) (*config.Config, error) {
   349  	p.MethodCall(p, "PrepareForCreateEnvironment", cfg)
   350  	return cfg, p.NextErr()
   351  }
   352  
   353  func (p *fakeProvider) CredentialSchemas() map[cloud.AuthType]cloud.CredentialSchema {
   354  	return map[cloud.AuthType]cloud.CredentialSchema{
   355  		cloud.UserPassAuthType: {
   356  			{
   357  				"username", cloud.CredentialAttr{Description: "The username"},
   358  			}, {
   359  				"password", cloud.CredentialAttr{
   360  					Description: "The password",
   361  					Hidden:      true,
   362  				},
   363  			},
   364  		},
   365  	}
   366  }
   367  
   368  func (p *fakeProvider) DetectCredentials() (*cloud.CloudCredential, error) {
   369  	return nil, errors.NotFoundf("credentials")
   370  }
   371  
   372  var fake fakeProvider
   373  
   374  func init() {
   375  	fake.Reset()
   376  	environs.RegisterProvider("fake", &fake)
   377  }