2013-08-27 00:57:23 -04:00
|
|
|
package openstack
|
|
|
|
|
|
|
|
import (
|
2014-05-05 12:44:25 -04:00
|
|
|
"crypto/tls"
|
2013-08-27 00:57:23 -04:00
|
|
|
"fmt"
|
2013-12-31 04:11:23 -05:00
|
|
|
"github.com/mitchellh/packer/common"
|
2013-08-27 00:57:23 -04:00
|
|
|
"github.com/mitchellh/packer/packer"
|
|
|
|
"github.com/rackspace/gophercloud"
|
2013-11-19 12:03:35 -05:00
|
|
|
"net/http"
|
|
|
|
"net/url"
|
2013-08-27 00:57:23 -04:00
|
|
|
"os"
|
2014-01-06 16:41:30 -05:00
|
|
|
"strings"
|
2013-08-27 00:57:23 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
// AccessConfig is for common configuration related to openstack access
|
|
|
|
type AccessConfig struct {
|
2013-09-01 16:22:22 -04:00
|
|
|
Username string `mapstructure:"username"`
|
|
|
|
Password string `mapstructure:"password"`
|
2014-01-06 13:16:56 -05:00
|
|
|
ApiKey string `mapstructure:"api_key"`
|
2013-09-01 00:58:52 -04:00
|
|
|
Project string `mapstructure:"project"`
|
2013-09-01 16:22:22 -04:00
|
|
|
Provider string `mapstructure:"provider"`
|
|
|
|
RawRegion string `mapstructure:"region"`
|
2013-11-19 12:03:35 -05:00
|
|
|
ProxyUrl string `mapstructure:"proxy_url"`
|
2014-04-30 20:20:44 -04:00
|
|
|
TenantId string `mapstructure:"tenant_id"`
|
2014-05-05 12:44:25 -04:00
|
|
|
Insecure bool `mapstructure:"insecure"`
|
2013-08-27 00:57:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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) {
|
2014-04-22 00:34:03 -04:00
|
|
|
c.Username = common.ChooseString(c.Username, os.Getenv("SDK_USERNAME"), os.Getenv("OS_USERNAME"))
|
|
|
|
c.Password = common.ChooseString(c.Password, os.Getenv("SDK_PASSWORD"), os.Getenv("OS_PASSWORD"))
|
|
|
|
c.ApiKey = common.ChooseString(c.ApiKey, os.Getenv("SDK_API_KEY"))
|
|
|
|
c.Project = common.ChooseString(c.Project, os.Getenv("SDK_PROJECT"), os.Getenv("OS_TENANT_NAME"))
|
|
|
|
c.Provider = common.ChooseString(c.Provider, os.Getenv("SDK_PROVIDER"), os.Getenv("OS_AUTH_URL"))
|
|
|
|
c.RawRegion = common.ChooseString(c.RawRegion, os.Getenv("SDK_REGION"), os.Getenv("OS_REGION_NAME"))
|
2014-04-30 20:20:44 -04:00
|
|
|
c.TenantId = common.ChooseString(c.TenantId, os.Getenv("OS_TENANT_ID"))
|
2013-08-27 00:57:23 -04:00
|
|
|
|
2014-01-06 16:41:30 -05:00
|
|
|
// 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"
|
|
|
|
}
|
|
|
|
|
2013-08-27 00:57:23 -04:00
|
|
|
authoptions := gophercloud.AuthOptions{
|
|
|
|
AllowReauth: true,
|
|
|
|
|
2014-04-30 20:20:44 -04:00
|
|
|
ApiKey: c.ApiKey,
|
|
|
|
TenantId: c.TenantId,
|
|
|
|
TenantName: c.Project,
|
|
|
|
Username: c.Username,
|
|
|
|
Password: c.Password,
|
2013-09-02 13:22:14 -04:00
|
|
|
}
|
|
|
|
|
2014-05-05 12:44:25 -04:00
|
|
|
default_transport := &http.Transport{}
|
|
|
|
|
|
|
|
if c.Insecure {
|
|
|
|
cfg := new(tls.Config)
|
|
|
|
cfg.InsecureSkipVerify = true
|
|
|
|
default_transport.TLSClientConfig = cfg
|
|
|
|
}
|
|
|
|
|
2013-11-19 12:03:35 -05:00
|
|
|
// 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.
|
2013-12-31 04:11:23 -05:00
|
|
|
if c.ProxyUrl != "" {
|
|
|
|
url, err := url.Parse(c.ProxyUrl)
|
2013-11-19 12:03:35 -05:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// The gophercloud.Context has a UseCustomClient method which
|
|
|
|
// would allow us to override with a new instance of http.Client.
|
2014-05-05 12:44:25 -04:00
|
|
|
default_transport.Proxy = http.ProxyURL(url)
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.Insecure || c.ProxyUrl != "" {
|
|
|
|
http.DefaultTransport = default_transport
|
2013-11-19 12:03:35 -05:00
|
|
|
}
|
|
|
|
|
2013-12-31 04:11:23 -05:00
|
|
|
return gophercloud.Authenticate(c.Provider, authoptions)
|
2013-08-27 00:57:23 -04:00
|
|
|
}
|
|
|
|
|
2013-09-01 16:22:22 -04:00
|
|
|
func (c *AccessConfig) Region() string {
|
2014-04-22 00:34:03 -04:00
|
|
|
return common.ChooseString(c.RawRegion, os.Getenv("SDK_REGION"), os.Getenv("OS_REGION_NAME"))
|
2013-09-01 16:22:22 -04:00
|
|
|
}
|
|
|
|
|
2013-08-27 00:57:23 -04:00
|
|
|
func (c *AccessConfig) Prepare(t *packer.ConfigTemplate) []error {
|
|
|
|
if t == nil {
|
|
|
|
var err error
|
|
|
|
t, err = packer.NewConfigTemplate()
|
|
|
|
if err != nil {
|
|
|
|
return []error{err}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
templates := map[string]*string{
|
2014-05-01 05:23:43 -04:00
|
|
|
"username": &c.Username,
|
|
|
|
"password": &c.Password,
|
|
|
|
"api_key": &c.ApiKey,
|
|
|
|
"provider": &c.Provider,
|
|
|
|
"project": &c.Project,
|
|
|
|
"tenant_id": &c.TenantId,
|
|
|
|
"region": &c.RawRegion,
|
|
|
|
"proxy_url": &c.ProxyUrl,
|
2013-08-27 00:57:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
errs := make([]error, 0)
|
|
|
|
for n, ptr := range templates {
|
|
|
|
var err error
|
|
|
|
*ptr, err = t.Process(*ptr, nil)
|
|
|
|
if err != nil {
|
|
|
|
errs = append(
|
|
|
|
errs, fmt.Errorf("Error processing %s: %s", n, err))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-15 14:19:04 -04:00
|
|
|
if strings.HasPrefix(c.Provider, "rackspace") {
|
|
|
|
if c.Region() == "" {
|
|
|
|
errs = append(errs, fmt.Errorf("region must be specified when using rackspace"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-27 00:57:23 -04:00
|
|
|
if len(errs) > 0 {
|
|
|
|
return errs
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|