github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/cmd/juju/system/createenvironment_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package system_test 5 6 import ( 7 "io/ioutil" 8 "os" 9 "os/user" 10 11 "github.com/juju/cmd" 12 "github.com/juju/errors" 13 jc "github.com/juju/testing/checkers" 14 "github.com/juju/utils" 15 gc "gopkg.in/check.v1" 16 "gopkg.in/yaml.v1" 17 18 "github.com/juju/juju/apiserver/params" 19 "github.com/juju/juju/cmd/envcmd" 20 "github.com/juju/juju/cmd/juju/system" 21 "github.com/juju/juju/environs/configstore" 22 "github.com/juju/juju/feature" 23 "github.com/juju/juju/testing" 24 ) 25 26 type createSuite struct { 27 testing.FakeJujuHomeSuite 28 fake *fakeCreateClient 29 store configstore.Storage 30 serverUUID string 31 server configstore.EnvironInfo 32 } 33 34 var _ = gc.Suite(&createSuite{}) 35 36 func (s *createSuite) SetUpTest(c *gc.C) { 37 s.FakeJujuHomeSuite.SetUpTest(c) 38 s.SetFeatureFlags(feature.JES) 39 s.fake = &fakeCreateClient{} 40 store := configstore.Default 41 s.AddCleanup(func(*gc.C) { 42 configstore.Default = store 43 }) 44 s.store = configstore.NewMem() 45 configstore.Default = func() (configstore.Storage, error) { 46 return s.store, nil 47 } 48 // Set up the current environment, and write just enough info 49 // so we don't try to refresh 50 envName := "test-master" 51 s.serverUUID = "fake-server-uuid" 52 info := s.store.CreateInfo(envName) 53 info.SetAPIEndpoint(configstore.APIEndpoint{ 54 Addresses: []string{"localhost"}, 55 CACert: testing.CACert, 56 EnvironUUID: s.serverUUID, 57 ServerUUID: s.serverUUID, 58 }) 59 info.SetAPICredentials(configstore.APICredentials{User: "bob", Password: "sekrit"}) 60 err := info.Write() 61 c.Assert(err, jc.ErrorIsNil) 62 s.server = info 63 err = envcmd.WriteCurrentEnvironment(envName) 64 c.Assert(err, jc.ErrorIsNil) 65 } 66 67 func (s *createSuite) run(c *gc.C, args ...string) (*cmd.Context, error) { 68 command := system.NewCreateEnvironmentCommand(s.fake) 69 return testing.RunCommand(c, envcmd.WrapSystem(command), args...) 70 } 71 72 func (s *createSuite) TestInit(c *gc.C) { 73 74 for i, test := range []struct { 75 args []string 76 err string 77 name string 78 owner string 79 path string 80 values map[string]string 81 }{ 82 { 83 err: "environment name is required", 84 }, { 85 args: []string{"new-env"}, 86 name: "new-env", 87 }, { 88 args: []string{"new-env", "--owner", "foo"}, 89 name: "new-env", 90 owner: "foo", 91 }, { 92 args: []string{"new-env", "--owner", "not=valid"}, 93 err: `"not=valid" is not a valid user`, 94 }, { 95 args: []string{"new-env", "key=value", "key2=value2"}, 96 name: "new-env", 97 values: map[string]string{"key": "value", "key2": "value2"}, 98 }, { 99 args: []string{"new-env", "key=value", "key=value2"}, 100 err: `key "key" specified more than once`, 101 }, { 102 args: []string{"new-env", "another"}, 103 err: `expected "key=value", got "another"`, 104 }, { 105 args: []string{"new-env", "--config", "some-file"}, 106 name: "new-env", 107 path: "some-file", 108 }, 109 } { 110 c.Logf("test %d", i) 111 create := &system.CreateEnvironmentCommand{} 112 err := testing.InitCommand(create, test.args) 113 if test.err != "" { 114 c.Assert(err, gc.ErrorMatches, test.err) 115 continue 116 } 117 118 c.Assert(err, jc.ErrorIsNil) 119 c.Assert(create.Name(), gc.Equals, test.name) 120 c.Assert(create.Owner(), gc.Equals, test.owner) 121 c.Assert(create.ConfigFile().Path, gc.Equals, test.path) 122 // The config value parse method returns an empty map 123 // if there were no values 124 if len(test.values) == 0 { 125 c.Assert(create.ConfValues(), gc.HasLen, 0) 126 } else { 127 c.Assert(create.ConfValues(), jc.DeepEquals, test.values) 128 } 129 } 130 } 131 132 func (s *createSuite) TestCreateExistingName(c *gc.C) { 133 // Make a configstore entry with the same name. 134 info := s.store.CreateInfo("test") 135 err := info.Write() 136 c.Assert(err, jc.ErrorIsNil) 137 138 _, err = s.run(c, "test") 139 c.Assert(err, gc.ErrorMatches, `environment "test" already exists`) 140 } 141 142 func (s *createSuite) TestComandLineConfigPassedThrough(c *gc.C) { 143 _, err := s.run(c, "test", "account=magic", "cloud=special") 144 c.Assert(err, jc.ErrorIsNil) 145 146 c.Assert(s.fake.config["account"], gc.Equals, "magic") 147 c.Assert(s.fake.config["cloud"], gc.Equals, "special") 148 } 149 150 func (s *createSuite) TestConfigFileValuesPassedThrough(c *gc.C) { 151 config := map[string]string{ 152 "account": "magic", 153 "cloud": "9", 154 } 155 bytes, err := yaml.Marshal(config) 156 c.Assert(err, jc.ErrorIsNil) 157 file, err := ioutil.TempFile(c.MkDir(), "") 158 c.Assert(err, jc.ErrorIsNil) 159 file.Write(bytes) 160 file.Close() 161 162 _, err = s.run(c, "test", "--config", file.Name()) 163 c.Assert(err, jc.ErrorIsNil) 164 c.Assert(s.fake.config["account"], gc.Equals, "magic") 165 c.Assert(s.fake.config["cloud"], gc.Equals, "9") 166 } 167 168 func (s *createSuite) TestConfigFileFormatError(c *gc.C) { 169 file, err := ioutil.TempFile(c.MkDir(), "") 170 c.Assert(err, jc.ErrorIsNil) 171 file.Write(([]byte)("not: valid: yaml")) 172 file.Close() 173 174 _, err = s.run(c, "test", "--config", file.Name()) 175 c.Assert(err, gc.ErrorMatches, `YAML error: .*`) 176 } 177 178 func (s *createSuite) TestConfigFileDoesntExist(c *gc.C) { 179 _, err := s.run(c, "test", "--config", "missing-file") 180 errMsg := ".*" + utils.NoSuchFileErrRegexp 181 c.Assert(err, gc.ErrorMatches, errMsg) 182 } 183 184 func (s *createSuite) TestConfigValuePrecedence(c *gc.C) { 185 config := map[string]string{ 186 "account": "magic", 187 "cloud": "9", 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(), "account=magic", "cloud=special") 197 c.Assert(err, jc.ErrorIsNil) 198 c.Assert(s.fake.config["account"], gc.Equals, "magic") 199 c.Assert(s.fake.config["cloud"], gc.Equals, "special") 200 } 201 202 var setConfigSpecialCaseDefaultsTests = []struct { 203 about string 204 userEnvVar string 205 userCurrent func() (*user.User, error) 206 config map[string]interface{} 207 expectConfig map[string]interface{} 208 expectError string 209 }{{ 210 about: "use env var if available", 211 userEnvVar: "bob", 212 config: map[string]interface{}{ 213 "name": "envname", 214 "type": "local", 215 }, 216 expectConfig: map[string]interface{}{ 217 "name": "envname", 218 "type": "local", 219 "namespace": "bob-envname", 220 }, 221 }, { 222 about: "fall back to user.Current", 223 userCurrent: func() (*user.User, error) { 224 return &user.User{Username: "bob"}, nil 225 }, 226 config: map[string]interface{}{ 227 "name": "envname", 228 "type": "local", 229 }, 230 expectConfig: map[string]interface{}{ 231 "name": "envname", 232 "type": "local", 233 "namespace": "bob-envname", 234 }, 235 }, { 236 about: "other provider types unaffected", 237 userEnvVar: "bob", 238 config: map[string]interface{}{ 239 "name": "envname", 240 "type": "dummy", 241 }, 242 expectConfig: map[string]interface{}{ 243 "name": "envname", 244 "type": "dummy", 245 }, 246 }, { 247 about: "explicit namespace takes precedence", 248 userCurrent: func() (*user.User, error) { 249 return &user.User{Username: "bob"}, nil 250 }, 251 config: map[string]interface{}{ 252 "name": "envname", 253 "namespace": "something", 254 "type": "local", 255 }, 256 expectConfig: map[string]interface{}{ 257 "name": "envname", 258 "namespace": "something", 259 "type": "local", 260 }, 261 }, { 262 about: "user.Current returns error", 263 userCurrent: func() (*user.User, error) { 264 return nil, errors.New("an error") 265 }, 266 config: map[string]interface{}{ 267 "name": "envname", 268 "type": "local", 269 }, 270 expectError: "failed to determine username for namespace: an error", 271 }} 272 273 func (s *createSuite) TestSetConfigSpecialCaseDefaults(c *gc.C) { 274 noUserCurrent := func() (*user.User, error) { 275 panic("should not be called") 276 } 277 s.PatchValue(system.UserCurrent, noUserCurrent) 278 // We test setConfigSpecialCaseDefaults independently 279 // because we can't use the local provider in the tests. 280 for i, test := range setConfigSpecialCaseDefaultsTests { 281 c.Logf("test %d: %s", i, test.about) 282 os.Setenv("USER", test.userEnvVar) 283 if test.userCurrent != nil { 284 *system.UserCurrent = test.userCurrent 285 } else { 286 *system.UserCurrent = noUserCurrent 287 } 288 err := system.SetConfigSpecialCaseDefaults(test.config["name"].(string), test.config) 289 if test.expectError != "" { 290 c.Assert(err, gc.ErrorMatches, test.expectError) 291 } else { 292 c.Assert(err, gc.IsNil) 293 c.Assert(test.config, jc.DeepEquals, test.expectConfig) 294 } 295 } 296 297 } 298 299 func (s *createSuite) TestCreateErrorRemoveConfigstoreInfo(c *gc.C) { 300 s.fake.err = errors.New("bah humbug") 301 302 _, err := s.run(c, "test") 303 c.Assert(err, gc.ErrorMatches, "bah humbug") 304 305 _, err = s.store.ReadInfo("test") 306 c.Assert(err, gc.ErrorMatches, `environment "test" not found`) 307 } 308 309 func (s *createSuite) TestCreateStoresValues(c *gc.C) { 310 s.fake.env = params.Environment{ 311 Name: "test", 312 UUID: "fake-env-uuid", 313 OwnerTag: "ignored-for-now", 314 ServerUUID: s.serverUUID, 315 } 316 _, err := s.run(c, "test") 317 c.Assert(err, jc.ErrorIsNil) 318 319 info, err := s.store.ReadInfo("test") 320 c.Assert(err, jc.ErrorIsNil) 321 // Stores the credentials of the original environment 322 c.Assert(info.APICredentials(), jc.DeepEquals, s.server.APICredentials()) 323 endpoint := info.APIEndpoint() 324 expected := s.server.APIEndpoint() 325 c.Assert(endpoint.Addresses, jc.DeepEquals, expected.Addresses) 326 c.Assert(endpoint.Hostnames, jc.DeepEquals, expected.Hostnames) 327 c.Assert(endpoint.ServerUUID, gc.Equals, expected.ServerUUID) 328 c.Assert(endpoint.CACert, gc.Equals, expected.CACert) 329 c.Assert(endpoint.EnvironUUID, gc.Equals, "fake-env-uuid") 330 } 331 332 func (s *createSuite) TestNoEnvCacheOtherUser(c *gc.C) { 333 s.fake.env = params.Environment{ 334 Name: "test", 335 UUID: "fake-env-uuid", 336 OwnerTag: "ignored-for-now", 337 ServerUUID: s.serverUUID, 338 } 339 _, err := s.run(c, "test", "--owner", "zeus") 340 c.Assert(err, jc.ErrorIsNil) 341 342 _, err = s.store.ReadInfo("test") 343 c.Assert(err, gc.ErrorMatches, `environment "test" not found`) 344 } 345 346 // fakeCreateClient is used to mock out the behavior of the real 347 // CreateEnvironment command. 348 type fakeCreateClient struct { 349 owner string 350 account map[string]interface{} 351 config map[string]interface{} 352 err error 353 env params.Environment 354 } 355 356 var _ system.CreateEnvironmentAPI = (*fakeCreateClient)(nil) 357 358 func (*fakeCreateClient) Close() error { 359 return nil 360 } 361 362 func (*fakeCreateClient) ConfigSkeleton(provider, region string) (params.EnvironConfig, error) { 363 return params.EnvironConfig{ 364 "type": "dummy", 365 "state-server": false, 366 }, nil 367 } 368 func (f *fakeCreateClient) CreateEnvironment(owner string, account, config map[string]interface{}) (params.Environment, error) { 369 var env params.Environment 370 if f.err != nil { 371 return env, f.err 372 } 373 f.owner = owner 374 f.account = account 375 f.config = config 376 return f.env, nil 377 }