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 }