github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/apiserver/environmentmanager/environmentmanager_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package environmentmanager_test
     5  
     6  import (
     7  	"github.com/juju/loggo"
     8  	"github.com/juju/names"
     9  	jc "github.com/juju/testing/checkers"
    10  	gc "gopkg.in/check.v1"
    11  
    12  	"github.com/juju/juju/apiserver/common"
    13  	"github.com/juju/juju/apiserver/environmentmanager"
    14  	"github.com/juju/juju/apiserver/params"
    15  	apiservertesting "github.com/juju/juju/apiserver/testing"
    16  	"github.com/juju/juju/environs"
    17  	"github.com/juju/juju/environs/config"
    18  	jujutesting "github.com/juju/juju/juju/testing"
    19  	// Register the providers for the field check test
    20  	_ "github.com/juju/juju/provider/azure"
    21  	_ "github.com/juju/juju/provider/ec2"
    22  	_ "github.com/juju/juju/provider/joyent"
    23  	_ "github.com/juju/juju/provider/local"
    24  	_ "github.com/juju/juju/provider/maas"
    25  	_ "github.com/juju/juju/provider/openstack"
    26  	"github.com/juju/juju/state"
    27  	coretesting "github.com/juju/juju/testing"
    28  	"github.com/juju/juju/version"
    29  )
    30  
    31  type envManagerBaseSuite struct {
    32  	jujutesting.JujuConnSuite
    33  
    34  	envmanager *environmentmanager.EnvironmentManagerAPI
    35  	resources  *common.Resources
    36  	authoriser apiservertesting.FakeAuthorizer
    37  }
    38  
    39  func (s *envManagerBaseSuite) SetUpTest(c *gc.C) {
    40  	s.JujuConnSuite.SetUpTest(c)
    41  	s.resources = common.NewResources()
    42  	s.AddCleanup(func(_ *gc.C) { s.resources.StopAll() })
    43  
    44  	s.authoriser = apiservertesting.FakeAuthorizer{
    45  		Tag: s.AdminUserTag(c),
    46  	}
    47  
    48  	loggo.GetLogger("juju.apiserver.environmentmanager").SetLogLevel(loggo.TRACE)
    49  }
    50  
    51  func (s *envManagerBaseSuite) setAPIUser(c *gc.C, user names.UserTag) {
    52  	s.authoriser.Tag = user
    53  	envmanager, err := environmentmanager.NewEnvironmentManagerAPI(s.State, s.resources, s.authoriser)
    54  	c.Assert(err, jc.ErrorIsNil)
    55  	s.envmanager = envmanager
    56  }
    57  
    58  type envManagerSuite struct {
    59  	envManagerBaseSuite
    60  }
    61  
    62  var _ = gc.Suite(&envManagerSuite{})
    63  
    64  func (s *envManagerSuite) TestNewAPIAcceptsClient(c *gc.C) {
    65  	anAuthoriser := s.authoriser
    66  	anAuthoriser.Tag = names.NewUserTag("external@remote")
    67  	endPoint, err := environmentmanager.NewEnvironmentManagerAPI(s.State, s.resources, anAuthoriser)
    68  	c.Assert(err, jc.ErrorIsNil)
    69  	c.Assert(endPoint, gc.NotNil)
    70  }
    71  
    72  func (s *envManagerSuite) TestNewAPIRefusesNonClient(c *gc.C) {
    73  	anAuthoriser := s.authoriser
    74  	anAuthoriser.Tag = names.NewUnitTag("mysql/0")
    75  	endPoint, err := environmentmanager.NewEnvironmentManagerAPI(s.State, s.resources, anAuthoriser)
    76  	c.Assert(endPoint, gc.IsNil)
    77  	c.Assert(err, gc.ErrorMatches, "permission denied")
    78  }
    79  
    80  func (s *envManagerSuite) createArgs(c *gc.C, owner names.UserTag) params.EnvironmentCreateArgs {
    81  	return params.EnvironmentCreateArgs{
    82  		OwnerTag: owner.String(),
    83  		Account:  make(map[string]interface{}),
    84  		Config: map[string]interface{}{
    85  			"name":            "test-env",
    86  			"authorized-keys": "ssh-key",
    87  			// And to make it a valid dummy config
    88  			"state-server": false,
    89  		},
    90  	}
    91  }
    92  
    93  func (s *envManagerSuite) createArgsForVersion(c *gc.C, owner names.UserTag, ver interface{}) params.EnvironmentCreateArgs {
    94  	params := s.createArgs(c, owner)
    95  	params.Config["agent-version"] = ver
    96  	return params
    97  }
    98  
    99  func (s *envManagerSuite) TestUserCanCreateEnvironment(c *gc.C) {
   100  	owner := names.NewUserTag("external@remote")
   101  	s.setAPIUser(c, owner)
   102  	env, err := s.envmanager.CreateEnvironment(s.createArgs(c, owner))
   103  	c.Assert(err, jc.ErrorIsNil)
   104  	c.Assert(env.OwnerTag, gc.Equals, owner.String())
   105  	c.Assert(env.Name, gc.Equals, "test-env")
   106  }
   107  
   108  func (s *envManagerSuite) TestAdminCanCreateEnvironmentForSomeoneElse(c *gc.C) {
   109  	s.setAPIUser(c, s.AdminUserTag(c))
   110  	owner := names.NewUserTag("external@remote")
   111  	env, err := s.envmanager.CreateEnvironment(s.createArgs(c, owner))
   112  	c.Assert(err, jc.ErrorIsNil)
   113  	c.Assert(env.OwnerTag, gc.Equals, owner.String())
   114  	c.Assert(env.Name, gc.Equals, "test-env")
   115  	// Make sure that the environment created does actually have the correct
   116  	// owner, and that owner is actually allowed to use the environment.
   117  	newState, err := s.State.ForEnviron(names.NewEnvironTag(env.UUID))
   118  	c.Assert(err, jc.ErrorIsNil)
   119  	defer newState.Close()
   120  
   121  	newEnv, err := newState.Environment()
   122  	c.Assert(err, jc.ErrorIsNil)
   123  	c.Assert(newEnv.Owner(), gc.Equals, owner)
   124  	_, err = newState.EnvironmentUser(owner)
   125  	c.Assert(err, jc.ErrorIsNil)
   126  }
   127  
   128  func (s *envManagerSuite) TestNonAdminCannotCreateEnvironmentForSomeoneElse(c *gc.C) {
   129  	s.setAPIUser(c, names.NewUserTag("non-admin@remote"))
   130  	owner := names.NewUserTag("external@remote")
   131  	_, err := s.envmanager.CreateEnvironment(s.createArgs(c, owner))
   132  	c.Assert(err, gc.ErrorMatches, "permission denied")
   133  }
   134  
   135  func (s *envManagerSuite) TestRestrictedProviderFields(c *gc.C) {
   136  	s.setAPIUser(c, names.NewUserTag("non-admin@remote"))
   137  	for i, test := range []struct {
   138  		provider string
   139  		expected []string
   140  	}{
   141  		{
   142  			provider: "azure",
   143  			expected: []string{
   144  				"type", "ca-cert", "state-port", "api-port", "syslog-port", "rsyslog-ca-cert", "rsyslog-ca-key",
   145  				"location"},
   146  		}, {
   147  			provider: "dummy",
   148  			expected: []string{
   149  				"type", "ca-cert", "state-port", "api-port", "syslog-port", "rsyslog-ca-cert", "rsyslog-ca-key"},
   150  		}, {
   151  			provider: "joyent",
   152  			expected: []string{
   153  				"type", "ca-cert", "state-port", "api-port", "syslog-port", "rsyslog-ca-cert", "rsyslog-ca-key"},
   154  		}, {
   155  			provider: "local",
   156  			expected: []string{
   157  				"type", "ca-cert", "state-port", "api-port", "syslog-port", "rsyslog-ca-cert", "rsyslog-ca-key",
   158  				"container", "network-bridge", "root-dir", "proxy-ssh"},
   159  		}, {
   160  			provider: "maas",
   161  			expected: []string{
   162  				"type", "ca-cert", "state-port", "api-port", "syslog-port", "rsyslog-ca-cert", "rsyslog-ca-key",
   163  				"maas-server"},
   164  		}, {
   165  			provider: "openstack",
   166  			expected: []string{
   167  				"type", "ca-cert", "state-port", "api-port", "syslog-port", "rsyslog-ca-cert", "rsyslog-ca-key",
   168  				"region", "auth-url", "auth-mode"},
   169  		}, {
   170  			provider: "ec2",
   171  			expected: []string{
   172  				"type", "ca-cert", "state-port", "api-port", "syslog-port", "rsyslog-ca-cert", "rsyslog-ca-key",
   173  				"region"},
   174  		},
   175  	} {
   176  		c.Logf("%d: %s provider", i, test.provider)
   177  		fields, err := environmentmanager.RestrictedProviderFields(s.envmanager, test.provider)
   178  		c.Check(err, jc.ErrorIsNil)
   179  		c.Check(fields, jc.SameContents, test.expected)
   180  	}
   181  }
   182  
   183  func (s *envManagerSuite) TestConfigSkeleton(c *gc.C) {
   184  	s.setAPIUser(c, names.NewUserTag("non-admin@remote"))
   185  
   186  	_, err := s.envmanager.ConfigSkeleton(
   187  		params.EnvironmentSkeletonConfigArgs{Provider: "ec2"})
   188  	c.Check(err, gc.ErrorMatches, `provider value "ec2" not valid`)
   189  	_, err = s.envmanager.ConfigSkeleton(
   190  		params.EnvironmentSkeletonConfigArgs{Region: "the sun"})
   191  	c.Check(err, gc.ErrorMatches, `region value "the sun" not valid`)
   192  
   193  	skeleton, err := s.envmanager.ConfigSkeleton(params.EnvironmentSkeletonConfigArgs{})
   194  	c.Assert(err, jc.ErrorIsNil)
   195  
   196  	// The apiPort changes every test run as the dummy provider
   197  	// looks for a random open port.
   198  	apiPort := s.Environ.Config().APIPort()
   199  
   200  	c.Assert(skeleton.Config, jc.DeepEquals, params.EnvironConfig{
   201  		"type":        "dummy",
   202  		"ca-cert":     coretesting.CACert,
   203  		"state-port":  1234,
   204  		"api-port":    apiPort,
   205  		"syslog-port": 2345,
   206  	})
   207  }
   208  
   209  func (s *envManagerSuite) TestCreateEnvironmentValidatesConfig(c *gc.C) {
   210  	admin := s.AdminUserTag(c)
   211  	s.setAPIUser(c, admin)
   212  	args := s.createArgs(c, admin)
   213  	delete(args.Config, "state-server")
   214  	_, err := s.envmanager.CreateEnvironment(args)
   215  	c.Assert(err, gc.ErrorMatches, "provider validation failed: state-server: expected bool, got nothing")
   216  }
   217  
   218  func (s *envManagerSuite) TestCreateEnvironmentBadConfig(c *gc.C) {
   219  	owner := names.NewUserTag("external@remote")
   220  	s.setAPIUser(c, owner)
   221  	for i, test := range []struct {
   222  		key      string
   223  		value    interface{}
   224  		errMatch string
   225  	}{
   226  		{
   227  			key:      "uuid",
   228  			value:    "anything",
   229  			errMatch: `uuid is generated, you cannot specify one`,
   230  		}, {
   231  			key:      "type",
   232  			value:    "fake",
   233  			errMatch: `specified type "fake" does not match apiserver "dummy"`,
   234  		}, {
   235  			key:      "ca-cert",
   236  			value:    coretesting.OtherCACert,
   237  			errMatch: `(?s)specified ca-cert ".*" does not match apiserver ".*"`,
   238  		}, {
   239  			key:      "state-port",
   240  			value:    9876,
   241  			errMatch: `specified state-port "9876" does not match apiserver "1234"`,
   242  		}, {
   243  			// The api-port is dynamic, but always in user-space, so > 1024.
   244  			key:      "api-port",
   245  			value:    123,
   246  			errMatch: `specified api-port "123" does not match apiserver ".*"`,
   247  		}, {
   248  			key:      "syslog-port",
   249  			value:    1234,
   250  			errMatch: `specified syslog-port "1234" does not match apiserver "2345"`,
   251  		}, {
   252  			key:      "rsyslog-ca-cert",
   253  			value:    "some-cert",
   254  			errMatch: `specified rsyslog-ca-cert "some-cert" does not match apiserver ".*"`,
   255  		}, {
   256  			key:      "rsyslog-ca-key",
   257  			value:    "some-key",
   258  			errMatch: `specified rsyslog-ca-key "some-key" does not match apiserver ".*"`,
   259  		},
   260  	} {
   261  		c.Logf("%d: %s", i, test.key)
   262  		args := s.createArgs(c, owner)
   263  		args.Config[test.key] = test.value
   264  		_, err := s.envmanager.CreateEnvironment(args)
   265  		c.Assert(err, gc.ErrorMatches, test.errMatch)
   266  
   267  	}
   268  }
   269  
   270  func (s *envManagerSuite) TestCreateEnvironmentSameAgentVersion(c *gc.C) {
   271  	admin := s.AdminUserTag(c)
   272  	s.setAPIUser(c, admin)
   273  	args := s.createArgsForVersion(c, admin, version.Current.Number.String())
   274  	_, err := s.envmanager.CreateEnvironment(args)
   275  	c.Assert(err, jc.ErrorIsNil)
   276  }
   277  
   278  func (s *envManagerSuite) TestCreateEnvironmentBadAgentVersion(c *gc.C) {
   279  	admin := s.AdminUserTag(c)
   280  	s.setAPIUser(c, admin)
   281  
   282  	bigger := version.Current.Number
   283  	bigger.Minor += 1
   284  
   285  	smaller := version.Current.Number
   286  	smaller.Minor -= 1
   287  
   288  	for i, test := range []struct {
   289  		value    interface{}
   290  		errMatch string
   291  	}{
   292  		{
   293  			value:    42,
   294  			errMatch: `creating config from values failed: agent-version: expected string, got int\(42\)`,
   295  		}, {
   296  			value:    "not a number",
   297  			errMatch: `creating config from values failed: invalid agent version in environment configuration: "not a number"`,
   298  		}, {
   299  			value:    bigger.String(),
   300  			errMatch: "agent-version cannot be greater than the server: .*",
   301  		}, {
   302  			value:    smaller.String(),
   303  			errMatch: "no tools found for version .*",
   304  		},
   305  	} {
   306  		c.Logf("test %d", i)
   307  		args := s.createArgsForVersion(c, admin, test.value)
   308  		_, err := s.envmanager.CreateEnvironment(args)
   309  		c.Check(err, gc.ErrorMatches, test.errMatch)
   310  	}
   311  }
   312  
   313  func (s *envManagerSuite) TestListEnvironmentsForSelf(c *gc.C) {
   314  	user := names.NewUserTag("external@remote")
   315  	s.setAPIUser(c, user)
   316  	result, err := s.envmanager.ListEnvironments(params.Entity{user.String()})
   317  	c.Assert(err, jc.ErrorIsNil)
   318  	c.Assert(result.UserEnvironments, gc.HasLen, 0)
   319  }
   320  
   321  func (s *envManagerSuite) TestListEnvironmentsForSelfLocalUser(c *gc.C) {
   322  	// When the user's credentials cache stores the simple name, but the
   323  	// api server converts it to a fully qualified name.
   324  	user := names.NewUserTag("local-user")
   325  	s.setAPIUser(c, names.NewUserTag("local-user@local"))
   326  	result, err := s.envmanager.ListEnvironments(params.Entity{user.String()})
   327  	c.Assert(err, jc.ErrorIsNil)
   328  	c.Assert(result.UserEnvironments, gc.HasLen, 0)
   329  }
   330  
   331  func (s *envManagerSuite) checkEnvironmentMatches(c *gc.C, env params.Environment, expected *state.Environment) {
   332  	c.Check(env.Name, gc.Equals, expected.Name())
   333  	c.Check(env.UUID, gc.Equals, expected.UUID())
   334  	c.Check(env.OwnerTag, gc.Equals, expected.Owner().String())
   335  }
   336  
   337  func (s *envManagerSuite) TestListEnvironmentsAdminSelf(c *gc.C) {
   338  	user := s.AdminUserTag(c)
   339  	s.setAPIUser(c, user)
   340  	result, err := s.envmanager.ListEnvironments(params.Entity{user.String()})
   341  	c.Assert(err, jc.ErrorIsNil)
   342  	c.Assert(result.UserEnvironments, gc.HasLen, 1)
   343  	expected, err := s.State.Environment()
   344  	c.Assert(err, jc.ErrorIsNil)
   345  	s.checkEnvironmentMatches(c, result.UserEnvironments[0].Environment, expected)
   346  }
   347  
   348  func (s *envManagerSuite) TestListEnvironmentsAdminListsOther(c *gc.C) {
   349  	user := s.AdminUserTag(c)
   350  	s.setAPIUser(c, user)
   351  	other := names.NewUserTag("external@remote")
   352  	result, err := s.envmanager.ListEnvironments(params.Entity{other.String()})
   353  	c.Assert(err, jc.ErrorIsNil)
   354  	c.Assert(result.UserEnvironments, gc.HasLen, 0)
   355  }
   356  
   357  func (s *envManagerSuite) TestListEnvironmentsDenied(c *gc.C) {
   358  	user := names.NewUserTag("external@remote")
   359  	s.setAPIUser(c, user)
   360  	other := names.NewUserTag("other@remote")
   361  	_, err := s.envmanager.ListEnvironments(params.Entity{other.String()})
   362  	c.Assert(err, gc.ErrorMatches, "permission denied")
   363  }
   364  
   365  type fakeProvider struct {
   366  	environs.EnvironProvider
   367  }
   368  
   369  func (*fakeProvider) Validate(cfg, old *config.Config) (*config.Config, error) {
   370  	return cfg, nil
   371  }
   372  
   373  func (*fakeProvider) PrepareForCreateEnvironment(cfg *config.Config) (*config.Config, error) {
   374  	return cfg, nil
   375  }
   376  
   377  func init() {
   378  	environs.RegisterProvider("fake", &fakeProvider{})
   379  }