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 }