|
1 | 1 | /*
|
2 |
| -Package gophercloud provides a multi-vendor interface to OpenStack-compatible |
3 |
| -clouds. The library has a three-level hierarchy: providers, services, and |
4 |
| -resources. |
5 |
| -
|
6 |
| -# Authenticating with Providers |
7 |
| -
|
8 |
| -Provider structs represent the cloud providers that offer and manage a |
9 |
| -collection of services. You will generally want to create one Provider |
10 |
| -client per OpenStack cloud. |
11 |
| -
|
12 |
| - It is now recommended to use the `clientconfig` package found at |
13 |
| - https://github.com/gophercloud/utils/tree/master/openstack/clientconfig |
14 |
| - for all authentication purposes. |
15 |
| -
|
16 |
| - The below documentation is still relevant. clientconfig simply implements |
17 |
| - the below and presents it in an easier and more flexible way. |
18 |
| -
|
19 |
| -Use your OpenStack credentials to create a Provider client. The |
20 |
| -IdentityEndpoint is typically refered to as "auth_url" or "OS_AUTH_URL" in |
21 |
| -information provided by the cloud operator. Additionally, the cloud may refer to |
22 |
| -TenantID or TenantName as project_id and project_name. Credentials are |
23 |
| -specified like so: |
24 |
| -
|
25 |
| - opts := gophercloud.AuthOptions{ |
26 |
| - IdentityEndpoint: "https://openstack.example.com:5000/v2.0", |
27 |
| - Username: "{username}", |
28 |
| - Password: "{password}", |
29 |
| - TenantID: "{tenant_id}", |
30 |
| - } |
| 2 | +Gophercloud is a Go SDK for OpenStack. |
31 | 3 |
|
32 |
| - provider, err := openstack.AuthenticatedClient(context.TODO(), opts) |
| 4 | +Join us on kubernetes slack, on [#gophercloud]. Visit [slack.k8s.io] for an invitation. |
33 | 5 |
|
34 |
| -You can authenticate with a token by doing: |
| 6 | +[#gophercloud]: https://kubernetes.slack.com/archives/C05G4NJ6P6X |
| 7 | +[slack.k8s.io]: https://slack.k8s.io |
35 | 8 |
|
36 |
| - opts := gophercloud.AuthOptions{ |
37 |
| - IdentityEndpoint: "https://openstack.example.com:5000/v2.0", |
38 |
| - TokenID: "{token_id}", |
39 |
| - TenantID: "{tenant_id}", |
40 |
| - } |
| 9 | +# Credentials |
| 10 | +
|
| 11 | +Because you'll be hitting an API, you will need to retrieve your OpenStack |
| 12 | +credentials and either store them in a `clouds.yaml` file, as environment |
| 13 | +variables, or in your local Go files. The first method is recommended because |
| 14 | +it decouples credential information from source code, allowing you to push the |
| 15 | +latter to your version control system without any security risk. |
| 16 | +
|
| 17 | +You will need to retrieve the following: |
41 | 18 |
|
42 |
| - provider, err := openstack.AuthenticatedClient(context.TODO(), opts) |
| 19 | + - A valid Keystone identity URL |
| 20 | + - Credentials. These can be a username/password combo, a set of Application |
| 21 | + Credentials, a pre-generated token, or any other supported authentication |
| 22 | + mechanism. |
43 | 23 |
|
44 |
| -You may also use the openstack.AuthOptionsFromEnv() helper function. This |
45 |
| -function reads in standard environment variables frequently found in an |
46 |
| -OpenStack `openrc` file. Again note that Gophercloud currently uses "tenant" |
47 |
| -instead of "project". |
| 24 | +For users who have the OpenStack dashboard installed, there's a shortcut. If |
| 25 | +you visit the `project/api_access` path in Horizon and click on the |
| 26 | +"Download OpenStack RC File" button at the top right hand corner, you can |
| 27 | +download either a `clouds.yaml` file or an `openrc` bash file that exports all |
| 28 | +of your access details to environment variables. To use the `clouds.yaml` file, |
| 29 | +place it at `~/.config/openstack/clouds.yaml`. To use the `openrc` file, run |
| 30 | +`source openrc` and you will be prompted for your password. |
48 | 31 |
|
49 |
| - opts, err := openstack.AuthOptionsFromEnv() |
50 |
| - provider, err := openstack.AuthenticatedClient(context.TODO(), opts) |
| 32 | +# Gophercloud authentication |
51 | 33 |
|
52 |
| -# Service Clients |
| 34 | +Gophercloud authentication is organized into two layered abstractions: |
| 35 | + - `ProviderClient` holds the authentication token and can be used to build a |
| 36 | + `ServiceClient`. |
| 37 | + - `ServiceClient` specializes against one specific OpenStack module and can |
| 38 | + directly be used to make API calls. |
53 | 39 |
|
54 |
| -Service structs are specific to a provider and handle all of the logic and |
55 |
| -operations for a particular OpenStack service. Examples of services include: |
56 |
| -Compute, Object Storage, Block Storage. In order to define one, you need to |
57 |
| -pass in the parent provider, like so: |
| 40 | +A provider client is a top-level client that all of your OpenStack service |
| 41 | +clients derive from. The provider contains all of the authentication details |
| 42 | +that allow your Go code to access the API - such as the base URL and token ID. |
58 | 43 |
|
59 |
| - opts := gophercloud.EndpointOpts{Region: "RegionOne"} |
| 44 | +One single Provider client can be used to build as many Service clients as needed. |
60 | 45 |
|
61 |
| - client, err := openstack.NewComputeV2(provider, opts) |
| 46 | +# With clouds.yaml |
62 | 47 |
|
63 |
| -# Resources |
| 48 | + package main |
64 | 49 |
|
65 |
| -Resource structs are the domain models that services make use of in order |
66 |
| -to work with and represent the state of API resources: |
| 50 | + import ( |
67 | 51 |
|
68 |
| - server, err := servers.Get(context.TODO(), client, "{serverId}").Extract() |
| 52 | + "context" |
69 | 53 |
|
70 |
| -Intermediate Result structs are returned for API operations, which allow |
71 |
| -generic access to the HTTP headers, response body, and any errors associated |
72 |
| -with the network transaction. To turn a result into a usable resource struct, |
73 |
| -you must call the Extract method which is chained to the response, or an |
74 |
| -Extract function from an applicable extension: |
| 54 | + "github.com/gophercloud/gophercloud/v2/openstack" |
| 55 | + "github.com/gophercloud/gophercloud/v2/openstack/config" |
| 56 | + "github.com/gophercloud/gophercloud/v2/openstack/config/clouds" |
75 | 57 |
|
76 |
| - result := servers.Get(context.TODO(), client, "{serverId}") |
| 58 | + ) |
77 | 59 |
|
78 |
| - // Attempt to extract the disk configuration from the OS-DCF disk config |
79 |
| - // extension: |
80 |
| - config, err := diskconfig.ExtractGet(result) |
| 60 | + func main() { |
| 61 | + ctx := context.Background() |
| 62 | +
|
| 63 | + // Fetch coordinates from a `cloud.yaml` in the current directory, or |
| 64 | + // in the well-known config directories (different for each operating |
| 65 | + // system). |
| 66 | + authOptions, endpointOptions, tlsConfig, err := clouds.Parse() |
| 67 | + if err != nil { |
| 68 | + panic(err) |
| 69 | + } |
81 | 70 |
|
82 |
| -All requests that enumerate a collection return a Pager struct that is used to |
83 |
| -iterate through the results one page at a time. Use the EachPage method on that |
84 |
| -Pager to handle each successive Page in a closure, then use the appropriate |
85 |
| -extraction method from that request's package to interpret that Page as a slice |
86 |
| -of results: |
| 71 | + // Call Keystone to get an authentication token, and use it to |
| 72 | + // construct a ProviderClient. All functions hitting the OpenStack API |
| 73 | + // accept a `context.Context` to enable tracing and cancellation. |
| 74 | + providerClient, err := config.NewProviderClient(ctx, authOptions, config.WithTLSConfig(tlsConfig)) |
| 75 | + if err != nil { |
| 76 | + panic(err) |
| 77 | + } |
87 | 78 |
|
88 |
| - err := servers.List(client, nil).EachPage(context.TODO(), func (_ context.Context, page pagination.Page) (bool, error) { |
89 |
| - s, err := servers.ExtractServers(page) |
| 79 | + // Use the ProviderClient and the endpoint options fetched from |
| 80 | + // `clouds.yaml` to build a service client: a compute client in this |
| 81 | + // case. Note that the contructor does not accept a `context.Context`: |
| 82 | + // no further call to the OpenStack API is needed at this stage. |
| 83 | + computeClient, err := openstack.NewComputeV2(providerClient, endpointOptions) |
90 | 84 | if err != nil {
|
91 |
| - return false, err |
| 85 | + panic(err) |
92 | 86 | }
|
93 | 87 |
|
94 |
| - // Handle the []servers.Server slice. |
| 88 | + // use the computeClient |
| 89 | + } |
95 | 90 |
|
96 |
| - // Return "false" or an error to prematurely stop fetching new pages. |
97 |
| - return true, nil |
98 |
| - }) |
| 91 | +# With environment variables (openrc) |
99 | 92 |
|
100 |
| -If you want to obtain the entire collection of pages without doing any |
101 |
| -intermediary processing on each page, you can use the AllPages method: |
| 93 | +Gophercloud can parse the environment variables previously set by running |
| 94 | +`source openrc`: |
102 | 95 |
|
103 |
| - allPages, err := servers.List(client, nil).AllPages(context.TODO()) |
104 |
| - allServers, err := servers.ExtractServers(allPages) |
| 96 | + package main |
105 | 97 |
|
106 |
| -This top-level package contains utility functions and data types that are used |
107 |
| -throughout the provider and service packages. Of particular note for end users |
108 |
| -are the AuthOptions and EndpointOpts structs. |
| 98 | + import ( |
109 | 99 |
|
110 |
| -An example retry backoff function, which respects the 429 HTTP response code and a "Retry-After" header: |
| 100 | + "context" |
| 101 | + "os" |
111 | 102 |
|
112 |
| - endpoint := "http://localhost:5000" |
113 |
| - provider, err := openstack.NewClient(endpoint) |
114 |
| - if err != nil { |
115 |
| - panic(err) |
116 |
| - } |
117 |
| - provider.MaxBackoffRetries = 3 // max three retries |
118 |
| - provider.RetryBackoffFunc = func(ctx context.Context, respErr *ErrUnexpectedResponseCode, e error, retries uint) error { |
119 |
| - retryAfter := respErr.ResponseHeader.Get("Retry-After") |
120 |
| - if retryAfter == "" { |
121 |
| - return e |
| 103 | + "github.com/gophercloud/gophercloud/v2" |
| 104 | + "github.com/gophercloud/gophercloud/v2/openstack" |
| 105 | +
|
| 106 | + ) |
| 107 | +
|
| 108 | + func main() { |
| 109 | + ctx := context.Background() |
| 110 | +
|
| 111 | + opts, err := openstack.AuthOptionsFromEnv() |
| 112 | + if err != nil { |
| 113 | + panic(err) |
122 | 114 | }
|
123 | 115 |
|
124 |
| - var sleep time.Duration |
| 116 | + providerClient, err := openstack.AuthenticatedClient(ctx, opts) |
| 117 | + if err != nil { |
| 118 | + panic(err) |
| 119 | + } |
125 | 120 |
|
126 |
| - // Parse delay seconds or HTTP date |
127 |
| - if v, err := strconv.ParseUint(retryAfter, 10, 32); err == nil { |
128 |
| - sleep = time.Duration(v) * time.Second |
129 |
| - } else if v, err := time.Parse(http.TimeFormat, retryAfter); err == nil { |
130 |
| - sleep = time.Until(v) |
131 |
| - } else { |
132 |
| - return e |
| 121 | + computeClient, err := openstack.NewComputeV2(providerClient, gophercloud.EndpointOpts{ |
| 122 | + Region: os.Getenv("OS_REGION_NAME"), |
| 123 | + }) |
| 124 | + if err != nil { |
| 125 | + panic(err) |
133 | 126 | }
|
134 | 127 |
|
135 |
| - if ctx != nil { |
136 |
| - select { |
137 |
| - case <-time.After(sleep): |
138 |
| - case <-ctx.Done(): |
139 |
| - return e |
140 |
| - } |
141 |
| - } else { |
142 |
| - time.Sleep(sleep) |
| 128 | + // use the computeClient |
| 129 | + } |
| 130 | +
|
| 131 | +# Manually |
| 132 | +
|
| 133 | +You can also generate a "Provider" by passing in your credentials explicitly: |
| 134 | +
|
| 135 | + package main |
| 136 | +
|
| 137 | + import ( |
| 138 | +
|
| 139 | + "context" |
| 140 | +
|
| 141 | + "github.com/gophercloud/gophercloud/v2" |
| 142 | + "github.com/gophercloud/gophercloud/v2/openstack" |
| 143 | +
|
| 144 | + ) |
| 145 | +
|
| 146 | + func main() { |
| 147 | + ctx := context.Background() |
| 148 | +
|
| 149 | + providerClient, err := openstack.AuthenticatedClient(ctx, gophercloud.AuthOptions{ |
| 150 | + IdentityEndpoint: "https://openstack.example:5000/v2.0", |
| 151 | + Username: "username", |
| 152 | + Password: "password", |
| 153 | + }) |
| 154 | + if err != nil { |
| 155 | + panic(err) |
| 156 | + } |
| 157 | +
|
| 158 | + computeClient, err := openstack.NewComputeV2(providerClient, gophercloud.EndpointOpts{ |
| 159 | + Region: "RegionName", |
| 160 | + }) |
| 161 | + if err != nil { |
| 162 | + panic(err) |
143 | 163 | }
|
144 | 164 |
|
145 |
| - return nil |
| 165 | + // use the computeClient |
146 | 166 | }
|
| 167 | +
|
| 168 | +# Provision a server |
| 169 | +
|
| 170 | +We can use the Compute service client generated above for any Compute API |
| 171 | +operation we want. In our case, we want to provision a new server. To do this, |
| 172 | +we invoke the `Create` method and pass in the flavor ID (hardware |
| 173 | +specification) and image ID (operating system) we're interested in: |
| 174 | +
|
| 175 | + import "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers" |
| 176 | +
|
| 177 | + func main() { |
| 178 | + // [...] |
| 179 | +
|
| 180 | + server, err := servers.Create(context.TODO(), computeClient, servers.CreateOpts{ |
| 181 | + Name: "My new server!", |
| 182 | + FlavorRef: "flavor_id", |
| 183 | + ImageRef: "image_id", |
| 184 | + }).Extract() |
| 185 | +
|
| 186 | + // [...] |
| 187 | +
|
| 188 | +The above code sample creates a new server with the parameters, and returns a |
| 189 | +[github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers.Server]. |
| 190 | +
|
| 191 | +# Supported Services |
| 192 | +
|
| 193 | + | **Service** | **Name** | **Module** | **1.x** | **2.x** | |
| 194 | + |:------------------------:|------------------|:--------------------------------:|:-------:|:-------:| |
| 195 | + | Baremetal | Ironic | openstack/baremetal | ✔ | ✔ | |
| 196 | + | Baremetal Introspection | Ironic Inspector | openstack/baremetalintrospection | ✔ | ✔ | |
| 197 | + | Block Storage | Cinder | openstack/blockstorage | ✔ | ✔ | |
| 198 | + | Clustering | Senlin | openstack/clustering | ✔ | ✘ | |
| 199 | + | Compute | Nova | openstack/compute | ✔ | ✔ | |
| 200 | + | Container | Zun | openstack/container | ✔ | ✔ | |
| 201 | + | Container Infrastructure | Magnum | openstack/containerinfra | ✔ | ✔ | |
| 202 | + | Database | Trove | openstack/db | ✔ | ✔ | |
| 203 | + | DNS | Designate | openstack/dns | ✔ | ✔ | |
| 204 | + | Identity | Keystone | openstack/identity | ✔ | ✔ | |
| 205 | + | Image | Glance | openstack/image | ✔ | ✔ | |
| 206 | + | Key Management | Barbican | openstack/keymanager | ✔ | ✔ | |
| 207 | + | Load Balancing | Octavia | openstack/loadbalancer | ✔ | ✔ | |
| 208 | + | Messaging | Zaqar | openstack/messaging | ✔ | ✔ | |
| 209 | + | Networking | Neutron | openstack/networking | ✔ | ✔ | |
| 210 | + | Object Storage | Swift | openstack/objectstorage | ✔ | ✔ | |
| 211 | +
|
| 212 | +# Advanced Usage |
| 213 | +
|
| 214 | +Have a look at the [FAQ] for some tips on customizing the way Gophercloud works. |
| 215 | +
|
| 216 | +[FAQ]: https://github.com/gophercloud/gophercloud/blob/master/docs/FAQ.md |
| 217 | +
|
| 218 | +# Backwards-Compatibility Guarantees |
| 219 | +
|
| 220 | +Gophercloud versioning follows [semver]. |
| 221 | +
|
| 222 | +Before `v1.0.0`, there were no guarantees. Starting with v1, there will be no breaking changes within a major release. |
| 223 | +
|
| 224 | +See the [Release instructions]. |
| 225 | +
|
| 226 | +[semver]: https://semver.org/spec/v2.0.0.html |
| 227 | +[Release instructions]: https://github.com/gophercloud/gophercloud/blob/master/RELEASE.md |
| 228 | +
|
| 229 | +# Contributing |
| 230 | +
|
| 231 | +See the [contributing guide]. |
| 232 | +
|
| 233 | +[contributing guide]: https://github.com/gophercloud/gophercloud/blob/master/.github/CONTRIBUTING.md |
| 234 | +
|
| 235 | +# Help and feedback |
| 236 | +
|
| 237 | +If you're struggling with something or have spotted a potential bug, feel free |
| 238 | +to submit an issue to our [bug tracker]. |
| 239 | +
|
| 240 | +[bug tracker]: https://github.com/gophercloud/gophercloud/issues |
147 | 241 | */
|
148 | 242 | package gophercloud
|
0 commit comments