github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/builder/openstack/access_config.go (about)

     1  package openstack
     2  
     3  import (
     4  	"crypto/tls"
     5  	"fmt"
     6  	"os"
     7  
     8  	"crypto/x509"
     9  	"io/ioutil"
    10  
    11  	"github.com/gophercloud/gophercloud"
    12  	"github.com/gophercloud/gophercloud/openstack"
    13  	"github.com/hashicorp/go-cleanhttp"
    14  	"github.com/hashicorp/packer/template/interpolate"
    15  )
    16  
    17  // AccessConfig is for common configuration related to openstack access
    18  type AccessConfig struct {
    19  	Username         string `mapstructure:"username"`
    20  	UserID           string `mapstructure:"user_id"`
    21  	Password         string `mapstructure:"password"`
    22  	IdentityEndpoint string `mapstructure:"identity_endpoint"`
    23  	TenantID         string `mapstructure:"tenant_id"`
    24  	TenantName       string `mapstructure:"tenant_name"`
    25  	DomainID         string `mapstructure:"domain_id"`
    26  	DomainName       string `mapstructure:"domain_name"`
    27  	Insecure         bool   `mapstructure:"insecure"`
    28  	Region           string `mapstructure:"region"`
    29  	EndpointType     string `mapstructure:"endpoint_type"`
    30  	CACertFile       string `mapstructure:"cacert"`
    31  	ClientCertFile   string `mapstructure:"cert"`
    32  	ClientKeyFile    string `mapstructure:"key"`
    33  
    34  	osClient *gophercloud.ProviderClient
    35  }
    36  
    37  func (c *AccessConfig) Prepare(ctx *interpolate.Context) []error {
    38  	if c.EndpointType != "internal" && c.EndpointType != "internalURL" &&
    39  		c.EndpointType != "admin" && c.EndpointType != "adminURL" &&
    40  		c.EndpointType != "public" && c.EndpointType != "publicURL" &&
    41  		c.EndpointType != "" {
    42  		return []error{fmt.Errorf("Invalid endpoint type provided")}
    43  	}
    44  
    45  	if c.Region == "" {
    46  		c.Region = os.Getenv("OS_REGION_NAME")
    47  	}
    48  
    49  	// Legacy RackSpace stuff. We're keeping this around to keep things BC.
    50  	if c.Password == "" {
    51  		c.Password = os.Getenv("SDK_PASSWORD")
    52  	}
    53  	if c.Region == "" {
    54  		c.Region = os.Getenv("SDK_REGION")
    55  	}
    56  	if c.TenantName == "" {
    57  		c.TenantName = os.Getenv("SDK_PROJECT")
    58  	}
    59  	if c.Username == "" {
    60  		c.Username = os.Getenv("SDK_USERNAME")
    61  	}
    62  	if c.CACertFile == "" {
    63  		c.CACertFile = os.Getenv("OS_CACERT")
    64  	}
    65  	if c.ClientCertFile == "" {
    66  		c.ClientCertFile = os.Getenv("OS_CERT")
    67  	}
    68  	if c.ClientKeyFile == "" {
    69  		c.ClientKeyFile = os.Getenv("OS_KEY")
    70  	}
    71  
    72  	// Get as much as possible from the end
    73  	ao, _ := openstack.AuthOptionsFromEnv()
    74  
    75  	// Make sure we reauth as needed
    76  	ao.AllowReauth = true
    77  
    78  	// Override values if we have them in our config
    79  	overrides := []struct {
    80  		From, To *string
    81  	}{
    82  		{&c.Username, &ao.Username},
    83  		{&c.UserID, &ao.UserID},
    84  		{&c.Password, &ao.Password},
    85  		{&c.IdentityEndpoint, &ao.IdentityEndpoint},
    86  		{&c.TenantID, &ao.TenantID},
    87  		{&c.TenantName, &ao.TenantName},
    88  		{&c.DomainID, &ao.DomainID},
    89  		{&c.DomainName, &ao.DomainName},
    90  	}
    91  	for _, s := range overrides {
    92  		if *s.From != "" {
    93  			*s.To = *s.From
    94  		}
    95  	}
    96  
    97  	// Build the client itself
    98  	client, err := openstack.NewClient(ao.IdentityEndpoint)
    99  	if err != nil {
   100  		return []error{err}
   101  	}
   102  
   103  	tls_config := &tls.Config{}
   104  
   105  	if c.CACertFile != "" {
   106  		caCert, err := ioutil.ReadFile(c.CACertFile)
   107  		if err != nil {
   108  			return []error{err}
   109  		}
   110  		caCertPool := x509.NewCertPool()
   111  		caCertPool.AppendCertsFromPEM(caCert)
   112  		tls_config.RootCAs = caCertPool
   113  	}
   114  
   115  	// If we have insecure set, then create a custom HTTP client that
   116  	// ignores SSL errors.
   117  	if c.Insecure {
   118  		tls_config.InsecureSkipVerify = true
   119  	}
   120  
   121  	if c.ClientCertFile != "" && c.ClientKeyFile != "" {
   122  		cert, err := tls.LoadX509KeyPair(c.ClientCertFile, c.ClientKeyFile)
   123  		if err != nil {
   124  			return []error{err}
   125  		}
   126  
   127  		tls_config.Certificates = []tls.Certificate{cert}
   128  	}
   129  
   130  	transport := cleanhttp.DefaultTransport()
   131  	transport.TLSClientConfig = tls_config
   132  	client.HTTPClient.Transport = transport
   133  
   134  	// Auth
   135  	err = openstack.Authenticate(client, ao)
   136  	if err != nil {
   137  		return []error{err}
   138  	}
   139  
   140  	c.osClient = client
   141  	return nil
   142  }
   143  
   144  func (c *AccessConfig) computeV2Client() (*gophercloud.ServiceClient, error) {
   145  	return openstack.NewComputeV2(c.osClient, gophercloud.EndpointOpts{
   146  		Region:       c.Region,
   147  		Availability: c.getEndpointType(),
   148  	})
   149  }
   150  
   151  func (c *AccessConfig) imageV2Client() (*gophercloud.ServiceClient, error) {
   152  	return openstack.NewImageServiceV2(c.osClient, gophercloud.EndpointOpts{
   153  		Region:       c.Region,
   154  		Availability: c.getEndpointType(),
   155  	})
   156  }
   157  
   158  func (c *AccessConfig) getEndpointType() gophercloud.Availability {
   159  	if c.EndpointType == "internal" || c.EndpointType == "internalURL" {
   160  		return gophercloud.AvailabilityInternal
   161  	}
   162  	if c.EndpointType == "admin" || c.EndpointType == "adminURL" {
   163  		return gophercloud.AvailabilityAdmin
   164  	}
   165  	return gophercloud.AvailabilityPublic
   166  }