From bef63846afe74e8e73f3d5f7213dac27b3773218 Mon Sep 17 00:00:00 2001 From: Devin Carlen Date: Tue, 31 Dec 2013 01:11:23 -0800 Subject: [PATCH 1/3] Add support for standard OpenStack environment variables --- builder/openstack/access_config.go | 40 +++++++++++------------------- common/config.go | 9 +++++++ 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/builder/openstack/access_config.go b/builder/openstack/access_config.go index 947e58854..dab5989bf 100644 --- a/builder/openstack/access_config.go +++ b/builder/openstack/access_config.go @@ -2,6 +2,7 @@ package openstack import ( "fmt" + "github.com/mitchellh/packer/common" "github.com/mitchellh/packer/packer" "github.com/rackspace/gophercloud" "net/http" @@ -22,39 +23,26 @@ type AccessConfig struct { // Auth returns a valid Auth object for access to openstack services, or // an error if the authentication couldn't be resolved. func (c *AccessConfig) Auth() (gophercloud.AccessProvider, error) { - username := c.Username - password := c.Password - project := c.Project - provider := c.Provider - proxy := c.ProxyUrl - - if username == "" { - username = os.Getenv("SDK_USERNAME") - } - if password == "" { - password = os.Getenv("SDK_PASSWORD") - } - if project == "" { - project = os.Getenv("SDK_PROJECT") - } - if provider == "" { - provider = os.Getenv("SDK_PROVIDER") - } + c.Username = common.CoalesceVals(c.Username, os.Getenv("SDK_USERNAME"), os.Getenv("OS_USERNAME")) + c.Password = common.CoalesceVals(c.Password, os.Getenv("SDK_PASSWORD"), os.Getenv("OS_PASSWORD")) + c.Project = common.CoalesceVals(c.Project, os.Getenv("SDK_PROJECT"), os.Getenv("OS_TENANT_NAME")) + c.Provider = common.CoalesceVals(c.Provider, os.Getenv("SDK_PROVIDER"), os.Getenv("OS_AUTH_URL")) + c.RawRegion = common.CoalesceVals(c.RawRegion, os.Getenv("SDK_REGION"), os.Getenv("OS_REGION_NAME")) authoptions := gophercloud.AuthOptions{ - Username: username, - Password: password, + Username: c.Username, + Password: c.Password, AllowReauth: true, } - if project != "" { - authoptions.TenantName = project + if c.Project != "" { + authoptions.TenantName = c.Project } // For corporate networks it may be the case where we want our API calls // to be sent through a separate HTTP proxy than external traffic. - if proxy != "" { - url, err := url.Parse(proxy) + if c.ProxyUrl != "" { + url, err := url.Parse(c.ProxyUrl) if err != nil { return nil, err } @@ -64,11 +52,11 @@ func (c *AccessConfig) Auth() (gophercloud.AccessProvider, error) { http.DefaultTransport = &http.Transport{Proxy: http.ProxyURL(url)} } - return gophercloud.Authenticate(provider, authoptions) + return gophercloud.Authenticate(c.Provider, authoptions) } func (c *AccessConfig) Region() string { - return c.RawRegion + return common.CoalesceVals(c.RawRegion, os.Getenv("SDK_REGION"), os.Getenv("OS_REGION_NAME")) } func (c *AccessConfig) Prepare(t *packer.ConfigTemplate) []error { diff --git a/common/config.go b/common/config.go index bcd17ee04..dab95d6a9 100644 --- a/common/config.go +++ b/common/config.go @@ -194,3 +194,12 @@ func decodeConfigHook(raws []interface{}) (mapstructure.DecodeHookFunc, error) { return v, nil }, nil } + +func CoalesceVals(vals ...string) string { + for _, el := range vals { + if el != "" { + return el + } + } + return "" +} From 828d7ebdca7e09375d48b132515663e6261aa299 Mon Sep 17 00:00:00 2001 From: Devin Carlen Date: Mon, 6 Jan 2014 13:41:30 -0800 Subject: [PATCH 2/3] Append /tokens suffix if not present for specific OpenStack authentication URLs --- builder/openstack/access_config.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/builder/openstack/access_config.go b/builder/openstack/access_config.go index dab5989bf..d41a29823 100644 --- a/builder/openstack/access_config.go +++ b/builder/openstack/access_config.go @@ -8,6 +8,7 @@ import ( "net/http" "net/url" "os" + "strings" ) // AccessConfig is for common configuration related to openstack access @@ -29,6 +30,13 @@ func (c *AccessConfig) Auth() (gophercloud.AccessProvider, error) { c.Provider = common.CoalesceVals(c.Provider, os.Getenv("SDK_PROVIDER"), os.Getenv("OS_AUTH_URL")) c.RawRegion = common.CoalesceVals(c.RawRegion, os.Getenv("SDK_REGION"), os.Getenv("OS_REGION_NAME")) + // OpenStack's auto-generated openrc.sh files do not append the suffix + // /tokens to the authentication URL. This ensures it is present when + // specifying the URL. + if strings.Contains(c.Provider, "://") && !strings.HasSuffix(c.Provider, "/tokens") { + c.Provider += "/tokens" + } + authoptions := gophercloud.AuthOptions{ Username: c.Username, Password: c.Password, @@ -84,7 +92,7 @@ func (c *AccessConfig) Prepare(t *packer.ConfigTemplate) []error { } } - if c.RawRegion == "" { + if c.Region() == "" { errs = append(errs, fmt.Errorf("region must be specified")) } From e7d7f9bbfd74632b786b44f2801f873e241e70b9 Mon Sep 17 00:00:00 2001 From: Devin Carlen Date: Mon, 6 Jan 2014 10:16:56 -0800 Subject: [PATCH 3/3] Add OpenStack API key support --- builder/openstack/access_config.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/builder/openstack/access_config.go b/builder/openstack/access_config.go index d41a29823..703c4e5cf 100644 --- a/builder/openstack/access_config.go +++ b/builder/openstack/access_config.go @@ -15,6 +15,7 @@ import ( type AccessConfig struct { Username string `mapstructure:"username"` Password string `mapstructure:"password"` + ApiKey string `mapstructure:"api_key"` Project string `mapstructure:"project"` Provider string `mapstructure:"provider"` RawRegion string `mapstructure:"region"` @@ -26,6 +27,7 @@ type AccessConfig struct { func (c *AccessConfig) Auth() (gophercloud.AccessProvider, error) { c.Username = common.CoalesceVals(c.Username, os.Getenv("SDK_USERNAME"), os.Getenv("OS_USERNAME")) c.Password = common.CoalesceVals(c.Password, os.Getenv("SDK_PASSWORD"), os.Getenv("OS_PASSWORD")) + c.ApiKey = common.CoalesceVals(c.ApiKey, os.Getenv("SDK_API_KEY")) c.Project = common.CoalesceVals(c.Project, os.Getenv("SDK_PROJECT"), os.Getenv("OS_TENANT_NAME")) c.Provider = common.CoalesceVals(c.Provider, os.Getenv("SDK_PROVIDER"), os.Getenv("OS_AUTH_URL")) c.RawRegion = common.CoalesceVals(c.RawRegion, os.Getenv("SDK_REGION"), os.Getenv("OS_REGION_NAME")) @@ -40,6 +42,7 @@ func (c *AccessConfig) Auth() (gophercloud.AccessProvider, error) { authoptions := gophercloud.AuthOptions{ Username: c.Username, Password: c.Password, + ApiKey: c.ApiKey, AllowReauth: true, } @@ -79,6 +82,7 @@ func (c *AccessConfig) Prepare(t *packer.ConfigTemplate) []error { templates := map[string]*string{ "username": &c.Username, "password": &c.Password, + "apiKey": &c.ApiKey, "provider": &c.Provider, }