blob: 876df745d58c0fb0e8d2b0e6cb5d2d24ecd7ac20 [file] [log] [blame]
Ash Wilson8ba82242014-08-28 15:38:55 -04001package openstack
2
3import (
Ash Wilsona87ee062014-09-03 11:26:06 -04004 "fmt"
Ash Wilson09694b92014-09-09 14:08:27 -04005 "net/url"
Ash Wilson4dee1b82014-08-29 14:56:45 -04006
Ash Wilson8ba82242014-08-28 15:38:55 -04007 "github.com/rackspace/gophercloud"
Ash Wilson52fbd182014-10-03 13:48:06 -04008 tokens2 "github.com/rackspace/gophercloud/openstack/identity/v2/tokens"
Ash Wilsona87ee062014-09-03 11:26:06 -04009 tokens3 "github.com/rackspace/gophercloud/openstack/identity/v3/tokens"
Ash Wilson4dee1b82014-08-29 14:56:45 -040010 "github.com/rackspace/gophercloud/openstack/utils"
Ash Wilson8ba82242014-08-28 15:38:55 -040011)
12
Ash Wilson4dee1b82014-08-29 14:56:45 -040013const (
14 v20 = "v2.0"
15 v30 = "v3.0"
16)
Ash Wilson8ba82242014-08-28 15:38:55 -040017
Ash Wilsona87ee062014-09-03 11:26:06 -040018// NewClient prepares an unauthenticated ProviderClient instance.
19// Most users will probably prefer using the AuthenticatedClient function instead.
20// This is useful if you wish to explicitly control the version of the identity service that's used for authentication explicitly,
21// for example.
22func NewClient(endpoint string) (*gophercloud.ProviderClient, error) {
Ash Wilson09694b92014-09-09 14:08:27 -040023 u, err := url.Parse(endpoint)
24 if err != nil {
25 return nil, err
26 }
27 hadPath := u.Path != ""
28 u.Path, u.RawQuery, u.Fragment = "", "", ""
29 base := u.String()
30
Ash Wilsona8440642014-10-07 09:55:58 -040031 endpoint = gophercloud.NormalizeURL(endpoint)
32 base = gophercloud.NormalizeURL(base)
Ash Wilsone7da01c2014-09-09 12:31:06 -040033
Ash Wilson09694b92014-09-09 14:08:27 -040034 if hadPath {
35 return &gophercloud.ProviderClient{
36 IdentityBase: base,
37 IdentityEndpoint: endpoint,
38 }, nil
39 }
40
41 return &gophercloud.ProviderClient{
42 IdentityBase: base,
43 IdentityEndpoint: "",
44 }, nil
Ash Wilsona87ee062014-09-03 11:26:06 -040045}
46
47// AuthenticatedClient logs in to an OpenStack cloud found at the identity endpoint specified by options, acquires a token, and
Ash Wilsonccd020b2014-09-02 10:40:54 -040048// returns a Client instance that's ready to operate.
Ash Wilson8ba82242014-08-28 15:38:55 -040049// It first queries the root identity endpoint to determine which versions of the identity service are supported, then chooses
50// the most recent identity service available to proceed.
Ash Wilsona87ee062014-09-03 11:26:06 -040051func AuthenticatedClient(options gophercloud.AuthOptions) (*gophercloud.ProviderClient, error) {
52 client, err := NewClient(options.IdentityEndpoint)
53 if err != nil {
54 return nil, err
55 }
56
57 err = Authenticate(client, options)
Ash Wilsonccd020b2014-09-02 10:40:54 -040058 if err != nil {
59 return nil, err
60 }
Jon Perrittf4052c62015-02-14 09:48:18 -070061
Ash Wilsonccd020b2014-09-02 10:40:54 -040062 return client, nil
63}
64
Ash Wilsonccd020b2014-09-02 10:40:54 -040065// Authenticate or re-authenticate against the most recent identity service supported at the provided endpoint.
Ash Wilsona87ee062014-09-03 11:26:06 -040066func Authenticate(client *gophercloud.ProviderClient, options gophercloud.AuthOptions) error {
Ash Wilson4dee1b82014-08-29 14:56:45 -040067 versions := []*utils.Version{
Ash Wilson09694b92014-09-09 14:08:27 -040068 &utils.Version{ID: v20, Priority: 20, Suffix: "/v2.0/"},
69 &utils.Version{ID: v30, Priority: 30, Suffix: "/v3/"},
Ash Wilson4dee1b82014-08-29 14:56:45 -040070 }
71
Ash Wilson2491b4c2015-02-12 16:13:39 -050072 chosen, endpoint, err := utils.ChooseVersion(client, versions)
Ash Wilson4dee1b82014-08-29 14:56:45 -040073 if err != nil {
Ash Wilsonccd020b2014-09-02 10:40:54 -040074 return err
Ash Wilson4dee1b82014-08-29 14:56:45 -040075 }
76
77 switch chosen.ID {
78 case v20:
Ash Wilson09694b92014-09-09 14:08:27 -040079 return v2auth(client, endpoint, options)
Ash Wilson4dee1b82014-08-29 14:56:45 -040080 case v30:
Ash Wilson09694b92014-09-09 14:08:27 -040081 return v3auth(client, endpoint, options)
Ash Wilson4dee1b82014-08-29 14:56:45 -040082 default:
Ash Wilsonccd020b2014-09-02 10:40:54 -040083 // The switch statement must be out of date from the versions list.
Ash Wilsona87ee062014-09-03 11:26:06 -040084 return fmt.Errorf("Unrecognized identity version: %s", chosen.ID)
Ash Wilsonccd020b2014-09-02 10:40:54 -040085 }
86}
87
Ash Wilson09694b92014-09-09 14:08:27 -040088// AuthenticateV2 explicitly authenticates against the identity v2 endpoint.
89func AuthenticateV2(client *gophercloud.ProviderClient, options gophercloud.AuthOptions) error {
90 return v2auth(client, "", options)
91}
92
93func v2auth(client *gophercloud.ProviderClient, endpoint string, options gophercloud.AuthOptions) error {
94 v2Client := NewIdentityV2(client)
95 if endpoint != "" {
96 v2Client.Endpoint = endpoint
97 }
98
Ash Wilson40095f02014-10-07 15:46:40 -040099 result := tokens2.Create(v2Client, tokens2.AuthOptions{AuthOptions: options})
Ash Wilson52fbd182014-10-03 13:48:06 -0400100
101 token, err := result.ExtractToken()
Ash Wilson09694b92014-09-09 14:08:27 -0400102 if err != nil {
103 return err
104 }
105
Ash Wilson52fbd182014-10-03 13:48:06 -0400106 catalog, err := result.ExtractServiceCatalog()
Ash Wilson09694b92014-09-09 14:08:27 -0400107 if err != nil {
108 return err
109 }
110
Jon Perrittf4052c62015-02-14 09:48:18 -0700111 if options.AllowReauth {
112 client.ReauthFunc = AuthenticateV2
113 }
114 client.AuthOptions = options
Ash Wilson09694b92014-09-09 14:08:27 -0400115 client.TokenID = token.ID
Ash Wilson130a6e22014-10-07 10:48:17 -0400116 client.EndpointLocator = func(opts gophercloud.EndpointOpts) (string, error) {
117 return V2EndpointURL(catalog, opts)
118 }
Ash Wilson09694b92014-09-09 14:08:27 -0400119
120 return nil
121}
122
Ash Wilson09694b92014-09-09 14:08:27 -0400123// AuthenticateV3 explicitly authenticates against the identity v3 service.
124func AuthenticateV3(client *gophercloud.ProviderClient, options gophercloud.AuthOptions) error {
125 return v3auth(client, "", options)
126}
127
128func v3auth(client *gophercloud.ProviderClient, endpoint string, options gophercloud.AuthOptions) error {
129 // Override the generated service endpoint with the one returned by the version endpoint.
130 v3Client := NewIdentityV3(client)
131 if endpoint != "" {
132 v3Client.Endpoint = endpoint
133 }
134
Ash Wilson63b2a292014-10-02 09:29:06 -0400135 token, err := tokens3.Create(v3Client, options, nil).Extract()
Ash Wilson09694b92014-09-09 14:08:27 -0400136 if err != nil {
137 return err
138 }
Ash Wilson63b2a292014-10-02 09:29:06 -0400139 client.TokenID = token.ID
Ash Wilson09694b92014-09-09 14:08:27 -0400140
Jon Perrittf4052c62015-02-14 09:48:18 -0700141 if options.AllowReauth {
142 client.ReauthFunc = AuthenticateV3
143 }
144 client.AuthOptions = options
Ash Wilson09694b92014-09-09 14:08:27 -0400145 client.EndpointLocator = func(opts gophercloud.EndpointOpts) (string, error) {
Ash Wilson61c49a52014-10-08 14:15:04 -0400146 return V3EndpointURL(v3Client, opts)
Ash Wilson09694b92014-09-09 14:08:27 -0400147 }
148
149 return nil
150}
151
Ash Wilsona87ee062014-09-03 11:26:06 -0400152// NewIdentityV2 creates a ServiceClient that may be used to interact with the v2 identity service.
153func NewIdentityV2(client *gophercloud.ProviderClient) *gophercloud.ServiceClient {
Ash Wilson09694b92014-09-09 14:08:27 -0400154 v2Endpoint := client.IdentityBase + "v2.0/"
Ash Wilsonccd020b2014-09-02 10:40:54 -0400155
Ash Wilsona87ee062014-09-03 11:26:06 -0400156 return &gophercloud.ServiceClient{
Ash Wilson92c380c2014-10-22 09:14:53 -0400157 ProviderClient: client,
158 Endpoint: v2Endpoint,
Ash Wilson4dee1b82014-08-29 14:56:45 -0400159 }
Ash Wilson8ba82242014-08-28 15:38:55 -0400160}
161
Ash Wilsona87ee062014-09-03 11:26:06 -0400162// NewIdentityV3 creates a ServiceClient that may be used to access the v3 identity service.
163func NewIdentityV3(client *gophercloud.ProviderClient) *gophercloud.ServiceClient {
Ash Wilson09694b92014-09-09 14:08:27 -0400164 v3Endpoint := client.IdentityBase + "v3/"
Ash Wilsona87ee062014-09-03 11:26:06 -0400165
166 return &gophercloud.ServiceClient{
Ash Wilson92c380c2014-10-22 09:14:53 -0400167 ProviderClient: client,
168 Endpoint: v3Endpoint,
Ash Wilsona87ee062014-09-03 11:26:06 -0400169 }
Ash Wilson8ba82242014-08-28 15:38:55 -0400170}
Ash Wilson1cd3e692014-09-09 11:01:47 -0400171
Jon Perrittbb5e9812014-10-15 17:53:44 -0500172// NewObjectStorageV1 creates a ServiceClient that may be used with the v1 object storage package.
173func NewObjectStorageV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
Jon Perritt509fbb62014-09-10 13:29:56 -0500174 eo.ApplyDefaults("object-store")
175 url, err := client.EndpointLocator(eo)
Ash Wilson1cd3e692014-09-09 11:01:47 -0400176 if err != nil {
177 return nil, err
178 }
Ash Wilson92c380c2014-10-22 09:14:53 -0400179 return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
Ash Wilson1cd3e692014-09-09 11:01:47 -0400180}
Ash Wilson5e57c1b2014-09-17 09:24:46 -0400181
182// NewComputeV2 creates a ServiceClient that may be used with the v2 compute package.
183func NewComputeV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
184 eo.ApplyDefaults("compute")
185 url, err := client.EndpointLocator(eo)
186 if err != nil {
187 return nil, err
188 }
Ash Wilson92c380c2014-10-22 09:14:53 -0400189 return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
Ash Wilson5e57c1b2014-09-17 09:24:46 -0400190}
Ash Wilsonebc3d122014-09-24 13:44:05 -0400191
192// NewNetworkV2 creates a ServiceClient that may be used with the v2 network package.
Jamie Hannaford7ea29582014-09-11 15:49:46 +0200193func NewNetworkV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
194 eo.ApplyDefaults("network")
195 url, err := client.EndpointLocator(eo)
196 if err != nil {
197 return nil, err
198 }
Ash Wilson99541ab2014-10-06 17:32:39 -0400199 return &gophercloud.ServiceClient{
Ash Wilson92c380c2014-10-22 09:14:53 -0400200 ProviderClient: client,
201 Endpoint: url,
202 ResourceBase: url + "v2.0/",
Ash Wilson99541ab2014-10-06 17:32:39 -0400203 }, nil
Jamie Hannaford7ea29582014-09-11 15:49:46 +0200204}
Jon Perrittc5ee85e2014-09-17 00:53:19 -0500205
206// NewBlockStorageV1 creates a ServiceClient that may be used to access the v1 block storage service.
207func NewBlockStorageV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
208 eo.ApplyDefaults("volume")
209 url, err := client.EndpointLocator(eo)
210 if err != nil {
211 return nil, err
212 }
Ash Wilson92c380c2014-10-22 09:14:53 -0400213 return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
Jon Perrittc5ee85e2014-09-17 00:53:19 -0500214}
Jon Perrittebd18ec2015-01-16 09:13:31 -0700215
216// NewCDNV1 creates a ServiceClient that may be used to access the OpenStack v1
217// CDN service.
218func NewCDNV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
219 eo.ApplyDefaults("cdn")
220 url, err := client.EndpointLocator(eo)
221 if err != nil {
222 return nil, err
223 }
224 return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
225}
Jon Perritt35e27e42014-12-05 11:10:46 -0700226
227// NewOrchestrationV1 creates a ServiceClient that may be used to access the v1 orchestration service.
228func NewOrchestrationV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
229 eo.ApplyDefaults("orchestration")
230 url, err := client.EndpointLocator(eo)
231 if err != nil {
232 return nil, err
233 }
234 return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
235}