From a90d503fce27807ef561b7f3c842decfd2a37709 Mon Sep 17 00:00:00 2001 From: Angus Lees Date: Fri, 10 Oct 2014 00:22:01 +1100 Subject: [PATCH] Read user/pass from config and authenticate to OpenStack --- pkg/cloudprovider/openstack/openstack.go | 64 +++++++++++++++++-- pkg/cloudprovider/openstack/openstack_test.go | 31 ++++++++- 2 files changed, 89 insertions(+), 6 deletions(-) diff --git a/pkg/cloudprovider/openstack/openstack.go b/pkg/cloudprovider/openstack/openstack.go index 6e2ef1bb6bf..d4b8b8c2c7d 100644 --- a/pkg/cloudprovider/openstack/openstack.go +++ b/pkg/cloudprovider/openstack/openstack.go @@ -17,22 +17,78 @@ limitations under the License. package openstack import ( + "fmt" "io" + "code.google.com/p/gcfg" + "github.com/rackspace/gophercloud" + "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider" ) // OpenStack is an implementation of cloud provider Interface for OpenStack. -type OpenStack struct {} +type OpenStack struct { + provider string + authOpt gophercloud.AuthOptions + region string + access *gophercloud.Access +} + +type Config struct { + Global struct { + AuthUrl string + Username, Password string + ApiKey string + TenantId, TenantName string + Region string + } +} func init() { cloudprovider.RegisterCloudProvider("openstack", func(config io.Reader) (cloudprovider.Interface, error) { - return newOpenStack(config) + cfg, err := readConfig(config) + if err != nil { + return nil, err + } + return newOpenStack(cfg) }) } -func newOpenStack(config io.Reader) (*OpenStack, error) { - return &OpenStack{}, nil +func (cfg Config) toAuthOptions() gophercloud.AuthOptions { + return gophercloud.AuthOptions{ + Username: cfg.Global.Username, + Password: cfg.Global.Password, + ApiKey: cfg.Global.ApiKey, + TenantId: cfg.Global.TenantId, + TenantName: cfg.Global.TenantName, + + // Persistent service, so we need to be able to renew tokens + AllowReauth: true, + } +} + +func readConfig(config io.Reader) (Config, error) { + if config == nil { + err := fmt.Errorf("No OpenStack cloud provider config file given") + return Config{}, err + } + + var cfg Config + err := gcfg.ReadInto(&cfg, config) + return cfg, err +} + +func newOpenStack(cfg Config) (*OpenStack, error) { + os := OpenStack{ + provider: cfg.Global.AuthUrl, + authOpt: cfg.toAuthOptions(), + region: cfg.Global.Region, + } + + access, err := gophercloud.Authenticate(os.provider, os.authOpt) + os.access = access + + return &os, err } func (os *OpenStack) TCPLoadBalancer() (cloudprovider.TCPLoadBalancer, bool) { diff --git a/pkg/cloudprovider/openstack/openstack_test.go b/pkg/cloudprovider/openstack/openstack_test.go index 41f99ab93e9..079391cbb4c 100644 --- a/pkg/cloudprovider/openstack/openstack_test.go +++ b/pkg/cloudprovider/openstack/openstack_test.go @@ -22,8 +22,35 @@ import ( ) func TestNewOpenStack(t *testing.T) { - _, err := newOpenStack(strings.NewReader("")) + _, err := readConfig(nil) + if err == nil { + t.Errorf("Should fail when no config is provided: %s", err) + } + + cfg, err := readConfig(strings.NewReader(` +[Global] +authurl = http://auth.url +username = user +`)) if err != nil { - t.Errorf("Should succeed when a valid config is provided: %s", err) + t.Fatalf("Should succeed when a valid config is provided: %s", err) + } + if cfg.Global.AuthUrl != "http://auth.url" { + t.Errorf("incorrect authurl: %s", cfg.Global.AuthUrl) + } +} + +func TestToAuthOptions(t *testing.T) { + cfg := Config{} + cfg.Global.Username = "user" + // etc. + + ao := cfg.toAuthOptions() + + if !ao.AllowReauth { + t.Errorf("Will need to be able to reauthenticate") + } + if ao.Username != cfg.Global.Username { + t.Errorf("Username %s != %s", ao.Username, cfg.Global.Username) } }