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 }