| Left: | ||
| Right: |
| LEFT | RIGHT |
|---|---|
| 1 package openstack | 1 package openstack |
| 2 | 2 |
| 3 import ( | 3 import ( |
| 4 "fmt" | 4 "fmt" |
| 5 "launchpad.net/juju-core/environs/config" | 5 "launchpad.net/juju-core/environs/config" |
| 6 "launchpad.net/juju-core/schema" | 6 "launchpad.net/juju-core/schema" |
| 7 "os" | 7 "os" |
| 8 ) | 8 ) |
| 9 | 9 |
| 10 var configChecker = schema.StrictFieldMap( | 10 var configChecker = schema.StrictFieldMap( |
| 11 schema.Fields{ | 11 schema.Fields{ |
| 12 » » "username": schema.String(), | 12 » » "username": schema.String(), |
| 13 » » "password": schema.String(), | 13 » » "password": schema.String(), |
| 14 » » "region": schema.String(), | 14 » » "tenant-name": schema.String(), |
| 15 » » "tenant-id": schema.String(), | 15 » » "auth-url": schema.String(), |
| 16 » » "identity-url": schema.String(), | 16 » » "region": schema.String(), |
|
gz
2012/11/21 17:28:20
Where possible, use the existing keys names that p
| |
| 17 » » "container": schema.String(), | 17 » » "container": schema.String(), |
| 18 }, | 18 }, |
| 19 schema.Defaults{ | 19 schema.Defaults{ |
| 20 » » "username": "", | 20 » » "username": "", |
| 21 » » "password": "", | 21 » » "password": "", |
| 22 » » "region": "", | 22 » » "tenant-name": "", |
| 23 » » "tenant-id": "", | 23 » » "auth-url": "", |
| 24 » » "identity-url": "", | 24 » » "region": "", |
| 25 » » "container": "", | 25 » » "container": "", |
| 26 }, | 26 }, |
| 27 ) | 27 ) |
| 28 | 28 |
| 29 type environConfig struct { | 29 type environConfig struct { |
| 30 *config.Config | 30 *config.Config |
| 31 attrs map[string]interface{} | 31 attrs map[string]interface{} |
| 32 } | 32 } |
| 33 | 33 |
| 34 func (c *environConfig) region() string { | 34 func (c *environConfig) region() string { |
| 35 return c.attrs["region"].(string) | 35 return c.attrs["region"].(string) |
| 36 } | 36 } |
| 37 | 37 |
| 38 func (c *environConfig) username() string { | 38 func (c *environConfig) username() string { |
| 39 return c.attrs["username"].(string) | 39 return c.attrs["username"].(string) |
| 40 } | 40 } |
| 41 | 41 |
| 42 func (c *environConfig) password() string { | 42 func (c *environConfig) password() string { |
| 43 return c.attrs["password"].(string) | 43 return c.attrs["password"].(string) |
| 44 } | 44 } |
| 45 | 45 |
| 46 func (c *environConfig) tenantId() string { | 46 func (c *environConfig) tenantName() string { |
|
gz
2012/11/21 17:28:20
Using tenant-id vs. tenant-name is something we'll
jameinel
2012/11/22 07:19:49
Just to follow up on this, "tenant-name" is what w
| |
| 47 » return c.attrs["tenant-id"].(string) | 47 » return c.attrs["tenant-name"].(string) |
| 48 } | 48 } |
| 49 | 49 |
| 50 func (c *environConfig) identityURL() string { | 50 func (c *environConfig) authURL() string { |
|
gz
2012/11/21 17:28:20
As above, 'auth-url' instead.
| |
| 51 » return c.attrs["identity-url"].(string) | 51 » return c.attrs["auth-url"].(string) |
| 52 } | 52 } |
| 53 | 53 |
| 54 func (c *environConfig) container() string { | 54 func (c *environConfig) container() string { |
|
niemeyer
2012/11/22 12:54:14
As we discussed, let's use controlBucket/"control-
dimitern
2012/11/22 13:13:17
Done.
| |
| 55 return c.attrs["container"].(string) | 55 return c.attrs["container"].(string) |
| 56 } | 56 } |
| 57 | 57 |
| 58 func (p environProvider) newConfig(cfg *config.Config) (*environConfig, error) { | 58 func (p environProvider) newConfig(cfg *config.Config) (*environConfig, error) { |
| 59 valid, err := p.Validate(cfg, nil) | 59 valid, err := p.Validate(cfg, nil) |
| 60 if err != nil { | 60 if err != nil { |
| 61 return nil, err | 61 return nil, err |
| 62 } | 62 } |
| 63 return &environConfig{valid, valid.UnknownAttrs()}, nil | 63 return &environConfig{valid, valid.UnknownAttrs()}, nil |
| 64 } | 64 } |
| 65 | 65 |
| 66 func (p environProvider) Validate(cfg, old *config.Config) (valid *config.Config , err error) { | 66 func (p environProvider) Validate(cfg, old *config.Config) (valid *config.Config , err error) { |
|
gz
2012/11/21 17:28:20
Having one big function in the style of the curren
| |
| 67 v, err := configChecker.Coerce(cfg.UnknownAttrs(), nil) | 67 v, err := configChecker.Coerce(cfg.UnknownAttrs(), nil) |
| 68 if err != nil { | 68 if err != nil { |
| 69 return nil, err | 69 return nil, err |
| 70 } | 70 } |
| 71 ecfg := &environConfig{cfg, v.(map[string]interface{})} | 71 ecfg := &environConfig{cfg, v.(map[string]interface{})} |
| 72 if ecfg.username() == "" || | 72 if ecfg.username() == "" || |
| 73 ecfg.password() == "" || | 73 ecfg.password() == "" || |
| 74 » » ecfg.tenantId() == "" || | 74 » » ecfg.tenantName() == "" || |
| 75 » » ecfg.identityURL() == "" { | 75 » » ecfg.authURL() == "" { |
|
niemeyer
2012/11/22 12:54:14
Can we please have these in the same line? We have
dimitern
2012/11/22 13:13:17
Done.
| |
| 76 » » // TODO: get goose client to handle this | 76 » » // TODO(dimitern): get goose client to handle this |
| 77 auth, err := dummyEnvAuth() | 77 auth, err := dummyEnvAuth() |
| 78 » » if err != nil || | 78 » » if err != nil { |
| 79 » » » ecfg.username() != "" || | 79 » » » return nil, fmt.Errorf("environment has no username, pas sword, tenant-name, or auth-url") |
|
rog
2012/11/21 17:26:12
perhaps these checks should be in dummyEnvAuth, an
|
niemeyer
2012/11/22 12:54:14
"OpenStack environment requires options username,
dimitern
2012/11/22 13:13:17
Done.
|
| 80 » » » ecfg.password() != "" || | |
| 81 » » » ecfg.tenantId() != "" || | |
| 82 » » » ecfg.identityURL() != "" { | |
| 83 » » » return nil, fmt.Errorf("environment has no username, pas sword, tenant-id, or identity-url") | |
| 84 } | 80 } |
| 85 ecfg.attrs["username"] = auth.username | 81 ecfg.attrs["username"] = auth.username |
| 86 ecfg.attrs["password"] = auth.password | 82 ecfg.attrs["password"] = auth.password |
| 87 » » ecfg.attrs["tenant-id"] = auth.tenantId | 83 » » ecfg.attrs["tenant-name"] = auth.tenantName |
| 88 » » ecfg.attrs["identity-url"] = auth.identityURL | 84 » » ecfg.attrs["auth-url"] = auth.authURL |
| 89 } | 85 } |
| 90 // We cannot validate the region name, since each OS installation | 86 // We cannot validate the region name, since each OS installation |
| 91 // can have its own region names - only after authentication the | 87 // can have its own region names - only after authentication the |
| 92 // region names are known (from the service endpoints) | 88 // region names are known (from the service endpoints) |
| 93 | 89 |
| 94 if old != nil { | 90 if old != nil { |
| 95 attrs := old.UnknownAttrs() | 91 attrs := old.UnknownAttrs() |
| 96 if region, _ := attrs["region"].(string); ecfg.region() != regio n { | 92 if region, _ := attrs["region"].(string); ecfg.region() != regio n { |
| 97 return nil, fmt.Errorf("cannot change region from %q to %q", region, ecfg.region()) | 93 return nil, fmt.Errorf("cannot change region from %q to %q", region, ecfg.region()) |
| 98 } | 94 } |
| 99 if container, _ := attrs["container"].(string); ecfg.container() != container { | 95 if container, _ := attrs["container"].(string); ecfg.container() != container { |
| 100 return nil, fmt.Errorf("cannot change container from %q to %q", container, ecfg.container()) | 96 return nil, fmt.Errorf("cannot change container from %q to %q", container, ecfg.container()) |
| 101 } | 97 } |
| 102 } | 98 } |
| 103 | 99 |
| 104 switch cfg.FirewallMode() { | 100 switch cfg.FirewallMode() { |
| 105 case config.FwDefault: | 101 case config.FwDefault: |
| 106 ecfg.attrs["firewall-mode"] = config.FwInstance | 102 ecfg.attrs["firewall-mode"] = config.FwInstance |
| 107 case config.FwInstance, config.FwGlobal: | 103 case config.FwInstance, config.FwGlobal: |
| 108 default: | 104 default: |
| 109 return nil, fmt.Errorf("unsupported firewall mode: %q", cfg.Fire wallMode()) | 105 return nil, fmt.Errorf("unsupported firewall mode: %q", cfg.Fire wallMode()) |
| 110 } | 106 } |
| 111 | 107 |
| 112 return cfg.Apply(ecfg.attrs) | 108 return cfg.Apply(ecfg.attrs) |
| 113 } | 109 } |
| 114 | 110 |
| 115 // TODO: temporarily here, until goose client handles this | 111 // TODO(dimitern): temporarily here, until goose client handles this |
|
gz
2012/11/21 17:28:20
You should be able to use Credentials from the ide
| |
| 116 type dummyAuth struct { | 112 type dummyAuth struct { |
|
niemeyer
2012/11/22 12:54:14
Why dummy? This looks quite real. I think it shoul
dimitern
2012/11/22 13:13:17
This is here only because the goose identity packa
| |
| 117 » username, password, tenantId, identityURL string | 113 » username, password, tenantName, authURL string |
| 118 } | 114 } |
| 119 | 115 |
| 120 func dummyEnvAuth() (dummyAuth, error) { | 116 func dummyEnvAuth() (dummyAuth, error) { |
|
gz
2012/11/21 17:28:20
Just use CredentialsFromEnv from the goose identit
|
niemeyer
2012/11/22 12:54:14
getEnvAuth?
dimitern
2012/11/22 13:13:17
Done.
|
| 121 » return dummyAuth{ | 117 » auth := dummyAuth{ |
| 122 » » username: os.Getenv("OS_USERNAME"), | 118 » » username: os.Getenv("OS_USERNAME"), |
| 123 » » password: os.Getenv("OS_PASSWORD"), | 119 » » password: os.Getenv("OS_PASSWORD"), |
| 124 » » tenantId: os.Getenv("OS_TENANT_NAME"), | 120 » » tenantName: os.Getenv("OS_TENANT_NAME"), |
| 125 » » identityURL: os.Getenv("OS_AUTH_URL"), | 121 » » authURL: os.Getenv("OS_AUTH_URL"), |
| 126 » }, nil | 122 » } |
| 123 » if auth.username == "" || | |
| 124 » » auth.password == "" || | |
| 125 » » auth.tenantName == "" || | |
| 126 » » auth.authURL == "" { | |
|
niemeyer
2012/11/22 12:54:14
Same line as well, please.
dimitern
2012/11/22 13:13:17
Done.
| |
| 127 » » return auth, fmt.Errorf("missing username, password, tenant-name , or auth-url") | |
|
niemeyer
2012/11/22 12:54:14
This function can be simplified to return (auth en
| |
| 128 » } | |
| 129 » return auth, nil | |
| 127 } | 130 } |
| LEFT | RIGHT |