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 }