github.com/raghuse92/packer@v1.3.2/builder/openstack/access_config.go (about)

     1  package openstack
     2  
     3  import (
     4  	"crypto/tls"
     5  	"crypto/x509"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"os"
     9  
    10  	"github.com/gophercloud/gophercloud"
    11  	"github.com/gophercloud/gophercloud/openstack"
    12  	"github.com/gophercloud/utils/openstack/clientconfig"
    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  	Token            string `mapstructure:"token"`
    34  	Cloud            string `mapstructure:"cloud"`
    35  
    36  	osClient *gophercloud.ProviderClient
    37  }
    38  
    39  func (c *AccessConfig) Prepare(ctx *interpolate.Context) []error {
    40  	if c.EndpointType != "internal" && c.EndpointType != "internalURL" &&
    41  		c.EndpointType != "admin" && c.EndpointType != "adminURL" &&
    42  		c.EndpointType != "public" && c.EndpointType != "publicURL" &&
    43  		c.EndpointType != "" {
    44  		return []error{fmt.Errorf("Invalid endpoint type provided")}
    45  	}
    46  
    47  	// Legacy RackSpace stuff. We're keeping this around to keep things BC.
    48  	if c.Password == "" {
    49  		c.Password = os.Getenv("SDK_PASSWORD")
    50  	}
    51  	if c.Region == "" {
    52  		c.Region = os.Getenv("SDK_REGION")
    53  	}
    54  	if c.TenantName == "" {
    55  		c.TenantName = os.Getenv("SDK_PROJECT")
    56  	}
    57  	if c.Username == "" {
    58  		c.Username = os.Getenv("SDK_USERNAME")
    59  	}
    60  	// End RackSpace
    61  
    62  	if c.Cloud == "" {
    63  		c.Cloud = os.Getenv("OS_CLOUD")
    64  	}
    65  	if c.Region == "" {
    66  		c.Region = os.Getenv("OS_REGION_NAME")
    67  	}
    68  
    69  	if c.CACertFile == "" {
    70  		c.CACertFile = os.Getenv("OS_CACERT")
    71  	}
    72  	if c.ClientCertFile == "" {
    73  		c.ClientCertFile = os.Getenv("OS_CERT")
    74  	}
    75  	if c.ClientKeyFile == "" {
    76  		c.ClientKeyFile = os.Getenv("OS_KEY")
    77  	}
    78  
    79  	clientOpts := new(clientconfig.ClientOpts)
    80  
    81  	// If a cloud entry was given, base AuthOptions on a clouds.yaml file.
    82  	if c.Cloud != "" {
    83  		clientOpts.Cloud = c.Cloud
    84  
    85  		cloud, err := clientconfig.GetCloudFromYAML(clientOpts)
    86  		if err != nil {
    87  			return []error{err}
    88  		}
    89  
    90  		if c.Region == "" && cloud.RegionName != "" {
    91  			c.Region = cloud.RegionName
    92  		}
    93  	} else {
    94  		authInfo := &clientconfig.AuthInfo{
    95  			AuthURL:     c.IdentityEndpoint,
    96  			DomainID:    c.DomainID,
    97  			DomainName:  c.DomainName,
    98  			Password:    c.Password,
    99  			ProjectID:   c.TenantID,
   100  			ProjectName: c.TenantName,
   101  			Token:       c.Token,
   102  			Username:    c.Username,
   103  			UserID:      c.UserID,
   104  		}
   105  		clientOpts.AuthInfo = authInfo
   106  	}
   107  
   108  	ao, err := clientconfig.AuthOptions(clientOpts)
   109  	if err != nil {
   110  		return []error{err}
   111  	}
   112  
   113  	// Make sure we reauth as needed
   114  	ao.AllowReauth = true
   115  
   116  	// Override values if we have them in our config
   117  	overrides := []struct {
   118  		From, To *string
   119  	}{
   120  		{&c.Username, &ao.Username},
   121  		{&c.UserID, &ao.UserID},
   122  		{&c.Password, &ao.Password},
   123  		{&c.IdentityEndpoint, &ao.IdentityEndpoint},
   124  		{&c.TenantID, &ao.TenantID},
   125  		{&c.TenantName, &ao.TenantName},
   126  		{&c.DomainID, &ao.DomainID},
   127  		{&c.DomainName, &ao.DomainName},
   128  		{&c.Token, &ao.TokenID},
   129  	}
   130  	for _, s := range overrides {
   131  		if *s.From != "" {
   132  			*s.To = *s.From
   133  		}
   134  	}
   135  
   136  	// Build the client itself
   137  	client, err := openstack.NewClient(ao.IdentityEndpoint)
   138  	if err != nil {
   139  		return []error{err}
   140  	}
   141  
   142  	tls_config := &tls.Config{}
   143  
   144  	if c.CACertFile != "" {
   145  		caCert, err := ioutil.ReadFile(c.CACertFile)
   146  		if err != nil {
   147  			return []error{err}
   148  		}
   149  		caCertPool := x509.NewCertPool()
   150  		caCertPool.AppendCertsFromPEM(caCert)
   151  		tls_config.RootCAs = caCertPool
   152  	}
   153  
   154  	// If we have insecure set, then create a custom HTTP client that
   155  	// ignores SSL errors.
   156  	if c.Insecure {
   157  		tls_config.InsecureSkipVerify = true
   158  	}
   159  
   160  	if c.ClientCertFile != "" && c.ClientKeyFile != "" {
   161  		cert, err := tls.LoadX509KeyPair(c.ClientCertFile, c.ClientKeyFile)
   162  		if err != nil {
   163  			return []error{err}
   164  		}
   165  
   166  		tls_config.Certificates = []tls.Certificate{cert}
   167  	}
   168  
   169  	transport := cleanhttp.DefaultTransport()
   170  	transport.TLSClientConfig = tls_config
   171  	client.HTTPClient.Transport = transport
   172  
   173  	// Auth
   174  	err = openstack.Authenticate(client, *ao)
   175  	if err != nil {
   176  		return []error{err}
   177  	}
   178  
   179  	c.osClient = client
   180  	return nil
   181  }
   182  
   183  func (c *AccessConfig) computeV2Client() (*gophercloud.ServiceClient, error) {
   184  	return openstack.NewComputeV2(c.osClient, gophercloud.EndpointOpts{
   185  		Region:       c.Region,
   186  		Availability: c.getEndpointType(),
   187  	})
   188  }
   189  
   190  func (c *AccessConfig) imageV2Client() (*gophercloud.ServiceClient, error) {
   191  	return openstack.NewImageServiceV2(c.osClient, gophercloud.EndpointOpts{
   192  		Region:       c.Region,
   193  		Availability: c.getEndpointType(),
   194  	})
   195  }
   196  
   197  func (c *AccessConfig) blockStorageV3Client() (*gophercloud.ServiceClient, error) {
   198  	return openstack.NewBlockStorageV3(c.osClient, gophercloud.EndpointOpts{
   199  		Region:       c.Region,
   200  		Availability: c.getEndpointType(),
   201  	})
   202  }
   203  
   204  func (c *AccessConfig) networkV2Client() (*gophercloud.ServiceClient, error) {
   205  	return openstack.NewNetworkV2(c.osClient, gophercloud.EndpointOpts{
   206  		Region:       c.Region,
   207  		Availability: c.getEndpointType(),
   208  	})
   209  }
   210  
   211  func (c *AccessConfig) getEndpointType() gophercloud.Availability {
   212  	if c.EndpointType == "internal" || c.EndpointType == "internalURL" {
   213  		return gophercloud.AvailabilityInternal
   214  	}
   215  	if c.EndpointType == "admin" || c.EndpointType == "adminURL" {
   216  		return gophercloud.AvailabilityAdmin
   217  	}
   218  	return gophercloud.AvailabilityPublic
   219  }