vendor: adding github.com/gophercloud/gophercloud
This commit is contained in:
parent
17b1787ec2
commit
27c59bf1e2
|
@ -0,0 +1,235 @@
|
||||||
|
# Contributing to Gophercloud
|
||||||
|
|
||||||
|
- [Getting started](#getting-started)
|
||||||
|
- [Tests](#tests)
|
||||||
|
- [Style guide](#basic-style-guide)
|
||||||
|
- [3 ways to get involved](#5-ways-to-get-involved)
|
||||||
|
|
||||||
|
## Setting up your git workspace
|
||||||
|
|
||||||
|
As a contributor you will need to setup your workspace in a slightly different
|
||||||
|
way than just downloading it. Here are the basic installation instructions:
|
||||||
|
|
||||||
|
1. Configure your `$GOPATH` and run `go get` as described in the main
|
||||||
|
[README](/README.md#how-to-install) but add `-tags "fixtures acceptance"` to
|
||||||
|
get dependencies for unit and acceptance tests.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go get -tags "fixtures acceptance" github.com/gophercloud/gophercloud
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Move into the directory that houses your local repository:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ${GOPATH}/src/github.com/gophercloud/gophercloud
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Fork the `gophercloud/gophercloud` repository and update your remote refs. You
|
||||||
|
will need to rename the `origin` remote branch to `upstream`, and add your
|
||||||
|
fork as `origin` instead:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git remote rename origin upstream
|
||||||
|
git remote add origin git@github.com:<my_username>/gophercloud.git
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Checkout the latest development branch:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git checkout master
|
||||||
|
```
|
||||||
|
|
||||||
|
5. If you're working on something (discussed more in detail below), you will
|
||||||
|
need to checkout a new feature branch:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git checkout -b my-new-feature
|
||||||
|
```
|
||||||
|
|
||||||
|
Another thing to bear in mind is that you will need to add a few extra
|
||||||
|
environment variables for acceptance tests - this is documented in our
|
||||||
|
[acceptance tests readme](/acceptance).
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
When working on a new or existing feature, testing will be the backbone of your
|
||||||
|
work since it helps uncover and prevent regressions in the codebase. There are
|
||||||
|
two types of test we use in Gophercloud: unit tests and acceptance tests, which
|
||||||
|
are both described below.
|
||||||
|
|
||||||
|
### Unit tests
|
||||||
|
|
||||||
|
Unit tests are the fine-grained tests that establish and ensure the behavior
|
||||||
|
of individual units of functionality. We usually test on an
|
||||||
|
operation-by-operation basis (an operation typically being an API action) with
|
||||||
|
the use of mocking to set up explicit expectations. Each operation will set up
|
||||||
|
its HTTP response expectation, and then test how the system responds when fed
|
||||||
|
this controlled, pre-determined input.
|
||||||
|
|
||||||
|
To make life easier, we've introduced a bunch of test helpers to simplify the
|
||||||
|
process of testing expectations with assertions:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud/testhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSomething(t *testing.T) {
|
||||||
|
result, err := Operation()
|
||||||
|
|
||||||
|
testhelper.AssertEquals(t, "foo", result.Bar)
|
||||||
|
testhelper.AssertNoErr(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSomethingElse(t *testing.T) {
|
||||||
|
testhelper.CheckEquals(t, "expected", "actual")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`AssertEquals` and `AssertNoErr` will throw a fatal error if a value does not
|
||||||
|
match an expected value or if an error has been declared, respectively. You can
|
||||||
|
also use `CheckEquals` and `CheckNoErr` for the same purpose; the only difference
|
||||||
|
being that `t.Errorf` is raised rather than `t.Fatalf`.
|
||||||
|
|
||||||
|
Here is a truncated example of mocked HTTP responses:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
th "github.com/gophercloud/gophercloud/testhelper"
|
||||||
|
fake "github.com/gophercloud/gophercloud/testhelper/client"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/networking/v2/networks"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGet(t *testing.T) {
|
||||||
|
// Setup the HTTP request multiplexer and server
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
th.Mux.HandleFunc("/networks/d32019d3-bc6e-4319-9c1d-6722fc136a22", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Test we're using the correct HTTP method
|
||||||
|
th.TestMethod(t, r, "GET")
|
||||||
|
|
||||||
|
// Test we're setting the auth token
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
|
||||||
|
// Set the appropriate headers for our mocked response
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
|
// Set the HTTP body
|
||||||
|
fmt.Fprintf(w, `
|
||||||
|
{
|
||||||
|
"network": {
|
||||||
|
"status": "ACTIVE",
|
||||||
|
"name": "private-network",
|
||||||
|
"admin_state_up": true,
|
||||||
|
"tenant_id": "4fd44f30292945e481c7b8a0c8908869",
|
||||||
|
"shared": true,
|
||||||
|
"id": "d32019d3-bc6e-4319-9c1d-6722fc136a22"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Call our API operation
|
||||||
|
network, err := networks.Get(fake.ServiceClient(), "d32019d3-bc6e-4319-9c1d-6722fc136a22").Extract()
|
||||||
|
|
||||||
|
// Assert no errors and equality
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
th.AssertEquals(t, n.Status, "ACTIVE")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Acceptance tests
|
||||||
|
|
||||||
|
As we've already mentioned, unit tests have a very narrow and confined focus -
|
||||||
|
they test small units of behavior. Acceptance tests on the other hand have a
|
||||||
|
far larger scope: they are fully functional tests that test the entire API of a
|
||||||
|
service in one fell swoop. They don't care about unit isolation or mocking
|
||||||
|
expectations, they instead do a full run-through and consequently test how the
|
||||||
|
entire system _integrates_ together. When an API satisfies expectations, it
|
||||||
|
proves by default that the requirements for a contract have been met.
|
||||||
|
|
||||||
|
Please be aware that acceptance tests will hit a live API - and may incur
|
||||||
|
service charges from your provider. Although most tests handle their own
|
||||||
|
teardown procedures, it is always worth manually checking that resources are
|
||||||
|
deleted after the test suite finishes.
|
||||||
|
|
||||||
|
### Running tests
|
||||||
|
|
||||||
|
To run all tests:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go test -tags fixtures ./...
|
||||||
|
```
|
||||||
|
|
||||||
|
To run all tests with verbose output:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go test -v -tags fixtures ./...
|
||||||
|
```
|
||||||
|
|
||||||
|
To run tests that match certain [build tags]():
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go test -tags "fixtures foo bar" ./...
|
||||||
|
```
|
||||||
|
|
||||||
|
To run tests for a particular sub-package:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ./path/to/package && go test -tags fixtures .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Style guide
|
||||||
|
|
||||||
|
See [here](/STYLEGUIDE.md)
|
||||||
|
|
||||||
|
## 3 ways to get involved
|
||||||
|
|
||||||
|
There are five main ways you can get involved in our open-source project, and
|
||||||
|
each is described briefly below. Once you've made up your mind and decided on
|
||||||
|
your fix, you will need to follow the same basic steps that all submissions are
|
||||||
|
required to adhere to:
|
||||||
|
|
||||||
|
1. [fork](https://help.github.com/articles/fork-a-repo/) the `gophercloud/gophercloud` repository
|
||||||
|
2. checkout a [new branch](https://github.com/Kunena/Kunena-Forum/wiki/Create-a-new-branch-with-git-and-manage-branches)
|
||||||
|
3. submit your branch as a [pull request](https://help.github.com/articles/creating-a-pull-request/)
|
||||||
|
|
||||||
|
### 1. Fixing bugs
|
||||||
|
|
||||||
|
If you want to start fixing open bugs, we'd really appreciate that! Bug fixing
|
||||||
|
is central to any project. The best way to get started is by heading to our
|
||||||
|
[bug tracker](https://github.com/gophercloud/gophercloud/issues) and finding open
|
||||||
|
bugs that you think nobody is working on. It might be useful to comment on the
|
||||||
|
thread to see the current state of the issue and if anybody has made any
|
||||||
|
breakthroughs on it so far.
|
||||||
|
|
||||||
|
### 2. Improving documentation
|
||||||
|
The best source of documentation is on [godoc.org](http://godoc.org). It is
|
||||||
|
automatically generated from the source code.
|
||||||
|
|
||||||
|
If you feel that a certain section could be improved - whether it's to clarify
|
||||||
|
ambiguity, correct a technical mistake, or to fix a grammatical error - please
|
||||||
|
feel entitled to do so! We welcome doc pull requests with the same childlike
|
||||||
|
enthusiasm as any other contribution!
|
||||||
|
|
||||||
|
###3. Working on a new feature
|
||||||
|
|
||||||
|
If you've found something we've left out, definitely feel free to start work on
|
||||||
|
introducing that feature. It's always useful to open an issue or submit a pull
|
||||||
|
request early on to indicate your intent to a core contributor - this enables
|
||||||
|
quick/early feedback and can help steer you in the right direction by avoiding
|
||||||
|
known issues. It might also help you avoid losing time implementing something
|
||||||
|
that might not ever work. One tip is to prefix your Pull Request issue title
|
||||||
|
with [wip] - then people know it's a work in progress.
|
||||||
|
|
||||||
|
You must ensure that all of your work is well tested - both in terms of unit
|
||||||
|
and acceptance tests. Untested code will not be merged because it introduces
|
||||||
|
too much of a risk to end-users.
|
||||||
|
|
||||||
|
Happy hacking!
|
|
@ -0,0 +1,191 @@
|
||||||
|
Copyright 2012-2013 Rackspace, Inc.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||||
|
this file except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
|
@ -0,0 +1,32 @@
|
||||||
|
# Compute
|
||||||
|
|
||||||
|
## Floating IPs
|
||||||
|
|
||||||
|
* `github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/floatingip` is now `github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/floatingips`
|
||||||
|
* `floatingips.Associate` and `floatingips.Disassociate` have been removed.
|
||||||
|
* `floatingips.DisassociateOpts` is now required to disassociate a Floating IP.
|
||||||
|
|
||||||
|
## Security Groups
|
||||||
|
|
||||||
|
* `secgroups.AddServerToGroup` is now `secgroups.AddServer`.
|
||||||
|
* `secgroups.RemoveServerFromGroup` is now `secgroups.RemoveServer`.
|
||||||
|
|
||||||
|
## Servers
|
||||||
|
|
||||||
|
* `servers.Reboot` now requires a `servers.RebootOpts` struct:
|
||||||
|
|
||||||
|
```golang
|
||||||
|
rebootOpts := &servers.RebootOpts{
|
||||||
|
Type: servers.SoftReboot,
|
||||||
|
}
|
||||||
|
res := servers.Reboot(client, server.ID, rebootOpts)
|
||||||
|
```
|
||||||
|
|
||||||
|
# Identity
|
||||||
|
|
||||||
|
## V3
|
||||||
|
|
||||||
|
### Tokens
|
||||||
|
|
||||||
|
* `Token.ExpiresAt` is now of type `gophercloud.JSONRFC3339Milli` instead of
|
||||||
|
`time.Time`
|
|
@ -0,0 +1,139 @@
|
||||||
|
# Gophercloud: an OpenStack SDK for Go
|
||||||
|
[![Build Status](https://travis-ci.org/gophercloud/gophercloud.svg?branch=master)](https://travis-ci.org/gophercloud/gophercloud)
|
||||||
|
[![Coverage Status](https://coveralls.io/repos/github/gophercloud/gophercloud/badge.svg?branch=master)](https://coveralls.io/github/gophercloud/gophercloud?branch=master)
|
||||||
|
|
||||||
|
Gophercloud is an OpenStack Go SDK.
|
||||||
|
|
||||||
|
## Useful links
|
||||||
|
|
||||||
|
* [Reference documentation](http://godoc.org/github.com/gophercloud/gophercloud)
|
||||||
|
* [Effective Go](https://golang.org/doc/effective_go.html)
|
||||||
|
|
||||||
|
## How to install
|
||||||
|
|
||||||
|
Before installing, you need to ensure that your [GOPATH environment variable](https://golang.org/doc/code.html#GOPATH)
|
||||||
|
is pointing to an appropriate directory where you want to install Gophercloud:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir $HOME/go
|
||||||
|
export GOPATH=$HOME/go
|
||||||
|
```
|
||||||
|
|
||||||
|
To protect yourself against changes in your dependencies, we highly recommend choosing a
|
||||||
|
[dependency management solution](https://github.com/golang/go/wiki/PackageManagementTools) for
|
||||||
|
your projects, such as [godep](https://github.com/tools/godep). Once this is set up, you can install
|
||||||
|
Gophercloud as a dependency like so:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go get github.com/gophercloud/gophercloud
|
||||||
|
|
||||||
|
# Edit your code to import relevant packages from "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
godep save ./...
|
||||||
|
```
|
||||||
|
|
||||||
|
This will install all the source files you need into a `Godeps/_workspace` directory, which is
|
||||||
|
referenceable from your own source files when you use the `godep go` command.
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
### Credentials
|
||||||
|
|
||||||
|
Because you'll be hitting an API, you will need to retrieve your OpenStack
|
||||||
|
credentials and either store them as environment variables or in your local Go
|
||||||
|
files. The first method is recommended because it decouples credential
|
||||||
|
information from source code, allowing you to push the latter to your version
|
||||||
|
control system without any security risk.
|
||||||
|
|
||||||
|
You will need to retrieve the following:
|
||||||
|
|
||||||
|
* username
|
||||||
|
* password
|
||||||
|
* a valid Keystone identity URL
|
||||||
|
|
||||||
|
For users that have the OpenStack dashboard installed, there's a shortcut. If
|
||||||
|
you visit the `project/access_and_security` path in Horizon and click on the
|
||||||
|
"Download OpenStack RC File" button at the top right hand corner, you will
|
||||||
|
download a bash file that exports all of your access details to environment
|
||||||
|
variables. To execute the file, run `source admin-openrc.sh` and you will be
|
||||||
|
prompted for your password.
|
||||||
|
|
||||||
|
### Authentication
|
||||||
|
|
||||||
|
Once you have access to your credentials, you can begin plugging them into
|
||||||
|
Gophercloud. The next step is authentication, and this is handled by a base
|
||||||
|
"Provider" struct. To get one, you can either pass in your credentials
|
||||||
|
explicitly, or tell Gophercloud to use environment variables:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Option 1: Pass in the values yourself
|
||||||
|
opts := gophercloud.AuthOptions{
|
||||||
|
IdentityEndpoint: "https://my-openstack.com:5000/v2.0",
|
||||||
|
Username: "{username}",
|
||||||
|
Password: "{password}",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Option 2: Use a utility function to retrieve all your environment variables
|
||||||
|
opts, err := openstack.AuthOptionsFromEnv()
|
||||||
|
```
|
||||||
|
|
||||||
|
Once you have the `opts` variable, you can pass it in and get back a
|
||||||
|
`ProviderClient` struct:
|
||||||
|
|
||||||
|
```go
|
||||||
|
provider, err := openstack.AuthenticatedClient(opts)
|
||||||
|
```
|
||||||
|
|
||||||
|
The `ProviderClient` is the top-level client that all of your OpenStack services
|
||||||
|
derive from. The provider contains all of the authentication details that allow
|
||||||
|
your Go code to access the API - such as the base URL and token ID.
|
||||||
|
|
||||||
|
### Provision a server
|
||||||
|
|
||||||
|
Once we have a base Provider, we inject it as a dependency into each OpenStack
|
||||||
|
service. In order to work with the Compute API, we need a Compute service
|
||||||
|
client; which can be created like so:
|
||||||
|
|
||||||
|
```go
|
||||||
|
client, err := openstack.NewComputeV2(provider, gophercloud.EndpointOpts{
|
||||||
|
Region: os.Getenv("OS_REGION_NAME"),
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
We then use this `client` for any Compute API operation we want. In our case,
|
||||||
|
we want to provision a new server - so we invoke the `Create` method and pass
|
||||||
|
in the flavor ID (hardware specification) and image ID (operating system) we're
|
||||||
|
interested in:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
|
||||||
|
|
||||||
|
server, err := servers.Create(client, servers.CreateOpts{
|
||||||
|
Name: "My new server!",
|
||||||
|
FlavorRef: "flavor_id",
|
||||||
|
ImageRef: "image_id",
|
||||||
|
}).Extract()
|
||||||
|
```
|
||||||
|
|
||||||
|
The above code sample creates a new server with the parameters, and embodies the
|
||||||
|
new resource in the `server` variable (a
|
||||||
|
[`servers.Server`](http://godoc.org/github.com/gophercloud/gophercloud) struct).
|
||||||
|
|
||||||
|
## Backwards-Compatibility Guarantees
|
||||||
|
|
||||||
|
None. Vendor it and write tests covering the parts you use.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
See the [contributing guide](./CONTRIBUTING.md).
|
||||||
|
|
||||||
|
## Help and feedback
|
||||||
|
|
||||||
|
If you're struggling with something or have spotted a potential bug, feel free
|
||||||
|
to submit an issue to our [bug tracker](/issues).
|
|
@ -0,0 +1,68 @@
|
||||||
|
|
||||||
|
## On Pull Requests
|
||||||
|
|
||||||
|
- Before you start a PR there needs to be a Github issue and a discussion about it
|
||||||
|
on that issue with a core contributor, even if it's just a 'SGTM'.
|
||||||
|
|
||||||
|
- A PR's description must reference the issue it closes with a `For <ISSUE NUMBER>` (e.g. For #293).
|
||||||
|
|
||||||
|
- A PR's description must contain link(s) to the line(s) in the OpenStack
|
||||||
|
source code (on Github) that prove(s) the PR code to be valid. Links to documentation
|
||||||
|
are not good enough. The link(s) should be to a non-`master` branch. For example,
|
||||||
|
a pull request implementing the creation of a Neutron v2 subnet might put the
|
||||||
|
following link in the description:
|
||||||
|
|
||||||
|
https://github.com/openstack/neutron/blob/stable/mitaka/neutron/api/v2/attributes.py#L749
|
||||||
|
|
||||||
|
From that link, a reviewer (or user) can verify the fields in the request/response
|
||||||
|
objects in the PR.
|
||||||
|
|
||||||
|
- A PR that is in-progress should have `[wip]` in front of the PR's title. When
|
||||||
|
ready for review, remove the `[wip]` and ping a core contributor with an `@`.
|
||||||
|
|
||||||
|
- A PR should be small. Even if you intend on implementing an entire
|
||||||
|
service, a PR should only be one route of that service
|
||||||
|
(e.g. create server or get server, but not both).
|
||||||
|
|
||||||
|
- Unless explicitly asked, do not squash commits in the middle of a review; only
|
||||||
|
append. It makes it difficult for the reviewer to see what's changed from one
|
||||||
|
review to the next.
|
||||||
|
|
||||||
|
## On Code
|
||||||
|
|
||||||
|
- In re design: follow as closely as is reasonable the code already in the library.
|
||||||
|
Most operations (e.g. create, delete) admit the same design.
|
||||||
|
|
||||||
|
- Unit tests and acceptance (integration) tests must be written to cover each PR.
|
||||||
|
Tests for operations with several options (e.g. list, create) should include all
|
||||||
|
the options in the tests. This will allow users to verify an operation on their
|
||||||
|
own infrastructure and see an example of usage.
|
||||||
|
|
||||||
|
- If in doubt, ask in-line on the PR.
|
||||||
|
|
||||||
|
### File Structure
|
||||||
|
|
||||||
|
- The following should be used in most cases:
|
||||||
|
|
||||||
|
- `requests.go`: contains all the functions that make HTTP requests and the
|
||||||
|
types associated with the HTTP request (parameters for URL, body, etc)
|
||||||
|
- `results.go`: contains all the response objects and their methods
|
||||||
|
- `urls.go`: contains the endpoints to which the requests are made
|
||||||
|
|
||||||
|
### Naming
|
||||||
|
|
||||||
|
- For methods on a type in `response.go`, the receiver should be named `r` and the
|
||||||
|
variable into which it will be unmarshalled `s`.
|
||||||
|
|
||||||
|
- Functions in `requests.go`, with the exception of functions that return a
|
||||||
|
`pagination.Pager`, should be named returns of the name `r`.
|
||||||
|
|
||||||
|
- Functions in `requests.go` that accept request bodies should accept as their
|
||||||
|
last parameter an `interface` named `<Action>OptsBuilder` (eg `CreateOptsBuilder`).
|
||||||
|
This `interface` should have at the least a method named `To<Resource><Action>Map`
|
||||||
|
(eg `ToPortCreateMap`).
|
||||||
|
|
||||||
|
- Functions in `requests.go` that accept query strings should accept as their
|
||||||
|
last parameter an `interface` named `<Action>OptsBuilder` (eg `ListOptsBuilder`).
|
||||||
|
This `interface` should have at the least a method named `To<Resource><Action>Query`
|
||||||
|
(eg `ToServerListQuery`).
|
|
@ -0,0 +1,331 @@
|
||||||
|
package gophercloud
|
||||||
|
|
||||||
|
/*
|
||||||
|
AuthOptions stores information needed to authenticate to an OpenStack cluster.
|
||||||
|
You can populate one manually, or use a provider's AuthOptionsFromEnv() function
|
||||||
|
to read relevant information from the standard environment variables. Pass one
|
||||||
|
to a provider's AuthenticatedClient function to authenticate and obtain a
|
||||||
|
ProviderClient representing an active session on that provider.
|
||||||
|
|
||||||
|
Its fields are the union of those recognized by each identity implementation and
|
||||||
|
provider.
|
||||||
|
*/
|
||||||
|
type AuthOptions struct {
|
||||||
|
// IdentityEndpoint specifies the HTTP endpoint that is required to work with
|
||||||
|
// the Identity API of the appropriate version. While it's ultimately needed by
|
||||||
|
// all of the identity services, it will often be populated by a provider-level
|
||||||
|
// function.
|
||||||
|
IdentityEndpoint string `json:"-"`
|
||||||
|
|
||||||
|
// Username is required if using Identity V2 API. Consult with your provider's
|
||||||
|
// control panel to discover your account's username. In Identity V3, either
|
||||||
|
// UserID or a combination of Username and DomainID or DomainName are needed.
|
||||||
|
Username string `json:"username,omitempty"`
|
||||||
|
UserID string `json:"id,omitempty"`
|
||||||
|
|
||||||
|
Password string `json:"password,omitempty"`
|
||||||
|
|
||||||
|
// At most one of DomainID and DomainName must be provided if using Username
|
||||||
|
// with Identity V3. Otherwise, either are optional.
|
||||||
|
DomainID string `json:"id,omitempty"`
|
||||||
|
DomainName string `json:"name,omitempty"`
|
||||||
|
|
||||||
|
// The TenantID and TenantName fields are optional for the Identity V2 API.
|
||||||
|
// Some providers allow you to specify a TenantName instead of the TenantId.
|
||||||
|
// Some require both. Your provider's authentication policies will determine
|
||||||
|
// how these fields influence authentication.
|
||||||
|
TenantID string `json:"tenantId,omitempty"`
|
||||||
|
TenantName string `json:"tenantName,omitempty"`
|
||||||
|
|
||||||
|
// AllowReauth should be set to true if you grant permission for Gophercloud to
|
||||||
|
// cache your credentials in memory, and to allow Gophercloud to attempt to
|
||||||
|
// re-authenticate automatically if/when your token expires. If you set it to
|
||||||
|
// false, it will not cache these settings, but re-authentication will not be
|
||||||
|
// possible. This setting defaults to false.
|
||||||
|
//
|
||||||
|
// NOTE: The reauth function will try to re-authenticate endlessly if left unchecked.
|
||||||
|
// The way to limit the number of attempts is to provide a custom HTTP client to the provider client
|
||||||
|
// and provide a transport that implements the RoundTripper interface and stores the number of failed retries.
|
||||||
|
// For an example of this, see here: https://github.com/rackspace/rack/blob/1.0.0/auth/clients.go#L311
|
||||||
|
AllowReauth bool `json:"-"`
|
||||||
|
|
||||||
|
// TokenID allows users to authenticate (possibly as another user) with an
|
||||||
|
// authentication token ID.
|
||||||
|
TokenID string `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToTokenV2CreateMap allows AuthOptions to satisfy the AuthOptionsBuilder
|
||||||
|
// interface in the v2 tokens package
|
||||||
|
func (opts AuthOptions) ToTokenV2CreateMap() (map[string]interface{}, error) {
|
||||||
|
// Populate the request map.
|
||||||
|
authMap := make(map[string]interface{})
|
||||||
|
|
||||||
|
if opts.Username != "" {
|
||||||
|
if opts.Password != "" {
|
||||||
|
authMap["passwordCredentials"] = map[string]interface{}{
|
||||||
|
"username": opts.Username,
|
||||||
|
"password": opts.Password,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, ErrMissingInput{Argument: "Password"}
|
||||||
|
}
|
||||||
|
} else if opts.TokenID != "" {
|
||||||
|
authMap["token"] = map[string]interface{}{
|
||||||
|
"id": opts.TokenID,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, ErrMissingInput{Argument: "Username"}
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.TenantID != "" {
|
||||||
|
authMap["tenantId"] = opts.TenantID
|
||||||
|
}
|
||||||
|
if opts.TenantName != "" {
|
||||||
|
authMap["tenantName"] = opts.TenantName
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]interface{}{"auth": authMap}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opts *AuthOptions) ToTokenV3CreateMap(scope map[string]interface{}) (map[string]interface{}, error) {
|
||||||
|
type domainReq struct {
|
||||||
|
ID *string `json:"id,omitempty"`
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type projectReq struct {
|
||||||
|
Domain *domainReq `json:"domain,omitempty"`
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
ID *string `json:"id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type userReq struct {
|
||||||
|
ID *string `json:"id,omitempty"`
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
Domain *domainReq `json:"domain,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type passwordReq struct {
|
||||||
|
User userReq `json:"user"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type tokenReq struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type identityReq struct {
|
||||||
|
Methods []string `json:"methods"`
|
||||||
|
Password *passwordReq `json:"password,omitempty"`
|
||||||
|
Token *tokenReq `json:"token,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type authReq struct {
|
||||||
|
Identity identityReq `json:"identity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type request struct {
|
||||||
|
Auth authReq `json:"auth"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate the request structure based on the provided arguments. Create and return an error
|
||||||
|
// if insufficient or incompatible information is present.
|
||||||
|
var req request
|
||||||
|
|
||||||
|
// Test first for unrecognized arguments.
|
||||||
|
if opts.TenantID != "" {
|
||||||
|
return nil, ErrTenantIDProvided{}
|
||||||
|
}
|
||||||
|
if opts.TenantName != "" {
|
||||||
|
return nil, ErrTenantNameProvided{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.Password == "" {
|
||||||
|
if opts.TokenID != "" {
|
||||||
|
// Because we aren't using password authentication, it's an error to also provide any of the user-based authentication
|
||||||
|
// parameters.
|
||||||
|
if opts.Username != "" {
|
||||||
|
return nil, ErrUsernameWithToken{}
|
||||||
|
}
|
||||||
|
if opts.UserID != "" {
|
||||||
|
return nil, ErrUserIDWithToken{}
|
||||||
|
}
|
||||||
|
if opts.DomainID != "" {
|
||||||
|
return nil, ErrDomainIDWithToken{}
|
||||||
|
}
|
||||||
|
if opts.DomainName != "" {
|
||||||
|
return nil, ErrDomainNameWithToken{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure the request for Token authentication.
|
||||||
|
req.Auth.Identity.Methods = []string{"token"}
|
||||||
|
req.Auth.Identity.Token = &tokenReq{
|
||||||
|
ID: opts.TokenID,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If no password or token ID are available, authentication can't continue.
|
||||||
|
return nil, ErrMissingPassword{}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Password authentication.
|
||||||
|
req.Auth.Identity.Methods = []string{"password"}
|
||||||
|
|
||||||
|
// At least one of Username and UserID must be specified.
|
||||||
|
if opts.Username == "" && opts.UserID == "" {
|
||||||
|
return nil, ErrUsernameOrUserID{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.Username != "" {
|
||||||
|
// If Username is provided, UserID may not be provided.
|
||||||
|
if opts.UserID != "" {
|
||||||
|
return nil, ErrUsernameOrUserID{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Either DomainID or DomainName must also be specified.
|
||||||
|
if opts.DomainID == "" && opts.DomainName == "" {
|
||||||
|
return nil, ErrDomainIDOrDomainName{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.DomainID != "" {
|
||||||
|
if opts.DomainName != "" {
|
||||||
|
return nil, ErrDomainIDOrDomainName{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure the request for Username and Password authentication with a DomainID.
|
||||||
|
req.Auth.Identity.Password = &passwordReq{
|
||||||
|
User: userReq{
|
||||||
|
Name: &opts.Username,
|
||||||
|
Password: opts.Password,
|
||||||
|
Domain: &domainReq{ID: &opts.DomainID},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.DomainName != "" {
|
||||||
|
// Configure the request for Username and Password authentication with a DomainName.
|
||||||
|
req.Auth.Identity.Password = &passwordReq{
|
||||||
|
User: userReq{
|
||||||
|
Name: &opts.Username,
|
||||||
|
Password: opts.Password,
|
||||||
|
Domain: &domainReq{Name: &opts.DomainName},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.UserID != "" {
|
||||||
|
// If UserID is specified, neither DomainID nor DomainName may be.
|
||||||
|
if opts.DomainID != "" {
|
||||||
|
return nil, ErrDomainIDWithUserID{}
|
||||||
|
}
|
||||||
|
if opts.DomainName != "" {
|
||||||
|
return nil, ErrDomainNameWithUserID{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure the request for UserID and Password authentication.
|
||||||
|
req.Auth.Identity.Password = &passwordReq{
|
||||||
|
User: userReq{ID: &opts.UserID, Password: opts.Password},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := BuildRequestBody(req, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(scope) != 0 {
|
||||||
|
b["auth"].(map[string]interface{})["scope"] = scope
|
||||||
|
}
|
||||||
|
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opts *AuthOptions) ToTokenV3ScopeMap() (map[string]interface{}, error) {
|
||||||
|
|
||||||
|
var scope struct {
|
||||||
|
ProjectID string
|
||||||
|
ProjectName string
|
||||||
|
DomainID string
|
||||||
|
DomainName string
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.TenantID != "" {
|
||||||
|
scope.ProjectID = opts.TenantID
|
||||||
|
opts.TenantID = ""
|
||||||
|
opts.TenantName = ""
|
||||||
|
} else {
|
||||||
|
if opts.TenantName != "" {
|
||||||
|
scope.ProjectName = opts.TenantName
|
||||||
|
scope.DomainID = opts.DomainID
|
||||||
|
scope.DomainName = opts.DomainName
|
||||||
|
}
|
||||||
|
opts.TenantName = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if scope.ProjectName != "" {
|
||||||
|
// ProjectName provided: either DomainID or DomainName must also be supplied.
|
||||||
|
// ProjectID may not be supplied.
|
||||||
|
if scope.DomainID == "" && scope.DomainName == "" {
|
||||||
|
return nil, ErrScopeDomainIDOrDomainName{}
|
||||||
|
}
|
||||||
|
if scope.ProjectID != "" {
|
||||||
|
return nil, ErrScopeProjectIDOrProjectName{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if scope.DomainID != "" {
|
||||||
|
// ProjectName + DomainID
|
||||||
|
return map[string]interface{}{
|
||||||
|
"project": map[string]interface{}{
|
||||||
|
"name": &scope.ProjectName,
|
||||||
|
"domain": map[string]interface{}{"id": &scope.DomainID},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if scope.DomainName != "" {
|
||||||
|
// ProjectName + DomainName
|
||||||
|
return map[string]interface{}{
|
||||||
|
"project": map[string]interface{}{
|
||||||
|
"name": &scope.ProjectName,
|
||||||
|
"domain": map[string]interface{}{"name": &scope.DomainName},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
} else if scope.ProjectID != "" {
|
||||||
|
// ProjectID provided. ProjectName, DomainID, and DomainName may not be provided.
|
||||||
|
if scope.DomainID != "" {
|
||||||
|
return nil, ErrScopeProjectIDAlone{}
|
||||||
|
}
|
||||||
|
if scope.DomainName != "" {
|
||||||
|
return nil, ErrScopeProjectIDAlone{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectID
|
||||||
|
return map[string]interface{}{
|
||||||
|
"project": map[string]interface{}{
|
||||||
|
"id": &scope.ProjectID,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
} else if scope.DomainID != "" {
|
||||||
|
// DomainID provided. ProjectID, ProjectName, and DomainName may not be provided.
|
||||||
|
if scope.DomainName != "" {
|
||||||
|
return nil, ErrScopeDomainIDOrDomainName{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DomainID
|
||||||
|
return map[string]interface{}{
|
||||||
|
"domain": map[string]interface{}{
|
||||||
|
"id": &scope.DomainID,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
} else if scope.DomainName != "" {
|
||||||
|
return nil, ErrScopeDomainName{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opts AuthOptions) CanReauth() bool {
|
||||||
|
return opts.AllowReauth
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
Package gophercloud provides a multi-vendor interface to OpenStack-compatible
|
||||||
|
clouds. The library has a three-level hierarchy: providers, services, and
|
||||||
|
resources.
|
||||||
|
|
||||||
|
Provider structs represent the service providers that offer and manage a
|
||||||
|
collection of services. Examples of providers include: OpenStack, Rackspace,
|
||||||
|
HP. These are defined like so:
|
||||||
|
|
||||||
|
opts := gophercloud.AuthOptions{
|
||||||
|
IdentityEndpoint: "https://my-openstack.com:5000/v2.0",
|
||||||
|
Username: "{username}",
|
||||||
|
Password: "{password}",
|
||||||
|
TenantID: "{tenant_id}",
|
||||||
|
}
|
||||||
|
|
||||||
|
provider, err := openstack.AuthenticatedClient(opts)
|
||||||
|
|
||||||
|
Service structs are specific to a provider and handle all of the logic and
|
||||||
|
operations for a particular OpenStack service. Examples of services include:
|
||||||
|
Compute, Object Storage, Block Storage. In order to define one, you need to
|
||||||
|
pass in the parent provider, like so:
|
||||||
|
|
||||||
|
opts := gophercloud.EndpointOpts{Region: "RegionOne"}
|
||||||
|
|
||||||
|
client := openstack.NewComputeV2(provider, opts)
|
||||||
|
|
||||||
|
Resource structs are the domain models that services make use of in order
|
||||||
|
to work with and represent the state of API resources:
|
||||||
|
|
||||||
|
server, err := servers.Get(client, "{serverId}").Extract()
|
||||||
|
|
||||||
|
Intermediate Result structs are returned for API operations, which allow
|
||||||
|
generic access to the HTTP headers, response body, and any errors associated
|
||||||
|
with the network transaction. To turn a result into a usable resource struct,
|
||||||
|
you must call the Extract method which is chained to the response, or an
|
||||||
|
Extract function from an applicable extension:
|
||||||
|
|
||||||
|
result := servers.Get(client, "{serverId}")
|
||||||
|
|
||||||
|
// Attempt to extract the disk configuration from the OS-DCF disk config
|
||||||
|
// extension:
|
||||||
|
config, err := diskconfig.ExtractGet(result)
|
||||||
|
|
||||||
|
All requests that enumerate a collection return a Pager struct that is used to
|
||||||
|
iterate through the results one page at a time. Use the EachPage method on that
|
||||||
|
Pager to handle each successive Page in a closure, then use the appropriate
|
||||||
|
extraction method from that request's package to interpret that Page as a slice
|
||||||
|
of results:
|
||||||
|
|
||||||
|
err := servers.List(client, nil).EachPage(func (page pagination.Page) (bool, error) {
|
||||||
|
s, err := servers.ExtractServers(page)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the []servers.Server slice.
|
||||||
|
|
||||||
|
// Return "false" or an error to prematurely stop fetching new pages.
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
This top-level package contains utility functions and data types that are used
|
||||||
|
throughout the provider and service packages. Of particular note for end users
|
||||||
|
are the AuthOptions and EndpointOpts structs.
|
||||||
|
*/
|
||||||
|
package gophercloud
|
|
@ -0,0 +1,76 @@
|
||||||
|
package gophercloud
|
||||||
|
|
||||||
|
// Availability indicates to whom a specific service endpoint is accessible:
|
||||||
|
// the internet at large, internal networks only, or only to administrators.
|
||||||
|
// Different identity services use different terminology for these. Identity v2
|
||||||
|
// lists them as different kinds of URLs within the service catalog ("adminURL",
|
||||||
|
// "internalURL", and "publicURL"), while v3 lists them as "Interfaces" in an
|
||||||
|
// endpoint's response.
|
||||||
|
type Availability string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// AvailabilityAdmin indicates that an endpoint is only available to
|
||||||
|
// administrators.
|
||||||
|
AvailabilityAdmin Availability = "admin"
|
||||||
|
|
||||||
|
// AvailabilityPublic indicates that an endpoint is available to everyone on
|
||||||
|
// the internet.
|
||||||
|
AvailabilityPublic Availability = "public"
|
||||||
|
|
||||||
|
// AvailabilityInternal indicates that an endpoint is only available within
|
||||||
|
// the cluster's internal network.
|
||||||
|
AvailabilityInternal Availability = "internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EndpointOpts specifies search criteria used by queries against an
|
||||||
|
// OpenStack service catalog. The options must contain enough information to
|
||||||
|
// unambiguously identify one, and only one, endpoint within the catalog.
|
||||||
|
//
|
||||||
|
// Usually, these are passed to service client factory functions in a provider
|
||||||
|
// package, like "rackspace.NewComputeV2()".
|
||||||
|
type EndpointOpts struct {
|
||||||
|
// Type [required] is the service type for the client (e.g., "compute",
|
||||||
|
// "object-store"). Generally, this will be supplied by the service client
|
||||||
|
// function, but a user-given value will be honored if provided.
|
||||||
|
Type string
|
||||||
|
|
||||||
|
// Name [optional] is the service name for the client (e.g., "nova") as it
|
||||||
|
// appears in the service catalog. Services can have the same Type but a
|
||||||
|
// different Name, which is why both Type and Name are sometimes needed.
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// Region [required] is the geographic region in which the endpoint resides,
|
||||||
|
// generally specifying which datacenter should house your resources.
|
||||||
|
// Required only for services that span multiple regions.
|
||||||
|
Region string
|
||||||
|
|
||||||
|
// Availability [optional] is the visibility of the endpoint to be returned.
|
||||||
|
// Valid types include the constants AvailabilityPublic, AvailabilityInternal,
|
||||||
|
// or AvailabilityAdmin from this package.
|
||||||
|
//
|
||||||
|
// Availability is not required, and defaults to AvailabilityPublic. Not all
|
||||||
|
// providers or services offer all Availability options.
|
||||||
|
Availability Availability
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
EndpointLocator is an internal function to be used by provider implementations.
|
||||||
|
|
||||||
|
It provides an implementation that locates a single endpoint from a service
|
||||||
|
catalog for a specific ProviderClient based on user-provided EndpointOpts. The
|
||||||
|
provider then uses it to discover related ServiceClients.
|
||||||
|
*/
|
||||||
|
type EndpointLocator func(EndpointOpts) (string, error)
|
||||||
|
|
||||||
|
// ApplyDefaults is an internal method to be used by provider implementations.
|
||||||
|
//
|
||||||
|
// It sets EndpointOpts fields if not already set, including a default type.
|
||||||
|
// Currently, EndpointOpts.Availability defaults to the public endpoint.
|
||||||
|
func (eo *EndpointOpts) ApplyDefaults(t string) {
|
||||||
|
if eo.Type == "" {
|
||||||
|
eo.Type = t
|
||||||
|
}
|
||||||
|
if eo.Availability == "" {
|
||||||
|
eo.Availability = AvailabilityPublic
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,408 @@
|
||||||
|
package gophercloud
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// BaseError is an error type that all other error types embed.
|
||||||
|
type BaseError struct {
|
||||||
|
DefaultErrString string
|
||||||
|
Info string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e BaseError) Error() string {
|
||||||
|
e.DefaultErrString = "An error occurred while executing a Gophercloud request."
|
||||||
|
return e.choseErrString()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e BaseError) choseErrString() string {
|
||||||
|
if e.Info != "" {
|
||||||
|
return e.Info
|
||||||
|
}
|
||||||
|
return e.DefaultErrString
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrMissingInput is the error when input is required in a particular
|
||||||
|
// situation but not provided by the user
|
||||||
|
type ErrMissingInput struct {
|
||||||
|
BaseError
|
||||||
|
Argument string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrMissingInput) Error() string {
|
||||||
|
e.DefaultErrString = fmt.Sprintf("Missing input for argument [%s]", e.Argument)
|
||||||
|
return e.choseErrString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrInvalidInput is an error type used for most non-HTTP Gophercloud errors.
|
||||||
|
type ErrInvalidInput struct {
|
||||||
|
ErrMissingInput
|
||||||
|
Value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrInvalidInput) Error() string {
|
||||||
|
e.DefaultErrString = fmt.Sprintf("Invalid input provided for argument [%s]: [%+v]", e.Argument, e.Value)
|
||||||
|
return e.choseErrString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrUnexpectedResponseCode is returned by the Request method when a response code other than
|
||||||
|
// those listed in OkCodes is encountered.
|
||||||
|
type ErrUnexpectedResponseCode struct {
|
||||||
|
BaseError
|
||||||
|
URL string
|
||||||
|
Method string
|
||||||
|
Expected []int
|
||||||
|
Actual int
|
||||||
|
Body []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrUnexpectedResponseCode) Error() string {
|
||||||
|
e.DefaultErrString = fmt.Sprintf(
|
||||||
|
"Expected HTTP response code %v when accessing [%s %s], but got %d instead\n%s",
|
||||||
|
e.Expected, e.Method, e.URL, e.Actual, e.Body,
|
||||||
|
)
|
||||||
|
return e.choseErrString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrDefault400 is the default error type returned on a 400 HTTP response code.
|
||||||
|
type ErrDefault400 struct {
|
||||||
|
ErrUnexpectedResponseCode
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrDefault401 is the default error type returned on a 401 HTTP response code.
|
||||||
|
type ErrDefault401 struct {
|
||||||
|
ErrUnexpectedResponseCode
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrDefault404 is the default error type returned on a 404 HTTP response code.
|
||||||
|
type ErrDefault404 struct {
|
||||||
|
ErrUnexpectedResponseCode
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrDefault405 is the default error type returned on a 405 HTTP response code.
|
||||||
|
type ErrDefault405 struct {
|
||||||
|
ErrUnexpectedResponseCode
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrDefault408 is the default error type returned on a 408 HTTP response code.
|
||||||
|
type ErrDefault408 struct {
|
||||||
|
ErrUnexpectedResponseCode
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrDefault429 is the default error type returned on a 429 HTTP response code.
|
||||||
|
type ErrDefault429 struct {
|
||||||
|
ErrUnexpectedResponseCode
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrDefault500 is the default error type returned on a 500 HTTP response code.
|
||||||
|
type ErrDefault500 struct {
|
||||||
|
ErrUnexpectedResponseCode
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrDefault503 is the default error type returned on a 503 HTTP response code.
|
||||||
|
type ErrDefault503 struct {
|
||||||
|
ErrUnexpectedResponseCode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrDefault400) Error() string {
|
||||||
|
return "Invalid request due to incorrect syntax or missing required parameters."
|
||||||
|
}
|
||||||
|
func (e ErrDefault401) Error() string {
|
||||||
|
return "Authentication failed"
|
||||||
|
}
|
||||||
|
func (e ErrDefault404) Error() string {
|
||||||
|
return "Resource not found"
|
||||||
|
}
|
||||||
|
func (e ErrDefault405) Error() string {
|
||||||
|
return "Method not allowed"
|
||||||
|
}
|
||||||
|
func (e ErrDefault408) Error() string {
|
||||||
|
return "The server timed out waiting for the request"
|
||||||
|
}
|
||||||
|
func (e ErrDefault429) Error() string {
|
||||||
|
return "Too many requests have been sent in a given amount of time. Pause" +
|
||||||
|
" requests, wait up to one minute, and try again."
|
||||||
|
}
|
||||||
|
func (e ErrDefault500) Error() string {
|
||||||
|
return "Internal Server Error"
|
||||||
|
}
|
||||||
|
func (e ErrDefault503) Error() string {
|
||||||
|
return "The service is currently unable to handle the request due to a temporary" +
|
||||||
|
" overloading or maintenance. This is a temporary condition. Try again later."
|
||||||
|
}
|
||||||
|
|
||||||
|
// Err400er is the interface resource error types implement to override the error message
|
||||||
|
// from a 400 error.
|
||||||
|
type Err400er interface {
|
||||||
|
Error400(ErrUnexpectedResponseCode) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Err401er is the interface resource error types implement to override the error message
|
||||||
|
// from a 401 error.
|
||||||
|
type Err401er interface {
|
||||||
|
Error401(ErrUnexpectedResponseCode) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Err404er is the interface resource error types implement to override the error message
|
||||||
|
// from a 404 error.
|
||||||
|
type Err404er interface {
|
||||||
|
Error404(ErrUnexpectedResponseCode) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Err405er is the interface resource error types implement to override the error message
|
||||||
|
// from a 405 error.
|
||||||
|
type Err405er interface {
|
||||||
|
Error405(ErrUnexpectedResponseCode) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Err408er is the interface resource error types implement to override the error message
|
||||||
|
// from a 408 error.
|
||||||
|
type Err408er interface {
|
||||||
|
Error408(ErrUnexpectedResponseCode) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Err429er is the interface resource error types implement to override the error message
|
||||||
|
// from a 429 error.
|
||||||
|
type Err429er interface {
|
||||||
|
Error429(ErrUnexpectedResponseCode) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Err500er is the interface resource error types implement to override the error message
|
||||||
|
// from a 500 error.
|
||||||
|
type Err500er interface {
|
||||||
|
Error500(ErrUnexpectedResponseCode) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Err503er is the interface resource error types implement to override the error message
|
||||||
|
// from a 503 error.
|
||||||
|
type Err503er interface {
|
||||||
|
Error503(ErrUnexpectedResponseCode) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrTimeOut is the error type returned when an operations times out.
|
||||||
|
type ErrTimeOut struct {
|
||||||
|
BaseError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrTimeOut) Error() string {
|
||||||
|
e.DefaultErrString = "A time out occurred"
|
||||||
|
return e.choseErrString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrUnableToReauthenticate is the error type returned when reauthentication fails.
|
||||||
|
type ErrUnableToReauthenticate struct {
|
||||||
|
BaseError
|
||||||
|
ErrOriginal error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrUnableToReauthenticate) Error() string {
|
||||||
|
e.DefaultErrString = fmt.Sprintf("Unable to re-authenticate: %s", e.ErrOriginal)
|
||||||
|
return e.choseErrString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrErrorAfterReauthentication is the error type returned when reauthentication
|
||||||
|
// succeeds, but an error occurs afterword (usually an HTTP error).
|
||||||
|
type ErrErrorAfterReauthentication struct {
|
||||||
|
BaseError
|
||||||
|
ErrOriginal error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrErrorAfterReauthentication) Error() string {
|
||||||
|
e.DefaultErrString = fmt.Sprintf("Successfully re-authenticated, but got error executing request: %s", e.ErrOriginal)
|
||||||
|
return e.choseErrString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrServiceNotFound is returned when no service in a service catalog matches
|
||||||
|
// the provided EndpointOpts. This is generally returned by provider service
|
||||||
|
// factory methods like "NewComputeV2()" and can mean that a service is not
|
||||||
|
// enabled for your account.
|
||||||
|
type ErrServiceNotFound struct {
|
||||||
|
BaseError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrServiceNotFound) Error() string {
|
||||||
|
e.DefaultErrString = "No suitable service could be found in the service catalog."
|
||||||
|
return e.choseErrString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrEndpointNotFound is returned when no available endpoints match the
|
||||||
|
// provided EndpointOpts. This is also generally returned by provider service
|
||||||
|
// factory methods, and usually indicates that a region was specified
|
||||||
|
// incorrectly.
|
||||||
|
type ErrEndpointNotFound struct {
|
||||||
|
BaseError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrEndpointNotFound) Error() string {
|
||||||
|
e.DefaultErrString = "No suitable endpoint could be found in the service catalog."
|
||||||
|
return e.choseErrString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrResourceNotFound is the error when trying to retrieve a resource's
|
||||||
|
// ID by name and the resource doesn't exist.
|
||||||
|
type ErrResourceNotFound struct {
|
||||||
|
BaseError
|
||||||
|
Name string
|
||||||
|
ResourceType string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrResourceNotFound) Error() string {
|
||||||
|
e.DefaultErrString = fmt.Sprintf("Unable to find %s with name %s", e.ResourceType, e.Name)
|
||||||
|
return e.choseErrString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrMultipleResourcesFound is the error when trying to retrieve a resource's
|
||||||
|
// ID by name and multiple resources have the user-provided name.
|
||||||
|
type ErrMultipleResourcesFound struct {
|
||||||
|
BaseError
|
||||||
|
Name string
|
||||||
|
Count int
|
||||||
|
ResourceType string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrMultipleResourcesFound) Error() string {
|
||||||
|
e.DefaultErrString = fmt.Sprintf("Found %d %ss matching %s", e.Count, e.ResourceType, e.Name)
|
||||||
|
return e.choseErrString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrUnexpectedType is the error when an unexpected type is encountered
|
||||||
|
type ErrUnexpectedType struct {
|
||||||
|
BaseError
|
||||||
|
Expected string
|
||||||
|
Actual string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrUnexpectedType) Error() string {
|
||||||
|
e.DefaultErrString = fmt.Sprintf("Expected %s but got %s", e.Expected, e.Actual)
|
||||||
|
return e.choseErrString()
|
||||||
|
}
|
||||||
|
|
||||||
|
func unacceptedAttributeErr(attribute string) string {
|
||||||
|
return fmt.Sprintf("The base Identity V3 API does not accept authentication by %s", attribute)
|
||||||
|
}
|
||||||
|
|
||||||
|
func redundantWithTokenErr(attribute string) string {
|
||||||
|
return fmt.Sprintf("%s may not be provided when authenticating with a TokenID", attribute)
|
||||||
|
}
|
||||||
|
|
||||||
|
func redundantWithUserID(attribute string) string {
|
||||||
|
return fmt.Sprintf("%s may not be provided when authenticating with a UserID", attribute)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrAPIKeyProvided indicates that an APIKey was provided but can't be used.
|
||||||
|
type ErrAPIKeyProvided struct{ BaseError }
|
||||||
|
|
||||||
|
func (e ErrAPIKeyProvided) Error() string {
|
||||||
|
return unacceptedAttributeErr("APIKey")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrTenantIDProvided indicates that a TenantID was provided but can't be used.
|
||||||
|
type ErrTenantIDProvided struct{ BaseError }
|
||||||
|
|
||||||
|
func (e ErrTenantIDProvided) Error() string {
|
||||||
|
return unacceptedAttributeErr("TenantID")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrTenantNameProvided indicates that a TenantName was provided but can't be used.
|
||||||
|
type ErrTenantNameProvided struct{ BaseError }
|
||||||
|
|
||||||
|
func (e ErrTenantNameProvided) Error() string {
|
||||||
|
return unacceptedAttributeErr("TenantName")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrUsernameWithToken indicates that a Username was provided, but token authentication is being used instead.
|
||||||
|
type ErrUsernameWithToken struct{ BaseError }
|
||||||
|
|
||||||
|
func (e ErrUsernameWithToken) Error() string {
|
||||||
|
return redundantWithTokenErr("Username")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrUserIDWithToken indicates that a UserID was provided, but token authentication is being used instead.
|
||||||
|
type ErrUserIDWithToken struct{ BaseError }
|
||||||
|
|
||||||
|
func (e ErrUserIDWithToken) Error() string {
|
||||||
|
return redundantWithTokenErr("UserID")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrDomainIDWithToken indicates that a DomainID was provided, but token authentication is being used instead.
|
||||||
|
type ErrDomainIDWithToken struct{ BaseError }
|
||||||
|
|
||||||
|
func (e ErrDomainIDWithToken) Error() string {
|
||||||
|
return redundantWithTokenErr("DomainID")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrDomainNameWithToken indicates that a DomainName was provided, but token authentication is being used instead.s
|
||||||
|
type ErrDomainNameWithToken struct{ BaseError }
|
||||||
|
|
||||||
|
func (e ErrDomainNameWithToken) Error() string {
|
||||||
|
return redundantWithTokenErr("DomainName")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrUsernameOrUserID indicates that neither username nor userID are specified, or both are at once.
|
||||||
|
type ErrUsernameOrUserID struct{ BaseError }
|
||||||
|
|
||||||
|
func (e ErrUsernameOrUserID) Error() string {
|
||||||
|
return "Exactly one of Username and UserID must be provided for password authentication"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrDomainIDWithUserID indicates that a DomainID was provided, but unnecessary because a UserID is being used.
|
||||||
|
type ErrDomainIDWithUserID struct{ BaseError }
|
||||||
|
|
||||||
|
func (e ErrDomainIDWithUserID) Error() string {
|
||||||
|
return redundantWithUserID("DomainID")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrDomainNameWithUserID indicates that a DomainName was provided, but unnecessary because a UserID is being used.
|
||||||
|
type ErrDomainNameWithUserID struct{ BaseError }
|
||||||
|
|
||||||
|
func (e ErrDomainNameWithUserID) Error() string {
|
||||||
|
return redundantWithUserID("DomainName")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrDomainIDOrDomainName indicates that a username was provided, but no domain to scope it.
|
||||||
|
// It may also indicate that both a DomainID and a DomainName were provided at once.
|
||||||
|
type ErrDomainIDOrDomainName struct{ BaseError }
|
||||||
|
|
||||||
|
func (e ErrDomainIDOrDomainName) Error() string {
|
||||||
|
return "You must provide exactly one of DomainID or DomainName to authenticate by Username"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrMissingPassword indicates that no password was provided and no token is available.
|
||||||
|
type ErrMissingPassword struct{ BaseError }
|
||||||
|
|
||||||
|
func (e ErrMissingPassword) Error() string {
|
||||||
|
return "You must provide a password to authenticate"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrScopeDomainIDOrDomainName indicates that a domain ID or Name was required in a Scope, but not present.
|
||||||
|
type ErrScopeDomainIDOrDomainName struct{ BaseError }
|
||||||
|
|
||||||
|
func (e ErrScopeDomainIDOrDomainName) Error() string {
|
||||||
|
return "You must provide exactly one of DomainID or DomainName in a Scope with ProjectName"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrScopeProjectIDOrProjectName indicates that both a ProjectID and a ProjectName were provided in a Scope.
|
||||||
|
type ErrScopeProjectIDOrProjectName struct{ BaseError }
|
||||||
|
|
||||||
|
func (e ErrScopeProjectIDOrProjectName) Error() string {
|
||||||
|
return "You must provide at most one of ProjectID or ProjectName in a Scope"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrScopeProjectIDAlone indicates that a ProjectID was provided with other constraints in a Scope.
|
||||||
|
type ErrScopeProjectIDAlone struct{ BaseError }
|
||||||
|
|
||||||
|
func (e ErrScopeProjectIDAlone) Error() string {
|
||||||
|
return "ProjectID must be supplied alone in a Scope"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrScopeDomainName indicates that a DomainName was provided alone in a Scope.
|
||||||
|
type ErrScopeDomainName struct{ BaseError }
|
||||||
|
|
||||||
|
func (e ErrScopeDomainName) Error() string {
|
||||||
|
return "DomainName must be supplied with a ProjectName or ProjectID in a Scope"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrScopeEmpty indicates that no credentials were provided in a Scope.
|
||||||
|
type ErrScopeEmpty struct{ BaseError }
|
||||||
|
|
||||||
|
func (e ErrScopeEmpty) Error() string {
|
||||||
|
return "You must provide either a Project or Domain in a Scope"
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
)
|
||||||
|
|
||||||
|
var nilOptions = gophercloud.AuthOptions{}
|
||||||
|
|
||||||
|
// AuthOptionsFromEnv fills out an identity.AuthOptions structure with the settings found on the various OpenStack
|
||||||
|
// OS_* environment variables. The following variables provide sources of truth: OS_AUTH_URL, OS_USERNAME,
|
||||||
|
// OS_PASSWORD, OS_TENANT_ID, and OS_TENANT_NAME. Of these, OS_USERNAME, OS_PASSWORD, and OS_AUTH_URL must
|
||||||
|
// have settings, or an error will result. OS_TENANT_ID and OS_TENANT_NAME are optional.
|
||||||
|
func AuthOptionsFromEnv() (gophercloud.AuthOptions, error) {
|
||||||
|
authURL := os.Getenv("OS_AUTH_URL")
|
||||||
|
username := os.Getenv("OS_USERNAME")
|
||||||
|
userID := os.Getenv("OS_USERID")
|
||||||
|
password := os.Getenv("OS_PASSWORD")
|
||||||
|
tenantID := os.Getenv("OS_TENANT_ID")
|
||||||
|
tenantName := os.Getenv("OS_TENANT_NAME")
|
||||||
|
domainID := os.Getenv("OS_DOMAIN_ID")
|
||||||
|
domainName := os.Getenv("OS_DOMAIN_NAME")
|
||||||
|
|
||||||
|
if authURL == "" {
|
||||||
|
err := gophercloud.ErrMissingInput{Argument: "authURL"}
|
||||||
|
return nilOptions, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if username == "" && userID == "" {
|
||||||
|
err := gophercloud.ErrMissingInput{Argument: "username"}
|
||||||
|
return nilOptions, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if password == "" {
|
||||||
|
err := gophercloud.ErrMissingInput{Argument: "password"}
|
||||||
|
return nilOptions, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ao := gophercloud.AuthOptions{
|
||||||
|
IdentityEndpoint: authURL,
|
||||||
|
UserID: userID,
|
||||||
|
Username: username,
|
||||||
|
Password: password,
|
||||||
|
TenantID: tenantID,
|
||||||
|
TenantName: tenantName,
|
||||||
|
DomainID: domainID,
|
||||||
|
DomainName: domainName,
|
||||||
|
}
|
||||||
|
|
||||||
|
return ao, nil
|
||||||
|
}
|
5
vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes/doc.go
generated
vendored
Normal file
5
vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
// Package volumes provides information and interaction with volumes in the
|
||||||
|
// OpenStack Block Storage service. A volume is a detachable block storage
|
||||||
|
// device, akin to a USB hard drive. It can only be attached to one instance at
|
||||||
|
// a time.
|
||||||
|
package volumes
|
167
vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes/requests.go
generated
vendored
Normal file
167
vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
package volumes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreateOptsBuilder allows extensions to add additional parameters to the
|
||||||
|
// Create request.
|
||||||
|
type CreateOptsBuilder interface {
|
||||||
|
ToVolumeCreateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOpts contains options for creating a Volume. This object is passed to
|
||||||
|
// the volumes.Create function. For more information about these parameters,
|
||||||
|
// see the Volume object.
|
||||||
|
type CreateOpts struct {
|
||||||
|
Size int `json:"size" required:"true"`
|
||||||
|
Availability string `json:"availability,omitempty"`
|
||||||
|
Description string `json:"display_description,omitempty"`
|
||||||
|
Metadata map[string]string `json:"metadata,omitempty"`
|
||||||
|
Name string `json:"display_name,omitempty"`
|
||||||
|
SnapshotID string `json:"snapshot_id,omitempty"`
|
||||||
|
SourceVolID string `json:"source_volid,omitempty"`
|
||||||
|
ImageID string `json:"imageRef,omitempty"`
|
||||||
|
VolumeType string `json:"volume_type,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToVolumeCreateMap assembles a request body based on the contents of a
|
||||||
|
// CreateOpts.
|
||||||
|
func (opts CreateOpts) ToVolumeCreateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "volume")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create will create a new Volume based on the values in CreateOpts. To extract
|
||||||
|
// the Volume object from the response, call the Extract method on the
|
||||||
|
// CreateResult.
|
||||||
|
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
|
||||||
|
b, err := opts.ToVolumeCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200, 201},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete will delete the existing Volume with the provided ID.
|
||||||
|
func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) {
|
||||||
|
_, r.Err = client.Delete(deleteURL(client, id), nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get retrieves the Volume with the provided ID. To extract the Volume object
|
||||||
|
// from the response, call the Extract method on the GetResult.
|
||||||
|
func Get(client *gophercloud.ServiceClient, id string) (r GetResult) {
|
||||||
|
_, r.Err = client.Get(getURL(client, id), &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListOptsBuilder allows extensions to add additional parameters to the List
|
||||||
|
// request.
|
||||||
|
type ListOptsBuilder interface {
|
||||||
|
ToVolumeListQuery() (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListOpts holds options for listing Volumes. It is passed to the volumes.List
|
||||||
|
// function.
|
||||||
|
type ListOpts struct {
|
||||||
|
// admin-only option. Set it to true to see all tenant volumes.
|
||||||
|
AllTenants bool `q:"all_tenants"`
|
||||||
|
// List only volumes that contain Metadata.
|
||||||
|
Metadata map[string]string `q:"metadata"`
|
||||||
|
// List only volumes that have Name as the display name.
|
||||||
|
Name string `q:"display_name"`
|
||||||
|
// List only volumes that have a status of Status.
|
||||||
|
Status string `q:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToVolumeListQuery formats a ListOpts into a query string.
|
||||||
|
func (opts ListOpts) ToVolumeListQuery() (string, error) {
|
||||||
|
q, err := gophercloud.BuildQueryString(opts)
|
||||||
|
return q.String(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// List returns Volumes optionally limited by the conditions provided in ListOpts.
|
||||||
|
func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
|
||||||
|
url := listURL(client)
|
||||||
|
if opts != nil {
|
||||||
|
query, err := opts.ToVolumeListQuery()
|
||||||
|
if err != nil {
|
||||||
|
return pagination.Pager{Err: err}
|
||||||
|
}
|
||||||
|
url += query
|
||||||
|
}
|
||||||
|
return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
|
||||||
|
return VolumePage{pagination.SinglePageBase(r)}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateOptsBuilder allows extensions to add additional parameters to the
|
||||||
|
// Update request.
|
||||||
|
type UpdateOptsBuilder interface {
|
||||||
|
ToVolumeUpdateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateOpts contain options for updating an existing Volume. This object is passed
|
||||||
|
// to the volumes.Update function. For more information about the parameters, see
|
||||||
|
// the Volume object.
|
||||||
|
type UpdateOpts struct {
|
||||||
|
Name string `json:"display_name,omitempty"`
|
||||||
|
Description string `json:"display_description,omitempty"`
|
||||||
|
Metadata map[string]string `json:"metadata,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToVolumeUpdateMap assembles a request body based on the contents of an
|
||||||
|
// UpdateOpts.
|
||||||
|
func (opts UpdateOpts) ToVolumeUpdateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "volume")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update will update the Volume with provided information. To extract the updated
|
||||||
|
// Volume from the response, call the Extract method on the UpdateResult.
|
||||||
|
func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) {
|
||||||
|
b, err := opts.ToVolumeUpdateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = client.Put(updateURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDFromName is a convienience function that returns a server's ID given its name.
|
||||||
|
func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
|
||||||
|
count := 0
|
||||||
|
id := ""
|
||||||
|
pages, err := List(client, nil).AllPages()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
all, err := ExtractVolumes(pages)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range all {
|
||||||
|
if s.Name == name {
|
||||||
|
count++
|
||||||
|
id = s.ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch count {
|
||||||
|
case 0:
|
||||||
|
return "", gophercloud.ErrResourceNotFound{Name: name, ResourceType: "volume"}
|
||||||
|
case 1:
|
||||||
|
return id, nil
|
||||||
|
default:
|
||||||
|
return "", gophercloud.ErrMultipleResourcesFound{Name: name, Count: count, ResourceType: "volume"}
|
||||||
|
}
|
||||||
|
}
|
89
vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes/results.go
generated
vendored
Normal file
89
vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes/results.go
generated
vendored
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
package volumes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Volume contains all the information associated with an OpenStack Volume.
|
||||||
|
type Volume struct {
|
||||||
|
// Current status of the volume.
|
||||||
|
Status string `json:"status"`
|
||||||
|
// Human-readable display name for the volume.
|
||||||
|
Name string `json:"display_name"`
|
||||||
|
// Instances onto which the volume is attached.
|
||||||
|
Attachments []map[string]interface{} `json:"attachments"`
|
||||||
|
// This parameter is no longer used.
|
||||||
|
AvailabilityZone string `json:"availability_zone"`
|
||||||
|
// Indicates whether this is a bootable volume.
|
||||||
|
Bootable string `json:"bootable"`
|
||||||
|
// The date when this volume was created.
|
||||||
|
CreatedAt gophercloud.JSONRFC3339MilliNoZ `json:"created_at"`
|
||||||
|
// Human-readable description for the volume.
|
||||||
|
Description string `json:"display_description"`
|
||||||
|
// The type of volume to create, either SATA or SSD.
|
||||||
|
VolumeType string `json:"volume_type"`
|
||||||
|
// The ID of the snapshot from which the volume was created
|
||||||
|
SnapshotID string `json:"snapshot_id"`
|
||||||
|
// The ID of another block storage volume from which the current volume was created
|
||||||
|
SourceVolID string `json:"source_volid"`
|
||||||
|
// Arbitrary key-value pairs defined by the user.
|
||||||
|
Metadata map[string]string `json:"metadata"`
|
||||||
|
// Unique identifier for the volume.
|
||||||
|
ID string `json:"id"`
|
||||||
|
// Size of the volume in GB.
|
||||||
|
Size int `json:"size"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateResult contains the response body and error from a Create request.
|
||||||
|
type CreateResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResult contains the response body and error from a Get request.
|
||||||
|
type GetResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteResult contains the response body and error from a Delete request.
|
||||||
|
type DeleteResult struct {
|
||||||
|
gophercloud.ErrResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// VolumePage is a pagination.pager that is returned from a call to the List function.
|
||||||
|
type VolumePage struct {
|
||||||
|
pagination.SinglePageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty returns true if a VolumePage contains no Volumes.
|
||||||
|
func (r VolumePage) IsEmpty() (bool, error) {
|
||||||
|
volumes, err := ExtractVolumes(r)
|
||||||
|
return len(volumes) == 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractVolumes extracts and returns Volumes. It is used while iterating over a volumes.List call.
|
||||||
|
func ExtractVolumes(r pagination.Page) ([]Volume, error) {
|
||||||
|
var s struct {
|
||||||
|
Volumes []Volume `json:"volumes"`
|
||||||
|
}
|
||||||
|
err := (r.(VolumePage)).ExtractInto(&s)
|
||||||
|
return s.Volumes, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateResult contains the response body and error from an Update request.
|
||||||
|
type UpdateResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
type commonResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract will get the Volume object out of the commonResult object.
|
||||||
|
func (r commonResult) Extract() (*Volume, error) {
|
||||||
|
var s struct {
|
||||||
|
Volume *Volume `json:"volume"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return s.Volume, err
|
||||||
|
}
|
23
vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes/urls.go
generated
vendored
Normal file
23
vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes/urls.go
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package volumes
|
||||||
|
|
||||||
|
import "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
func createURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return c.ServiceURL("volumes")
|
||||||
|
}
|
||||||
|
|
||||||
|
func listURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return createURL(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return c.ServiceURL("volumes", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return deleteURL(c, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return deleteURL(c, id)
|
||||||
|
}
|
22
vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes/util.go
generated
vendored
Normal file
22
vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes/util.go
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package volumes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WaitForStatus will continually poll the resource, checking for a particular
|
||||||
|
// status. It will do this for the amount of seconds defined.
|
||||||
|
func WaitForStatus(c *gophercloud.ServiceClient, id, status string, secs int) error {
|
||||||
|
return gophercloud.WaitFor(secs, func() (bool, error) {
|
||||||
|
current, err := Get(c, id).Extract()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if current.Status == status {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
})
|
||||||
|
}
|
5
vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/doc.go
generated
vendored
Normal file
5
vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
// Package volumes provides information and interaction with volumes in the
|
||||||
|
// OpenStack Block Storage service. A volume is a detachable block storage
|
||||||
|
// device, akin to a USB hard drive. It can only be attached to one instance at
|
||||||
|
// a time.
|
||||||
|
package volumes
|
182
vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/requests.go
generated
vendored
Normal file
182
vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
package volumes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreateOptsBuilder allows extensions to add additional parameters to the
|
||||||
|
// Create request.
|
||||||
|
type CreateOptsBuilder interface {
|
||||||
|
ToVolumeCreateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOpts contains options for creating a Volume. This object is passed to
|
||||||
|
// the volumes.Create function. For more information about these parameters,
|
||||||
|
// see the Volume object.
|
||||||
|
type CreateOpts struct {
|
||||||
|
// The size of the volume, in GB
|
||||||
|
Size int `json:"size" required:"true"`
|
||||||
|
// The availability zone
|
||||||
|
AvailabilityZone string `json:"availability_zone,omitempty"`
|
||||||
|
// ConsistencyGroupID is the ID of a consistency group
|
||||||
|
ConsistencyGroupID string `json:"consistencygroup_id,omitempty"`
|
||||||
|
// The volume description
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
// One or more metadata key and value pairs to associate with the volume
|
||||||
|
Metadata map[string]string `json:"metadata,omitempty"`
|
||||||
|
// The volume name
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
// the ID of the existing volume snapshot
|
||||||
|
SnapshotID string `json:"snapshot_id,omitempty"`
|
||||||
|
// SourceReplica is a UUID of an existing volume to replicate with
|
||||||
|
SourceReplica string `json:"source_replica,omitempty"`
|
||||||
|
// the ID of the existing volume
|
||||||
|
SourceVolID string `json:"source_volid,omitempty"`
|
||||||
|
// The ID of the image from which you want to create the volume.
|
||||||
|
// Required to create a bootable volume.
|
||||||
|
ImageID string `json:"imageRef,omitempty"`
|
||||||
|
// The associated volume type
|
||||||
|
VolumeType string `json:"volume_type,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToVolumeCreateMap assembles a request body based on the contents of a
|
||||||
|
// CreateOpts.
|
||||||
|
func (opts CreateOpts) ToVolumeCreateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "volume")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create will create a new Volume based on the values in CreateOpts. To extract
|
||||||
|
// the Volume object from the response, call the Extract method on the
|
||||||
|
// CreateResult.
|
||||||
|
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
|
||||||
|
b, err := opts.ToVolumeCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{202},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete will delete the existing Volume with the provided ID.
|
||||||
|
func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) {
|
||||||
|
_, r.Err = client.Delete(deleteURL(client, id), nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get retrieves the Volume with the provided ID. To extract the Volume object
|
||||||
|
// from the response, call the Extract method on the GetResult.
|
||||||
|
func Get(client *gophercloud.ServiceClient, id string) (r GetResult) {
|
||||||
|
_, r.Err = client.Get(getURL(client, id), &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListOptsBuilder allows extensions to add additional parameters to the List
|
||||||
|
// request.
|
||||||
|
type ListOptsBuilder interface {
|
||||||
|
ToVolumeListQuery() (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListOpts holds options for listing Volumes. It is passed to the volumes.List
|
||||||
|
// function.
|
||||||
|
type ListOpts struct {
|
||||||
|
// admin-only option. Set it to true to see all tenant volumes.
|
||||||
|
AllTenants bool `q:"all_tenants"`
|
||||||
|
// List only volumes that contain Metadata.
|
||||||
|
Metadata map[string]string `q:"metadata"`
|
||||||
|
// List only volumes that have Name as the display name.
|
||||||
|
Name string `q:"name"`
|
||||||
|
// List only volumes that have a status of Status.
|
||||||
|
Status string `q:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToVolumeListQuery formats a ListOpts into a query string.
|
||||||
|
func (opts ListOpts) ToVolumeListQuery() (string, error) {
|
||||||
|
q, err := gophercloud.BuildQueryString(opts)
|
||||||
|
return q.String(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// List returns Volumes optionally limited by the conditions provided in ListOpts.
|
||||||
|
func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
|
||||||
|
url := listURL(client)
|
||||||
|
if opts != nil {
|
||||||
|
query, err := opts.ToVolumeListQuery()
|
||||||
|
if err != nil {
|
||||||
|
return pagination.Pager{Err: err}
|
||||||
|
}
|
||||||
|
url += query
|
||||||
|
}
|
||||||
|
|
||||||
|
return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
|
||||||
|
return VolumePage{pagination.SinglePageBase(r)}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateOptsBuilder allows extensions to add additional parameters to the
|
||||||
|
// Update request.
|
||||||
|
type UpdateOptsBuilder interface {
|
||||||
|
ToVolumeUpdateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateOpts contain options for updating an existing Volume. This object is passed
|
||||||
|
// to the volumes.Update function. For more information about the parameters, see
|
||||||
|
// the Volume object.
|
||||||
|
type UpdateOpts struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Metadata map[string]string `json:"metadata,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToVolumeUpdateMap assembles a request body based on the contents of an
|
||||||
|
// UpdateOpts.
|
||||||
|
func (opts UpdateOpts) ToVolumeUpdateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "volume")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update will update the Volume with provided information. To extract the updated
|
||||||
|
// Volume from the response, call the Extract method on the UpdateResult.
|
||||||
|
func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) {
|
||||||
|
b, err := opts.ToVolumeUpdateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = client.Put(updateURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDFromName is a convienience function that returns a server's ID given its name.
|
||||||
|
func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
|
||||||
|
count := 0
|
||||||
|
id := ""
|
||||||
|
pages, err := List(client, nil).AllPages()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
all, err := ExtractVolumes(pages)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range all {
|
||||||
|
if s.Name == name {
|
||||||
|
count++
|
||||||
|
id = s.ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch count {
|
||||||
|
case 0:
|
||||||
|
return "", gophercloud.ErrResourceNotFound{Name: name, ResourceType: "volume"}
|
||||||
|
case 1:
|
||||||
|
return id, nil
|
||||||
|
default:
|
||||||
|
return "", gophercloud.ErrMultipleResourcesFound{Name: name, Count: count, ResourceType: "volume"}
|
||||||
|
}
|
||||||
|
}
|
121
vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/results.go
generated
vendored
Normal file
121
vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/results.go
generated
vendored
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
package volumes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Attachment struct {
|
||||||
|
AttachedAt gophercloud.JSONRFC3339MilliNoZ `json:"attached_at"`
|
||||||
|
AttachmentID string `json:"attachment_id"`
|
||||||
|
Device string `json:"device"`
|
||||||
|
HostName string `json:"host_name"`
|
||||||
|
ID string `json:"id"`
|
||||||
|
ServerID string `json:"server_id"`
|
||||||
|
VolumeID string `json:"volume_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Volume contains all the information associated with an OpenStack Volume.
|
||||||
|
type Volume struct {
|
||||||
|
// Unique identifier for the volume.
|
||||||
|
ID string `json:"id"`
|
||||||
|
// Current status of the volume.
|
||||||
|
Status string `json:"status"`
|
||||||
|
// Size of the volume in GB.
|
||||||
|
Size int `json:"size"`
|
||||||
|
// AvailabilityZone is which availability zone the volume is in.
|
||||||
|
AvailabilityZone string `json:"availability_zone"`
|
||||||
|
// The date when this volume was created.
|
||||||
|
CreatedAt gophercloud.JSONRFC3339MilliNoZ `json:"created_at"`
|
||||||
|
// The date when this volume was last updated
|
||||||
|
UpdatedAt gophercloud.JSONRFC3339MilliNoZ `json:"updated_at"`
|
||||||
|
// Instances onto which the volume is attached.
|
||||||
|
Attachments []Attachment `json:"attachments"`
|
||||||
|
// Human-readable display name for the volume.
|
||||||
|
Name string `json:"name"`
|
||||||
|
// Human-readable description for the volume.
|
||||||
|
Description string `json:"description"`
|
||||||
|
// The type of volume to create, either SATA or SSD.
|
||||||
|
VolumeType string `json:"volume_type"`
|
||||||
|
// The ID of the snapshot from which the volume was created
|
||||||
|
SnapshotID string `json:"snapshot_id"`
|
||||||
|
// The ID of another block storage volume from which the current volume was created
|
||||||
|
SourceVolID string `json:"source_volid"`
|
||||||
|
// Arbitrary key-value pairs defined by the user.
|
||||||
|
Metadata map[string]string `json:"metadata"`
|
||||||
|
// UserID is the id of the user who created the volume.
|
||||||
|
UserID string `json:"user_id"`
|
||||||
|
// Indicates whether this is a bootable volume.
|
||||||
|
Bootable string `json:"bootable"`
|
||||||
|
// Encrypted denotes if the volume is encrypted.
|
||||||
|
Encrypted bool `json:"encrypted"`
|
||||||
|
// ReplicationStatus is the status of replication.
|
||||||
|
ReplicationStatus string `json:"replication_status"`
|
||||||
|
// ConsistencyGroupID is the consistency group ID.
|
||||||
|
ConsistencyGroupID string `json:"consistencygroup_id"`
|
||||||
|
// Multiattach denotes if the volume is multi-attach capable.
|
||||||
|
Multiattach bool `json:"multiattach"`
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
THESE BELONG IN EXTENSIONS:
|
||||||
|
// ReplicationDriverData contains data about the replication driver.
|
||||||
|
ReplicationDriverData string `json:"os-volume-replication:driver_data"`
|
||||||
|
// ReplicationExtendedStatus contains extended status about replication.
|
||||||
|
ReplicationExtendedStatus string `json:"os-volume-replication:extended_status"`
|
||||||
|
// TenantID is the id of the project that owns the volume.
|
||||||
|
TenantID string `json:"os-vol-tenant-attr:tenant_id"`
|
||||||
|
*/
|
||||||
|
|
||||||
|
// VolumePage is a pagination.pager that is returned from a call to the List function.
|
||||||
|
type VolumePage struct {
|
||||||
|
pagination.SinglePageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty returns true if a ListResult contains no Volumes.
|
||||||
|
func (r VolumePage) IsEmpty() (bool, error) {
|
||||||
|
volumes, err := ExtractVolumes(r)
|
||||||
|
return len(volumes) == 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractVolumes extracts and returns Volumes. It is used while iterating over a volumes.List call.
|
||||||
|
func ExtractVolumes(r pagination.Page) ([]Volume, error) {
|
||||||
|
var s struct {
|
||||||
|
Volumes []Volume `json:"volumes"`
|
||||||
|
}
|
||||||
|
err := (r.(VolumePage)).ExtractInto(&s)
|
||||||
|
return s.Volumes, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type commonResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract will get the Volume object out of the commonResult object.
|
||||||
|
func (r commonResult) Extract() (*Volume, error) {
|
||||||
|
var s struct {
|
||||||
|
Volume *Volume `json:"volume"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return s.Volume, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateResult contains the response body and error from a Create request.
|
||||||
|
type CreateResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResult contains the response body and error from a Get request.
|
||||||
|
type GetResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateResult contains the response body and error from an Update request.
|
||||||
|
type UpdateResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteResult contains the response body and error from a Delete request.
|
||||||
|
type DeleteResult struct {
|
||||||
|
gophercloud.ErrResult
|
||||||
|
}
|
23
vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/urls.go
generated
vendored
Normal file
23
vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/urls.go
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package volumes
|
||||||
|
|
||||||
|
import "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
func createURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return c.ServiceURL("volumes")
|
||||||
|
}
|
||||||
|
|
||||||
|
func listURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return c.ServiceURL("volumes", "detail")
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return c.ServiceURL("volumes", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return deleteURL(c, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return deleteURL(c, id)
|
||||||
|
}
|
22
vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/util.go
generated
vendored
Normal file
22
vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes/util.go
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package volumes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WaitForStatus will continually poll the resource, checking for a particular
|
||||||
|
// status. It will do this for the amount of seconds defined.
|
||||||
|
func WaitForStatus(c *gophercloud.ServiceClient, id, status string, secs int) error {
|
||||||
|
return gophercloud.WaitFor(secs, func() (bool, error) {
|
||||||
|
current, err := Get(c, id).Extract()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if current.Status == status {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,311 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
tokens2 "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens"
|
||||||
|
tokens3 "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
v20 = "v2.0"
|
||||||
|
v30 = "v3.0"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewClient prepares an unauthenticated ProviderClient instance.
|
||||||
|
// Most users will probably prefer using the AuthenticatedClient function instead.
|
||||||
|
// This is useful if you wish to explicitly control the version of the identity service that's used for authentication explicitly,
|
||||||
|
// for example.
|
||||||
|
func NewClient(endpoint string) (*gophercloud.ProviderClient, error) {
|
||||||
|
u, err := url.Parse(endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hadPath := u.Path != ""
|
||||||
|
u.Path, u.RawQuery, u.Fragment = "", "", ""
|
||||||
|
base := u.String()
|
||||||
|
|
||||||
|
endpoint = gophercloud.NormalizeURL(endpoint)
|
||||||
|
base = gophercloud.NormalizeURL(base)
|
||||||
|
|
||||||
|
if hadPath {
|
||||||
|
return &gophercloud.ProviderClient{
|
||||||
|
IdentityBase: base,
|
||||||
|
IdentityEndpoint: endpoint,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &gophercloud.ProviderClient{
|
||||||
|
IdentityBase: base,
|
||||||
|
IdentityEndpoint: "",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthenticatedClient logs in to an OpenStack cloud found at the identity endpoint specified by options, acquires a token, and
|
||||||
|
// returns a Client instance that's ready to operate.
|
||||||
|
// It first queries the root identity endpoint to determine which versions of the identity service are supported, then chooses
|
||||||
|
// the most recent identity service available to proceed.
|
||||||
|
func AuthenticatedClient(options gophercloud.AuthOptions) (*gophercloud.ProviderClient, error) {
|
||||||
|
client, err := NewClient(options.IdentityEndpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = Authenticate(client, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authenticate or re-authenticate against the most recent identity service supported at the provided endpoint.
|
||||||
|
func Authenticate(client *gophercloud.ProviderClient, options gophercloud.AuthOptions) error {
|
||||||
|
versions := []*utils.Version{
|
||||||
|
{ID: v20, Priority: 20, Suffix: "/v2.0/"},
|
||||||
|
{ID: v30, Priority: 30, Suffix: "/v3/"},
|
||||||
|
}
|
||||||
|
|
||||||
|
chosen, endpoint, err := utils.ChooseVersion(client, versions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch chosen.ID {
|
||||||
|
case v20:
|
||||||
|
return v2auth(client, endpoint, options, gophercloud.EndpointOpts{})
|
||||||
|
case v30:
|
||||||
|
return v3auth(client, endpoint, &options, gophercloud.EndpointOpts{})
|
||||||
|
default:
|
||||||
|
// The switch statement must be out of date from the versions list.
|
||||||
|
return fmt.Errorf("Unrecognized identity version: %s", chosen.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthenticateV2 explicitly authenticates against the identity v2 endpoint.
|
||||||
|
func AuthenticateV2(client *gophercloud.ProviderClient, options gophercloud.AuthOptions, eo gophercloud.EndpointOpts) error {
|
||||||
|
return v2auth(client, "", options, eo)
|
||||||
|
}
|
||||||
|
|
||||||
|
func v2auth(client *gophercloud.ProviderClient, endpoint string, options gophercloud.AuthOptions, eo gophercloud.EndpointOpts) error {
|
||||||
|
v2Client, err := NewIdentityV2(client, eo)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if endpoint != "" {
|
||||||
|
v2Client.Endpoint = endpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
v2Opts := tokens2.AuthOptions{
|
||||||
|
IdentityEndpoint: options.IdentityEndpoint,
|
||||||
|
Username: options.Username,
|
||||||
|
Password: options.Password,
|
||||||
|
TenantID: options.TenantID,
|
||||||
|
TenantName: options.TenantName,
|
||||||
|
AllowReauth: options.AllowReauth,
|
||||||
|
TokenID: options.TokenID,
|
||||||
|
}
|
||||||
|
|
||||||
|
result := tokens2.Create(v2Client, v2Opts)
|
||||||
|
|
||||||
|
token, err := result.ExtractToken()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
catalog, err := result.ExtractServiceCatalog()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.AllowReauth {
|
||||||
|
client.ReauthFunc = func() error {
|
||||||
|
client.TokenID = ""
|
||||||
|
return v2auth(client, endpoint, options, eo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
client.TokenID = token.ID
|
||||||
|
client.EndpointLocator = func(opts gophercloud.EndpointOpts) (string, error) {
|
||||||
|
return V2EndpointURL(catalog, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthenticateV3 explicitly authenticates against the identity v3 service.
|
||||||
|
func AuthenticateV3(client *gophercloud.ProviderClient, options tokens3.AuthOptionsBuilder, eo gophercloud.EndpointOpts) error {
|
||||||
|
return v3auth(client, "", options, eo)
|
||||||
|
}
|
||||||
|
|
||||||
|
func v3auth(client *gophercloud.ProviderClient, endpoint string, opts tokens3.AuthOptionsBuilder, eo gophercloud.EndpointOpts) error {
|
||||||
|
// Override the generated service endpoint with the one returned by the version endpoint.
|
||||||
|
v3Client, err := NewIdentityV3(client, eo)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if endpoint != "" {
|
||||||
|
v3Client.Endpoint = endpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
result := tokens3.Create(v3Client, opts)
|
||||||
|
|
||||||
|
token, err := result.ExtractToken()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
catalog, err := result.ExtractServiceCatalog()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
client.TokenID = token.ID
|
||||||
|
|
||||||
|
if opts.CanReauth() {
|
||||||
|
client.ReauthFunc = func() error {
|
||||||
|
client.TokenID = ""
|
||||||
|
return v3auth(client, endpoint, opts, eo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
client.EndpointLocator = func(opts gophercloud.EndpointOpts) (string, error) {
|
||||||
|
return V3EndpointURL(catalog, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewIdentityV2 creates a ServiceClient that may be used to interact with the v2 identity service.
|
||||||
|
func NewIdentityV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
|
||||||
|
endpoint := client.IdentityBase + "v2.0/"
|
||||||
|
var err error
|
||||||
|
if !reflect.DeepEqual(eo, gophercloud.EndpointOpts{}) {
|
||||||
|
eo.ApplyDefaults("identity")
|
||||||
|
endpoint, err = client.EndpointLocator(eo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &gophercloud.ServiceClient{
|
||||||
|
ProviderClient: client,
|
||||||
|
Endpoint: endpoint,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewIdentityV3 creates a ServiceClient that may be used to access the v3 identity service.
|
||||||
|
func NewIdentityV3(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
|
||||||
|
endpoint := client.IdentityBase + "v3/"
|
||||||
|
var err error
|
||||||
|
if !reflect.DeepEqual(eo, gophercloud.EndpointOpts{}) {
|
||||||
|
eo.ApplyDefaults("identity")
|
||||||
|
endpoint, err = client.EndpointLocator(eo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &gophercloud.ServiceClient{
|
||||||
|
ProviderClient: client,
|
||||||
|
Endpoint: endpoint,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewObjectStorageV1 creates a ServiceClient that may be used with the v1 object storage package.
|
||||||
|
func NewObjectStorageV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
|
||||||
|
eo.ApplyDefaults("object-store")
|
||||||
|
url, err := client.EndpointLocator(eo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewComputeV2 creates a ServiceClient that may be used with the v2 compute package.
|
||||||
|
func NewComputeV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
|
||||||
|
eo.ApplyDefaults("compute")
|
||||||
|
url, err := client.EndpointLocator(eo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNetworkV2 creates a ServiceClient that may be used with the v2 network package.
|
||||||
|
func NewNetworkV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
|
||||||
|
eo.ApplyDefaults("network")
|
||||||
|
url, err := client.EndpointLocator(eo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &gophercloud.ServiceClient{
|
||||||
|
ProviderClient: client,
|
||||||
|
Endpoint: url,
|
||||||
|
ResourceBase: url + "v2.0/",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBlockStorageV1 creates a ServiceClient that may be used to access the v1 block storage service.
|
||||||
|
func NewBlockStorageV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
|
||||||
|
eo.ApplyDefaults("volume")
|
||||||
|
url, err := client.EndpointLocator(eo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBlockStorageV2 creates a ServiceClient that may be used to access the v2 block storage service.
|
||||||
|
func NewBlockStorageV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
|
||||||
|
eo.ApplyDefaults("volumev2")
|
||||||
|
url, err := client.EndpointLocator(eo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSharedFileSystemV2 creates a ServiceClient that may be used to access the v2 shared file system service.
|
||||||
|
func NewSharedFileSystemV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
|
||||||
|
eo.ApplyDefaults("sharev2")
|
||||||
|
url, err := client.EndpointLocator(eo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCDNV1 creates a ServiceClient that may be used to access the OpenStack v1
|
||||||
|
// CDN service.
|
||||||
|
func NewCDNV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
|
||||||
|
eo.ApplyDefaults("cdn")
|
||||||
|
url, err := client.EndpointLocator(eo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOrchestrationV1 creates a ServiceClient that may be used to access the v1 orchestration service.
|
||||||
|
func NewOrchestrationV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
|
||||||
|
eo.ApplyDefaults("orchestration")
|
||||||
|
url, err := client.EndpointLocator(eo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDBV1 creates a ServiceClient that may be used to access the v1 DB service.
|
||||||
|
func NewDBV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
|
||||||
|
eo.ApplyDefaults("database")
|
||||||
|
url, err := client.EndpointLocator(eo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
|
||||||
|
}
|
120
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume/requests.go
generated
vendored
Normal file
120
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
package bootfromvolume
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
// DestinationType represents the type of medium being used as the
|
||||||
|
// destination of the bootable device.
|
||||||
|
DestinationType string
|
||||||
|
|
||||||
|
// SourceType represents the type of medium being used as the source of the
|
||||||
|
// bootable device.
|
||||||
|
SourceType string
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DestinationLocal DestinationType is for using an ephemeral disk as the
|
||||||
|
// destination.
|
||||||
|
DestinationLocal DestinationType = "local"
|
||||||
|
|
||||||
|
// DestinationVolume DestinationType is for using a volume as the destination.
|
||||||
|
DestinationVolume DestinationType = "volume"
|
||||||
|
|
||||||
|
// SourceBlank SourceType is for a "blank" or empty source.
|
||||||
|
SourceBlank SourceType = "blank"
|
||||||
|
|
||||||
|
// SourceImage SourceType is for using images as the source of a block device.
|
||||||
|
SourceImage SourceType = "image"
|
||||||
|
|
||||||
|
// SourceSnapshot SourceType is for using a volume snapshot as the source of
|
||||||
|
// a block device.
|
||||||
|
SourceSnapshot SourceType = "snapshot"
|
||||||
|
|
||||||
|
// SourceVolume SourceType is for using a volume as the source of block
|
||||||
|
// device.
|
||||||
|
SourceVolume SourceType = "volume"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BlockDevice is a structure with options for creating block devices in a
|
||||||
|
// server. The block device may be created from an image, snapshot, new volume,
|
||||||
|
// or existing volume. The destination may be a new volume, existing volume
|
||||||
|
// which will be attached to the instance, ephemeral disk, or boot device.
|
||||||
|
type BlockDevice struct {
|
||||||
|
// SourceType must be one of: "volume", "snapshot", "image", or "blank".
|
||||||
|
SourceType SourceType `json:"source_type" required:"true"`
|
||||||
|
|
||||||
|
// UUID is the unique identifier for the existing volume, snapshot, or
|
||||||
|
// image (see above).
|
||||||
|
UUID string `json:"uuid,omitempty"`
|
||||||
|
|
||||||
|
// BootIndex is the boot index. It defaults to 0.
|
||||||
|
BootIndex int `json:"boot_index"`
|
||||||
|
|
||||||
|
// DeleteOnTermination specifies whether or not to delete the attached volume
|
||||||
|
// when the server is deleted. Defaults to `false`.
|
||||||
|
DeleteOnTermination bool `json:"delete_on_termination"`
|
||||||
|
|
||||||
|
// DestinationType is the type that gets created. Possible values are "volume"
|
||||||
|
// and "local".
|
||||||
|
DestinationType DestinationType `json:"destination_type,omitempty"`
|
||||||
|
|
||||||
|
// GuestFormat specifies the format of the block device.
|
||||||
|
GuestFormat string `json:"guest_format,omitempty"`
|
||||||
|
|
||||||
|
// VolumeSize is the size of the volume to create (in gigabytes). This can be
|
||||||
|
// omitted for existing volumes.
|
||||||
|
VolumeSize int `json:"volume_size,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOptsExt is a structure that extends the server `CreateOpts` structure
|
||||||
|
// by allowing for a block device mapping.
|
||||||
|
type CreateOptsExt struct {
|
||||||
|
servers.CreateOptsBuilder
|
||||||
|
BlockDevice []BlockDevice `json:"block_device_mapping_v2,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToServerCreateMap adds the block device mapping option to the base server
|
||||||
|
// creation options.
|
||||||
|
func (opts CreateOptsExt) ToServerCreateMap() (map[string]interface{}, error) {
|
||||||
|
base, err := opts.CreateOptsBuilder.ToServerCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(opts.BlockDevice) == 0 {
|
||||||
|
err := gophercloud.ErrMissingInput{}
|
||||||
|
err.Argument = "bootfromvolume.CreateOptsExt.BlockDevice"
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
serverMap := base["server"].(map[string]interface{})
|
||||||
|
|
||||||
|
blockDevice := make([]map[string]interface{}, len(opts.BlockDevice))
|
||||||
|
|
||||||
|
for i, bd := range opts.BlockDevice {
|
||||||
|
b, err := gophercloud.BuildRequestBody(bd, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
blockDevice[i] = b
|
||||||
|
}
|
||||||
|
serverMap["block_device_mapping_v2"] = blockDevice
|
||||||
|
|
||||||
|
return base, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create requests the creation of a server from the given block device mapping.
|
||||||
|
func Create(client *gophercloud.ServiceClient, opts servers.CreateOptsBuilder) (r servers.CreateResult) {
|
||||||
|
b, err := opts.ToServerCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200, 202},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
10
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume/results.go
generated
vendored
Normal file
10
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume/results.go
generated
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
package bootfromvolume
|
||||||
|
|
||||||
|
import (
|
||||||
|
os "github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreateResult temporarily contains the response from a Create call.
|
||||||
|
type CreateResult struct {
|
||||||
|
os.CreateResult
|
||||||
|
}
|
7
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume/urls.go
generated
vendored
Normal file
7
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume/urls.go
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package bootfromvolume
|
||||||
|
|
||||||
|
import "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
func createURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return c.ServiceURL("os-volumes_boot")
|
||||||
|
}
|
3
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/floatingips/doc.go
generated
vendored
Normal file
3
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/floatingips/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
// Package floatingips provides the ability to manage floating ips through
|
||||||
|
// nova-network
|
||||||
|
package floatingips
|
112
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/floatingips/requests.go
generated
vendored
Normal file
112
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/floatingips/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
package floatingips
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// List returns a Pager that allows you to iterate over a collection of FloatingIPs.
|
||||||
|
func List(client *gophercloud.ServiceClient) pagination.Pager {
|
||||||
|
return pagination.NewPager(client, listURL(client), func(r pagination.PageResult) pagination.Page {
|
||||||
|
return FloatingIPPage{pagination.SinglePageBase(r)}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOptsBuilder describes struct types that can be accepted by the Create call. Notable, the
|
||||||
|
// CreateOpts struct in this package does.
|
||||||
|
type CreateOptsBuilder interface {
|
||||||
|
ToFloatingIPCreateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOpts specifies a Floating IP allocation request
|
||||||
|
type CreateOpts struct {
|
||||||
|
// Pool is the pool of floating IPs to allocate one from
|
||||||
|
Pool string `json:"pool" required:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToFloatingIPCreateMap constructs a request body from CreateOpts.
|
||||||
|
func (opts CreateOpts) ToFloatingIPCreateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create requests the creation of a new floating IP
|
||||||
|
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
|
||||||
|
b, err := opts.ToFloatingIPCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns data about a previously created FloatingIP.
|
||||||
|
func Get(client *gophercloud.ServiceClient, id string) (r GetResult) {
|
||||||
|
_, r.Err = client.Get(getURL(client, id), &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete requests the deletion of a previous allocated FloatingIP.
|
||||||
|
func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) {
|
||||||
|
_, r.Err = client.Delete(deleteURL(client, id), nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssociateOptsBuilder is the interface types must satfisfy to be used as
|
||||||
|
// Associate options
|
||||||
|
type AssociateOptsBuilder interface {
|
||||||
|
ToFloatingIPAssociateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssociateOpts specifies the required information to associate a floating IP with an instance
|
||||||
|
type AssociateOpts struct {
|
||||||
|
// FloatingIP is the floating IP to associate with an instance
|
||||||
|
FloatingIP string `json:"address" required:"true"`
|
||||||
|
// FixedIP is an optional fixed IP address of the server
|
||||||
|
FixedIP string `json:"fixed_address,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToFloatingIPAssociateMap constructs a request body from AssociateOpts.
|
||||||
|
func (opts AssociateOpts) ToFloatingIPAssociateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "addFloatingIp")
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssociateInstance pairs an allocated floating IP with an instance.
|
||||||
|
func AssociateInstance(client *gophercloud.ServiceClient, serverID string, opts AssociateOptsBuilder) (r AssociateResult) {
|
||||||
|
b, err := opts.ToFloatingIPAssociateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = client.Post(associateURL(client, serverID), b, nil, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisassociateOptsBuilder is the interface types must satfisfy to be used as
|
||||||
|
// Disassociate options
|
||||||
|
type DisassociateOptsBuilder interface {
|
||||||
|
ToFloatingIPDisassociateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisassociateOpts specifies the required information to disassociate a floating IP with an instance
|
||||||
|
type DisassociateOpts struct {
|
||||||
|
FloatingIP string `json:"address" required:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToFloatingIPDisassociateMap constructs a request body from AssociateOpts.
|
||||||
|
func (opts DisassociateOpts) ToFloatingIPDisassociateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "removeFloatingIp")
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisassociateInstance decouples an allocated floating IP from an instance
|
||||||
|
func DisassociateInstance(client *gophercloud.ServiceClient, serverID string, opts DisassociateOptsBuilder) (r DisassociateResult) {
|
||||||
|
b, err := opts.ToFloatingIPDisassociateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = client.Post(disassociateURL(client, serverID), b, nil, nil)
|
||||||
|
return
|
||||||
|
}
|
91
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/floatingips/results.go
generated
vendored
Normal file
91
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/floatingips/results.go
generated
vendored
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
package floatingips
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A FloatingIP is an IP that can be associated with an instance
|
||||||
|
type FloatingIP struct {
|
||||||
|
// ID is a unique ID of the Floating IP
|
||||||
|
ID string `json:"id"`
|
||||||
|
|
||||||
|
// FixedIP is the IP of the instance related to the Floating IP
|
||||||
|
FixedIP string `json:"fixed_ip,omitempty"`
|
||||||
|
|
||||||
|
// InstanceID is the ID of the instance that is using the Floating IP
|
||||||
|
InstanceID string `json:"instance_id"`
|
||||||
|
|
||||||
|
// IP is the actual Floating IP
|
||||||
|
IP string `json:"ip"`
|
||||||
|
|
||||||
|
// Pool is the pool of floating IPs that this floating IP belongs to
|
||||||
|
Pool string `json:"pool"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FloatingIPPage stores a single, only page of FloatingIPs
|
||||||
|
// results from a List call.
|
||||||
|
type FloatingIPPage struct {
|
||||||
|
pagination.SinglePageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty determines whether or not a FloatingIPsPage is empty.
|
||||||
|
func (page FloatingIPPage) IsEmpty() (bool, error) {
|
||||||
|
va, err := ExtractFloatingIPs(page)
|
||||||
|
return len(va) == 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractFloatingIPs interprets a page of results as a slice of
|
||||||
|
// FloatingIPs.
|
||||||
|
func ExtractFloatingIPs(r pagination.Page) ([]FloatingIP, error) {
|
||||||
|
var s struct {
|
||||||
|
FloatingIPs []FloatingIP `json:"floating_ips"`
|
||||||
|
}
|
||||||
|
err := (r.(FloatingIPPage)).ExtractInto(&s)
|
||||||
|
return s.FloatingIPs, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FloatingIPResult is the raw result from a FloatingIP request.
|
||||||
|
type FloatingIPResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract is a method that attempts to interpret any FloatingIP resource
|
||||||
|
// response as a FloatingIP struct.
|
||||||
|
func (r FloatingIPResult) Extract() (*FloatingIP, error) {
|
||||||
|
var s struct {
|
||||||
|
FloatingIP *FloatingIP `json:"floating_ip"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return s.FloatingIP, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateResult is the response from a Create operation. Call its Extract method to interpret it
|
||||||
|
// as a FloatingIP.
|
||||||
|
type CreateResult struct {
|
||||||
|
FloatingIPResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResult is the response from a Get operation. Call its Extract method to interpret it
|
||||||
|
// as a FloatingIP.
|
||||||
|
type GetResult struct {
|
||||||
|
FloatingIPResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteResult is the response from a Delete operation. Call its Extract method to determine if
|
||||||
|
// the call succeeded or failed.
|
||||||
|
type DeleteResult struct {
|
||||||
|
gophercloud.ErrResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssociateResult is the response from a Delete operation. Call its Extract method to determine if
|
||||||
|
// the call succeeded or failed.
|
||||||
|
type AssociateResult struct {
|
||||||
|
gophercloud.ErrResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisassociateResult is the response from a Delete operation. Call its Extract method to determine if
|
||||||
|
// the call succeeded or failed.
|
||||||
|
type DisassociateResult struct {
|
||||||
|
gophercloud.ErrResult
|
||||||
|
}
|
37
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/floatingips/urls.go
generated
vendored
Normal file
37
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/floatingips/urls.go
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package floatingips
|
||||||
|
|
||||||
|
import "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
const resourcePath = "os-floating-ips"
|
||||||
|
|
||||||
|
func resourceURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return c.ServiceURL(resourcePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func listURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return resourceURL(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return resourceURL(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return c.ServiceURL(resourcePath, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return getURL(c, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func serverURL(c *gophercloud.ServiceClient, serverID string) string {
|
||||||
|
return c.ServiceURL("servers/" + serverID + "/action")
|
||||||
|
}
|
||||||
|
|
||||||
|
func associateURL(c *gophercloud.ServiceClient, serverID string) string {
|
||||||
|
return serverURL(c, serverID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func disassociateURL(c *gophercloud.ServiceClient, serverID string) string {
|
||||||
|
return serverURL(c, serverID)
|
||||||
|
}
|
3
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs/doc.go
generated
vendored
Normal file
3
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
// Package keypairs provides information and interaction with the Keypairs
|
||||||
|
// extension for the OpenStack Compute service.
|
||||||
|
package keypairs
|
84
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs/requests.go
generated
vendored
Normal file
84
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
package keypairs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreateOptsExt adds a KeyPair option to the base CreateOpts.
|
||||||
|
type CreateOptsExt struct {
|
||||||
|
servers.CreateOptsBuilder
|
||||||
|
KeyName string `json:"key_name,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToServerCreateMap adds the key_name and, optionally, key_data options to
|
||||||
|
// the base server creation options.
|
||||||
|
func (opts CreateOptsExt) ToServerCreateMap() (map[string]interface{}, error) {
|
||||||
|
base, err := opts.CreateOptsBuilder.ToServerCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.KeyName == "" {
|
||||||
|
return base, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
serverMap := base["server"].(map[string]interface{})
|
||||||
|
serverMap["key_name"] = opts.KeyName
|
||||||
|
|
||||||
|
return base, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// List returns a Pager that allows you to iterate over a collection of KeyPairs.
|
||||||
|
func List(client *gophercloud.ServiceClient) pagination.Pager {
|
||||||
|
return pagination.NewPager(client, listURL(client), func(r pagination.PageResult) pagination.Page {
|
||||||
|
return KeyPairPage{pagination.SinglePageBase(r)}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOptsBuilder describes struct types that can be accepted by the Create call. Notable, the
|
||||||
|
// CreateOpts struct in this package does.
|
||||||
|
type CreateOptsBuilder interface {
|
||||||
|
ToKeyPairCreateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOpts specifies keypair creation or import parameters.
|
||||||
|
type CreateOpts struct {
|
||||||
|
// Name is a friendly name to refer to this KeyPair in other services.
|
||||||
|
Name string `json:"name" required:"true"`
|
||||||
|
// PublicKey [optional] is a pregenerated OpenSSH-formatted public key. If provided, this key
|
||||||
|
// will be imported and no new key will be created.
|
||||||
|
PublicKey string `json:"public_key,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToKeyPairCreateMap constructs a request body from CreateOpts.
|
||||||
|
func (opts CreateOpts) ToKeyPairCreateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "keypair")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create requests the creation of a new keypair on the server, or to import a pre-existing
|
||||||
|
// keypair.
|
||||||
|
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
|
||||||
|
b, err := opts.ToKeyPairCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns public data about a previously uploaded KeyPair.
|
||||||
|
func Get(client *gophercloud.ServiceClient, name string) (r GetResult) {
|
||||||
|
_, r.Err = client.Get(getURL(client, name), &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete requests the deletion of a previous stored KeyPair from the server.
|
||||||
|
func Delete(client *gophercloud.ServiceClient, name string) (r DeleteResult) {
|
||||||
|
_, r.Err = client.Delete(deleteURL(client, name), nil)
|
||||||
|
return
|
||||||
|
}
|
86
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs/results.go
generated
vendored
Normal file
86
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs/results.go
generated
vendored
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
package keypairs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// KeyPair is an SSH key known to the OpenStack cluster that is available to be injected into
|
||||||
|
// servers.
|
||||||
|
type KeyPair struct {
|
||||||
|
// Name is used to refer to this keypair from other services within this region.
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// Fingerprint is a short sequence of bytes that can be used to authenticate or validate a longer
|
||||||
|
// public key.
|
||||||
|
Fingerprint string `json:"fingerprint"`
|
||||||
|
|
||||||
|
// PublicKey is the public key from this pair, in OpenSSH format. "ssh-rsa AAAAB3Nz..."
|
||||||
|
PublicKey string `json:"public_key"`
|
||||||
|
|
||||||
|
// PrivateKey is the private key from this pair, in PEM format.
|
||||||
|
// "-----BEGIN RSA PRIVATE KEY-----\nMIICXA..." It is only present if this keypair was just
|
||||||
|
// returned from a Create call
|
||||||
|
PrivateKey string `json:"private_key"`
|
||||||
|
|
||||||
|
// UserID is the user who owns this keypair.
|
||||||
|
UserID string `json:"user_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyPairPage stores a single, only page of KeyPair results from a List call.
|
||||||
|
type KeyPairPage struct {
|
||||||
|
pagination.SinglePageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty determines whether or not a KeyPairPage is empty.
|
||||||
|
func (page KeyPairPage) IsEmpty() (bool, error) {
|
||||||
|
ks, err := ExtractKeyPairs(page)
|
||||||
|
return len(ks) == 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractKeyPairs interprets a page of results as a slice of KeyPairs.
|
||||||
|
func ExtractKeyPairs(r pagination.Page) ([]KeyPair, error) {
|
||||||
|
type pair struct {
|
||||||
|
KeyPair KeyPair `json:"keypair"`
|
||||||
|
}
|
||||||
|
var s struct {
|
||||||
|
KeyPairs []pair `json:"keypairs"`
|
||||||
|
}
|
||||||
|
err := (r.(KeyPairPage)).ExtractInto(&s)
|
||||||
|
results := make([]KeyPair, len(s.KeyPairs))
|
||||||
|
for i, pair := range s.KeyPairs {
|
||||||
|
results[i] = pair.KeyPair
|
||||||
|
}
|
||||||
|
return results, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type keyPairResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract is a method that attempts to interpret any KeyPair resource response as a KeyPair struct.
|
||||||
|
func (r keyPairResult) Extract() (*KeyPair, error) {
|
||||||
|
var s struct {
|
||||||
|
KeyPair *KeyPair `json:"keypair"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return s.KeyPair, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateResult is the response from a Create operation. Call its Extract method to interpret it
|
||||||
|
// as a KeyPair.
|
||||||
|
type CreateResult struct {
|
||||||
|
keyPairResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResult is the response from a Get operation. Call its Extract method to interpret it
|
||||||
|
// as a KeyPair.
|
||||||
|
type GetResult struct {
|
||||||
|
keyPairResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteResult is the response from a Delete operation. Call its Extract method to determine if
|
||||||
|
// the call succeeded or failed.
|
||||||
|
type DeleteResult struct {
|
||||||
|
gophercloud.ErrResult
|
||||||
|
}
|
25
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs/urls.go
generated
vendored
Normal file
25
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs/urls.go
generated
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package keypairs
|
||||||
|
|
||||||
|
import "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
const resourcePath = "os-keypairs"
|
||||||
|
|
||||||
|
func resourceURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return c.ServiceURL(resourcePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func listURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return resourceURL(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return resourceURL(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getURL(c *gophercloud.ServiceClient, name string) string {
|
||||||
|
return c.ServiceURL(resourcePath, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteURL(c *gophercloud.ServiceClient, name string) string {
|
||||||
|
return getURL(c, name)
|
||||||
|
}
|
3
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/schedulerhints/doc.go
generated
vendored
Normal file
3
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/schedulerhints/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
// Package schedulerhints enables instances to provide the OpenStack scheduler
|
||||||
|
// hints about where they should be placed in the cloud.
|
||||||
|
package schedulerhints
|
148
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/schedulerhints/requests.go
generated
vendored
Normal file
148
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/schedulerhints/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
package schedulerhints
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SchedulerHints represents a set of scheduling hints that are passed to the
|
||||||
|
// OpenStack scheduler
|
||||||
|
type SchedulerHints struct {
|
||||||
|
// Group specifies a Server Group to place the instance in.
|
||||||
|
Group string
|
||||||
|
// DifferentHost will place the instance on a compute node that does not
|
||||||
|
// host the given instances.
|
||||||
|
DifferentHost []string
|
||||||
|
// SameHost will place the instance on a compute node that hosts the given
|
||||||
|
// instances.
|
||||||
|
SameHost []string
|
||||||
|
// Query is a conditional statement that results in compute nodes able to
|
||||||
|
// host the instance.
|
||||||
|
Query []interface{}
|
||||||
|
// TargetCell specifies a cell name where the instance will be placed.
|
||||||
|
TargetCell string `json:"target_cell,omitempty"`
|
||||||
|
// BuildNearHostIP specifies a subnet of compute nodes to host the instance.
|
||||||
|
BuildNearHostIP string
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOptsBuilder builds the scheduler hints into a serializable format.
|
||||||
|
type CreateOptsBuilder interface {
|
||||||
|
ToServerSchedulerHintsCreateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToServerSchedulerHintsMap builds the scheduler hints into a serializable format.
|
||||||
|
func (opts SchedulerHints) ToServerSchedulerHintsCreateMap() (map[string]interface{}, error) {
|
||||||
|
sh := make(map[string]interface{})
|
||||||
|
|
||||||
|
uuidRegex, _ := regexp.Compile("^[a-z0-9]{8}-[a-z0-9]{4}-[1-5][a-z0-9]{3}-[a-z0-9]{4}-[a-z0-9]{12}$")
|
||||||
|
|
||||||
|
if opts.Group != "" {
|
||||||
|
if !uuidRegex.MatchString(opts.Group) {
|
||||||
|
err := gophercloud.ErrInvalidInput{}
|
||||||
|
err.Argument = "schedulerhints.SchedulerHints.Group"
|
||||||
|
err.Value = opts.Group
|
||||||
|
err.Info = "Group must be a UUID"
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sh["group"] = opts.Group
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(opts.DifferentHost) > 0 {
|
||||||
|
for _, diffHost := range opts.DifferentHost {
|
||||||
|
if !uuidRegex.MatchString(diffHost) {
|
||||||
|
err := gophercloud.ErrInvalidInput{}
|
||||||
|
err.Argument = "schedulerhints.SchedulerHints.DifferentHost"
|
||||||
|
err.Value = opts.DifferentHost
|
||||||
|
err.Info = "The hosts must be in UUID format."
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sh["different_host"] = opts.DifferentHost
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(opts.SameHost) > 0 {
|
||||||
|
for _, sameHost := range opts.SameHost {
|
||||||
|
if !uuidRegex.MatchString(sameHost) {
|
||||||
|
err := gophercloud.ErrInvalidInput{}
|
||||||
|
err.Argument = "schedulerhints.SchedulerHints.SameHost"
|
||||||
|
err.Value = opts.SameHost
|
||||||
|
err.Info = "The hosts must be in UUID format."
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sh["same_host"] = opts.SameHost
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Query can be something simple like:
|
||||||
|
[">=", "$free_ram_mb", 1024]
|
||||||
|
|
||||||
|
Or more complex like:
|
||||||
|
['and',
|
||||||
|
['>=', '$free_ram_mb', 1024],
|
||||||
|
['>=', '$free_disk_mb', 200 * 1024]
|
||||||
|
]
|
||||||
|
|
||||||
|
Because of the possible complexity, just make sure the length is a minimum of 3.
|
||||||
|
*/
|
||||||
|
if len(opts.Query) > 0 {
|
||||||
|
if len(opts.Query) < 3 {
|
||||||
|
err := gophercloud.ErrInvalidInput{}
|
||||||
|
err.Argument = "schedulerhints.SchedulerHints.Query"
|
||||||
|
err.Value = opts.Query
|
||||||
|
err.Info = "Must be a conditional statement in the format of [op,variable,value]"
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sh["query"] = opts.Query
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.TargetCell != "" {
|
||||||
|
sh["target_cell"] = opts.TargetCell
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.BuildNearHostIP != "" {
|
||||||
|
if _, _, err := net.ParseCIDR(opts.BuildNearHostIP); err != nil {
|
||||||
|
err := gophercloud.ErrInvalidInput{}
|
||||||
|
err.Argument = "schedulerhints.SchedulerHints.BuildNearHostIP"
|
||||||
|
err.Value = opts.BuildNearHostIP
|
||||||
|
err.Info = "Must be a valid subnet in the form 192.168.1.1/24"
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ipParts := strings.Split(opts.BuildNearHostIP, "/")
|
||||||
|
sh["build_near_host_ip"] = ipParts[0]
|
||||||
|
sh["cidr"] = "/" + ipParts[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return sh, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOptsExt adds a SchedulerHints option to the base CreateOpts.
|
||||||
|
type CreateOptsExt struct {
|
||||||
|
servers.CreateOptsBuilder
|
||||||
|
// SchedulerHints provides a set of hints to the scheduler.
|
||||||
|
SchedulerHints CreateOptsBuilder
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToServerCreateMap adds the SchedulerHints option to the base server creation options.
|
||||||
|
func (opts CreateOptsExt) ToServerCreateMap() (map[string]interface{}, error) {
|
||||||
|
base, err := opts.CreateOptsBuilder.ToServerCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
schedulerHints, err := opts.SchedulerHints.ToServerSchedulerHintsCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(schedulerHints) == 0 {
|
||||||
|
return base, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
base["os:scheduler_hints"] = schedulerHints
|
||||||
|
|
||||||
|
return base, nil
|
||||||
|
}
|
1
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/secgroups/doc.go
generated
vendored
Normal file
1
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/secgroups/doc.go
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package secgroups
|
171
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/secgroups/requests.go
generated
vendored
Normal file
171
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/secgroups/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
package secgroups
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
func commonList(client *gophercloud.ServiceClient, url string) pagination.Pager {
|
||||||
|
return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
|
||||||
|
return SecurityGroupPage{pagination.SinglePageBase(r)}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// List will return a collection of all the security groups for a particular
|
||||||
|
// tenant.
|
||||||
|
func List(client *gophercloud.ServiceClient) pagination.Pager {
|
||||||
|
return commonList(client, rootURL(client))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListByServer will return a collection of all the security groups which are
|
||||||
|
// associated with a particular server.
|
||||||
|
func ListByServer(client *gophercloud.ServiceClient, serverID string) pagination.Pager {
|
||||||
|
return commonList(client, listByServerURL(client, serverID))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupOpts is the underlying struct responsible for creating or updating
|
||||||
|
// security groups. It therefore represents the mutable attributes of a
|
||||||
|
// security group.
|
||||||
|
type GroupOpts struct {
|
||||||
|
// the name of your security group.
|
||||||
|
Name string `json:"name" required:"true"`
|
||||||
|
// the description of your security group.
|
||||||
|
Description string `json:"description" required:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOpts is the struct responsible for creating a security group.
|
||||||
|
type CreateOpts GroupOpts
|
||||||
|
|
||||||
|
// CreateOptsBuilder builds the create options into a serializable format.
|
||||||
|
type CreateOptsBuilder interface {
|
||||||
|
ToSecGroupCreateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToSecGroupCreateMap builds the create options into a serializable format.
|
||||||
|
func (opts CreateOpts) ToSecGroupCreateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "security_group")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create will create a new security group.
|
||||||
|
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
|
||||||
|
b, err := opts.ToSecGroupCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = client.Post(rootURL(client), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateOpts is the struct responsible for updating an existing security group.
|
||||||
|
type UpdateOpts GroupOpts
|
||||||
|
|
||||||
|
// UpdateOptsBuilder builds the update options into a serializable format.
|
||||||
|
type UpdateOptsBuilder interface {
|
||||||
|
ToSecGroupUpdateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToSecGroupUpdateMap builds the update options into a serializable format.
|
||||||
|
func (opts UpdateOpts) ToSecGroupUpdateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "security_group")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update will modify the mutable properties of a security group, notably its
|
||||||
|
// name and description.
|
||||||
|
func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) {
|
||||||
|
b, err := opts.ToSecGroupUpdateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = client.Put(resourceURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get will return details for a particular security group.
|
||||||
|
func Get(client *gophercloud.ServiceClient, id string) (r GetResult) {
|
||||||
|
_, r.Err = client.Get(resourceURL(client, id), &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete will permanently delete a security group from the project.
|
||||||
|
func Delete(client *gophercloud.ServiceClient, id string) (r gophercloud.ErrResult) {
|
||||||
|
_, r.Err = client.Delete(resourceURL(client, id), nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateRuleOpts represents the configuration for adding a new rule to an
|
||||||
|
// existing security group.
|
||||||
|
type CreateRuleOpts struct {
|
||||||
|
// the ID of the group that this rule will be added to.
|
||||||
|
ParentGroupID string `json:"parent_group_id" required:"true"`
|
||||||
|
// the lower bound of the port range that will be opened.
|
||||||
|
FromPort int `json:"from_port"`
|
||||||
|
// the upper bound of the port range that will be opened.
|
||||||
|
ToPort int `json:"to_port"`
|
||||||
|
// the protocol type that will be allowed, e.g. TCP.
|
||||||
|
IPProtocol string `json:"ip_protocol" required:"true"`
|
||||||
|
// ONLY required if FromGroupID is blank. This represents the IP range that
|
||||||
|
// will be the source of network traffic to your security group. Use
|
||||||
|
// 0.0.0.0/0 to allow all IP addresses.
|
||||||
|
CIDR string `json:"cidr,omitempty" or:"FromGroupID"`
|
||||||
|
// ONLY required if CIDR is blank. This value represents the ID of a group
|
||||||
|
// that forwards traffic to the parent group. So, instead of accepting
|
||||||
|
// network traffic from an entire IP range, you can instead refine the
|
||||||
|
// inbound source by an existing security group.
|
||||||
|
FromGroupID string `json:"group_id,omitempty" or:"CIDR"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateRuleOptsBuilder builds the create rule options into a serializable format.
|
||||||
|
type CreateRuleOptsBuilder interface {
|
||||||
|
ToRuleCreateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToRuleCreateMap builds the create rule options into a serializable format.
|
||||||
|
func (opts CreateRuleOpts) ToRuleCreateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "security_group_rule")
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateRule will add a new rule to an existing security group (whose ID is
|
||||||
|
// specified in CreateRuleOpts). You have the option of controlling inbound
|
||||||
|
// traffic from either an IP range (CIDR) or from another security group.
|
||||||
|
func CreateRule(client *gophercloud.ServiceClient, opts CreateRuleOptsBuilder) (r CreateRuleResult) {
|
||||||
|
b, err := opts.ToRuleCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = client.Post(rootRuleURL(client), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteRule will permanently delete a rule from a security group.
|
||||||
|
func DeleteRule(client *gophercloud.ServiceClient, id string) (r gophercloud.ErrResult) {
|
||||||
|
_, r.Err = client.Delete(resourceRuleURL(client, id), nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func actionMap(prefix, groupName string) map[string]map[string]string {
|
||||||
|
return map[string]map[string]string{
|
||||||
|
prefix + "SecurityGroup": map[string]string{"name": groupName},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddServer will associate a server and a security group, enforcing the
|
||||||
|
// rules of the group on the server.
|
||||||
|
func AddServer(client *gophercloud.ServiceClient, serverID, groupName string) (r gophercloud.ErrResult) {
|
||||||
|
_, r.Err = client.Post(serverActionURL(client, serverID), actionMap("add", groupName), &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveServer will disassociate a server from a security group.
|
||||||
|
func RemoveServer(client *gophercloud.ServiceClient, serverID, groupName string) (r gophercloud.ErrResult) {
|
||||||
|
_, r.Err = client.Post(serverActionURL(client, serverID), actionMap("remove", groupName), &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
127
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/secgroups/results.go
generated
vendored
Normal file
127
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/secgroups/results.go
generated
vendored
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
package secgroups
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SecurityGroup represents a security group.
|
||||||
|
type SecurityGroup struct {
|
||||||
|
// The unique ID of the group. If Neutron is installed, this ID will be
|
||||||
|
// represented as a string UUID; if Neutron is not installed, it will be a
|
||||||
|
// numeric ID. For the sake of consistency, we always cast it to a string.
|
||||||
|
ID string
|
||||||
|
|
||||||
|
// The human-readable name of the group, which needs to be unique.
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// The human-readable description of the group.
|
||||||
|
Description string
|
||||||
|
|
||||||
|
// The rules which determine how this security group operates.
|
||||||
|
Rules []Rule
|
||||||
|
|
||||||
|
// The ID of the tenant to which this security group belongs.
|
||||||
|
TenantID string `json:"tenant_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rule represents a security group rule, a policy which determines how a
|
||||||
|
// security group operates and what inbound traffic it allows in.
|
||||||
|
type Rule struct {
|
||||||
|
// The unique ID. If Neutron is installed, this ID will be
|
||||||
|
// represented as a string UUID; if Neutron is not installed, it will be a
|
||||||
|
// numeric ID. For the sake of consistency, we always cast it to a string.
|
||||||
|
ID string
|
||||||
|
|
||||||
|
// The lower bound of the port range which this security group should open up
|
||||||
|
FromPort int `json:"from_port"`
|
||||||
|
|
||||||
|
// The upper bound of the port range which this security group should open up
|
||||||
|
ToPort int `json:"to_port"`
|
||||||
|
|
||||||
|
// The IP protocol (e.g. TCP) which the security group accepts
|
||||||
|
IPProtocol string `json:"ip_protocol"`
|
||||||
|
|
||||||
|
// The CIDR IP range whose traffic can be received
|
||||||
|
IPRange IPRange `json:"ip_range"`
|
||||||
|
|
||||||
|
// The security group ID to which this rule belongs
|
||||||
|
ParentGroupID string `json:"parent_group_id"`
|
||||||
|
|
||||||
|
// Not documented.
|
||||||
|
Group Group
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPRange represents the IP range whose traffic will be accepted by the
|
||||||
|
// security group.
|
||||||
|
type IPRange struct {
|
||||||
|
CIDR string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group represents a group.
|
||||||
|
type Group struct {
|
||||||
|
TenantID string `json:"tenant_id"`
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecurityGroupPage is a single page of a SecurityGroup collection.
|
||||||
|
type SecurityGroupPage struct {
|
||||||
|
pagination.SinglePageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty determines whether or not a page of Security Groups contains any results.
|
||||||
|
func (page SecurityGroupPage) IsEmpty() (bool, error) {
|
||||||
|
users, err := ExtractSecurityGroups(page)
|
||||||
|
return len(users) == 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractSecurityGroups returns a slice of SecurityGroups contained in a single page of results.
|
||||||
|
func ExtractSecurityGroups(r pagination.Page) ([]SecurityGroup, error) {
|
||||||
|
var s struct {
|
||||||
|
SecurityGroups []SecurityGroup `json:"security_groups"`
|
||||||
|
}
|
||||||
|
err := (r.(SecurityGroupPage)).ExtractInto(&s)
|
||||||
|
return s.SecurityGroups, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type commonResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateResult represents the result of a create operation.
|
||||||
|
type CreateResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResult represents the result of a get operation.
|
||||||
|
type GetResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateResult represents the result of an update operation.
|
||||||
|
type UpdateResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract will extract a SecurityGroup struct from most responses.
|
||||||
|
func (r commonResult) Extract() (*SecurityGroup, error) {
|
||||||
|
var s struct {
|
||||||
|
SecurityGroup *SecurityGroup `json:"security_group"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return s.SecurityGroup, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateRuleResult represents the result when adding rules to a security group.
|
||||||
|
type CreateRuleResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract will extract a Rule struct from a CreateRuleResult.
|
||||||
|
func (r CreateRuleResult) Extract() (*Rule, error) {
|
||||||
|
var s struct {
|
||||||
|
Rule *Rule `json:"security_group_rule"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return s.Rule, err
|
||||||
|
}
|
32
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/secgroups/urls.go
generated
vendored
Normal file
32
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/secgroups/urls.go
generated
vendored
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
package secgroups
|
||||||
|
|
||||||
|
import "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
const (
|
||||||
|
secgrouppath = "os-security-groups"
|
||||||
|
rulepath = "os-security-group-rules"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return c.ServiceURL(secgrouppath, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func rootURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return c.ServiceURL(secgrouppath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func listByServerURL(c *gophercloud.ServiceClient, serverID string) string {
|
||||||
|
return c.ServiceURL("servers", serverID, secgrouppath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func rootRuleURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return c.ServiceURL(rulepath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceRuleURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return c.ServiceURL(rulepath, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func serverActionURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return c.ServiceURL("servers", id, "action")
|
||||||
|
}
|
2
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/servergroups/doc.go
generated
vendored
Normal file
2
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/servergroups/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
// Package servergroups provides the ability to manage server groups
|
||||||
|
package servergroups
|
57
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/servergroups/requests.go
generated
vendored
Normal file
57
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/servergroups/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package servergroups
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// List returns a Pager that allows you to iterate over a collection of ServerGroups.
|
||||||
|
func List(client *gophercloud.ServiceClient) pagination.Pager {
|
||||||
|
return pagination.NewPager(client, listURL(client), func(r pagination.PageResult) pagination.Page {
|
||||||
|
return ServerGroupPage{pagination.SinglePageBase(r)}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOptsBuilder describes struct types that can be accepted by the Create call. Notably, the
|
||||||
|
// CreateOpts struct in this package does.
|
||||||
|
type CreateOptsBuilder interface {
|
||||||
|
ToServerGroupCreateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOpts specifies a Server Group allocation request
|
||||||
|
type CreateOpts struct {
|
||||||
|
// Name is the name of the server group
|
||||||
|
Name string `json:"name" required:"true"`
|
||||||
|
// Policies are the server group policies
|
||||||
|
Policies []string `json:"policies" required:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToServerGroupCreateMap constructs a request body from CreateOpts.
|
||||||
|
func (opts CreateOpts) ToServerGroupCreateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "server_group")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create requests the creation of a new Server Group
|
||||||
|
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
|
||||||
|
b, err := opts.ToServerGroupCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns data about a previously created ServerGroup.
|
||||||
|
func Get(client *gophercloud.ServiceClient, id string) (r GetResult) {
|
||||||
|
_, r.Err = client.Get(getURL(client, id), &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete requests the deletion of a previously allocated ServerGroup.
|
||||||
|
func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) {
|
||||||
|
_, r.Err = client.Delete(deleteURL(client, id), nil)
|
||||||
|
return
|
||||||
|
}
|
78
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/servergroups/results.go
generated
vendored
Normal file
78
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/servergroups/results.go
generated
vendored
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
package servergroups
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A ServerGroup creates a policy for instance placement in the cloud
|
||||||
|
type ServerGroup struct {
|
||||||
|
// ID is the unique ID of the Server Group.
|
||||||
|
ID string `json:"id"`
|
||||||
|
|
||||||
|
// Name is the common name of the server group.
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// Polices are the group policies.
|
||||||
|
Policies []string `json:"policies"`
|
||||||
|
|
||||||
|
// Members are the members of the server group.
|
||||||
|
Members []string `json:"members"`
|
||||||
|
|
||||||
|
// Metadata includes a list of all user-specified key-value pairs attached to the Server Group.
|
||||||
|
Metadata map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerGroupPage stores a single, only page of ServerGroups
|
||||||
|
// results from a List call.
|
||||||
|
type ServerGroupPage struct {
|
||||||
|
pagination.SinglePageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty determines whether or not a ServerGroupsPage is empty.
|
||||||
|
func (page ServerGroupPage) IsEmpty() (bool, error) {
|
||||||
|
va, err := ExtractServerGroups(page)
|
||||||
|
return len(va) == 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractServerGroups interprets a page of results as a slice of
|
||||||
|
// ServerGroups.
|
||||||
|
func ExtractServerGroups(r pagination.Page) ([]ServerGroup, error) {
|
||||||
|
var s struct {
|
||||||
|
ServerGroups []ServerGroup `json:"server_groups"`
|
||||||
|
}
|
||||||
|
err := (r.(ServerGroupPage)).ExtractInto(&s)
|
||||||
|
return s.ServerGroups, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerGroupResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract is a method that attempts to interpret any Server Group resource
|
||||||
|
// response as a ServerGroup struct.
|
||||||
|
func (r ServerGroupResult) Extract() (*ServerGroup, error) {
|
||||||
|
var s struct {
|
||||||
|
ServerGroup *ServerGroup `json:"server_group"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return s.ServerGroup, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateResult is the response from a Create operation. Call its Extract method to interpret it
|
||||||
|
// as a ServerGroup.
|
||||||
|
type CreateResult struct {
|
||||||
|
ServerGroupResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResult is the response from a Get operation. Call its Extract method to interpret it
|
||||||
|
// as a ServerGroup.
|
||||||
|
type GetResult struct {
|
||||||
|
ServerGroupResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteResult is the response from a Delete operation. Call its Extract method to determine if
|
||||||
|
// the call succeeded or failed.
|
||||||
|
type DeleteResult struct {
|
||||||
|
gophercloud.ErrResult
|
||||||
|
}
|
25
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/servergroups/urls.go
generated
vendored
Normal file
25
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/servergroups/urls.go
generated
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package servergroups
|
||||||
|
|
||||||
|
import "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
const resourcePath = "os-server-groups"
|
||||||
|
|
||||||
|
func resourceURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return c.ServiceURL(resourcePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func listURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return resourceURL(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return resourceURL(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return c.ServiceURL(resourcePath, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return getURL(c, id)
|
||||||
|
}
|
5
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/startstop/doc.go
generated
vendored
Normal file
5
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/startstop/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/*
|
||||||
|
Package startstop provides functionality to start and stop servers that have
|
||||||
|
been provisioned by the OpenStack Compute service.
|
||||||
|
*/
|
||||||
|
package startstop
|
19
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/startstop/requests.go
generated
vendored
Normal file
19
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/startstop/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
package startstop
|
||||||
|
|
||||||
|
import "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
func actionURL(client *gophercloud.ServiceClient, id string) string {
|
||||||
|
return client.ServiceURL("servers", id, "action")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start is the operation responsible for starting a Compute server.
|
||||||
|
func Start(client *gophercloud.ServiceClient, id string) (r gophercloud.ErrResult) {
|
||||||
|
_, r.Err = client.Post(actionURL(client, id), map[string]interface{}{"os-start": nil}, nil, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop is the operation responsible for stopping a Compute server.
|
||||||
|
func Stop(client *gophercloud.ServiceClient, id string) (r gophercloud.ErrResult) {
|
||||||
|
_, r.Err = client.Post(actionURL(client, id), map[string]interface{}{"os-stop": nil}, nil, nil)
|
||||||
|
return
|
||||||
|
}
|
2
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/tenantnetworks/doc.go
generated
vendored
Normal file
2
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/tenantnetworks/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
// Package tenantnetworks provides the ability for tenants to see information about the networks they have access to
|
||||||
|
package tenantnetworks
|
19
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/tenantnetworks/requests.go
generated
vendored
Normal file
19
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/tenantnetworks/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
package tenantnetworks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// List returns a Pager that allows you to iterate over a collection of Network.
|
||||||
|
func List(client *gophercloud.ServiceClient) pagination.Pager {
|
||||||
|
return pagination.NewPager(client, listURL(client), func(r pagination.PageResult) pagination.Page {
|
||||||
|
return NetworkPage{pagination.SinglePageBase(r)}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns data about a previously created Network.
|
||||||
|
func Get(client *gophercloud.ServiceClient, id string) (r GetResult) {
|
||||||
|
_, r.Err = client.Get(getURL(client, id), &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
59
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/tenantnetworks/results.go
generated
vendored
Normal file
59
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/tenantnetworks/results.go
generated
vendored
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
package tenantnetworks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Network represents a nova-network that an instance communicates on
|
||||||
|
type Network struct {
|
||||||
|
// CIDR is the IPv4 subnet.
|
||||||
|
CIDR string `json:"cidr"`
|
||||||
|
|
||||||
|
// ID is the UUID of the network.
|
||||||
|
ID string `json:"id"`
|
||||||
|
|
||||||
|
// Name is the common name that the network has.
|
||||||
|
Name string `json:"label"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetworkPage stores a single, only page of Networks
|
||||||
|
// results from a List call.
|
||||||
|
type NetworkPage struct {
|
||||||
|
pagination.SinglePageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty determines whether or not a NetworkPage is empty.
|
||||||
|
func (page NetworkPage) IsEmpty() (bool, error) {
|
||||||
|
va, err := ExtractNetworks(page)
|
||||||
|
return len(va) == 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractNetworks interprets a page of results as a slice of Networks
|
||||||
|
func ExtractNetworks(r pagination.Page) ([]Network, error) {
|
||||||
|
var s struct {
|
||||||
|
Networks []Network `json:"networks"`
|
||||||
|
}
|
||||||
|
err := (r.(NetworkPage)).ExtractInto(&s)
|
||||||
|
return s.Networks, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type NetworkResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract is a method that attempts to interpret any Network resource
|
||||||
|
// response as a Network struct.
|
||||||
|
func (r NetworkResult) Extract() (*Network, error) {
|
||||||
|
var s struct {
|
||||||
|
Network *Network `json:"network"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return s.Network, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResult is the response from a Get operation. Call its Extract method to interpret it
|
||||||
|
// as a Network.
|
||||||
|
type GetResult struct {
|
||||||
|
NetworkResult
|
||||||
|
}
|
17
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/tenantnetworks/urls.go
generated
vendored
Normal file
17
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/tenantnetworks/urls.go
generated
vendored
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package tenantnetworks
|
||||||
|
|
||||||
|
import "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
const resourcePath = "os-tenant-networks"
|
||||||
|
|
||||||
|
func resourceURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return c.ServiceURL(resourcePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func listURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return resourceURL(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return c.ServiceURL(resourcePath, id)
|
||||||
|
}
|
3
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach/doc.go
generated
vendored
Normal file
3
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
// Package volumeattach provides the ability to attach and detach volumes
|
||||||
|
// to instances
|
||||||
|
package volumeattach
|
57
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach/requests.go
generated
vendored
Normal file
57
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package volumeattach
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// List returns a Pager that allows you to iterate over a collection of VolumeAttachments.
|
||||||
|
func List(client *gophercloud.ServiceClient, serverID string) pagination.Pager {
|
||||||
|
return pagination.NewPager(client, listURL(client, serverID), func(r pagination.PageResult) pagination.Page {
|
||||||
|
return VolumeAttachmentPage{pagination.SinglePageBase(r)}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOptsBuilder describes struct types that can be accepted by the Create call. Notable, the
|
||||||
|
// CreateOpts struct in this package does.
|
||||||
|
type CreateOptsBuilder interface {
|
||||||
|
ToVolumeAttachmentCreateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOpts specifies volume attachment creation or import parameters.
|
||||||
|
type CreateOpts struct {
|
||||||
|
// Device is the device that the volume will attach to the instance as. Omit for "auto"
|
||||||
|
Device string `json:"device,omitempty"`
|
||||||
|
// VolumeID is the ID of the volume to attach to the instance
|
||||||
|
VolumeID string `json:"volumeId" required:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToVolumeAttachmentCreateMap constructs a request body from CreateOpts.
|
||||||
|
func (opts CreateOpts) ToVolumeAttachmentCreateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "volumeAttachment")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create requests the creation of a new volume attachment on the server
|
||||||
|
func Create(client *gophercloud.ServiceClient, serverID string, opts CreateOptsBuilder) (r CreateResult) {
|
||||||
|
b, err := opts.ToVolumeAttachmentCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = client.Post(createURL(client, serverID), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns public data about a previously created VolumeAttachment.
|
||||||
|
func Get(client *gophercloud.ServiceClient, serverID, attachmentID string) (r GetResult) {
|
||||||
|
_, r.Err = client.Get(getURL(client, serverID, attachmentID), &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete requests the deletion of a previous stored VolumeAttachment from the server.
|
||||||
|
func Delete(client *gophercloud.ServiceClient, serverID, attachmentID string) (r DeleteResult) {
|
||||||
|
_, r.Err = client.Delete(deleteURL(client, serverID, attachmentID), nil)
|
||||||
|
return
|
||||||
|
}
|
76
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach/results.go
generated
vendored
Normal file
76
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach/results.go
generated
vendored
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
package volumeattach
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// VolumeAttachment controls the attachment of a volume to an instance.
|
||||||
|
type VolumeAttachment struct {
|
||||||
|
// ID is a unique id of the attachment
|
||||||
|
ID string `json:"id"`
|
||||||
|
|
||||||
|
// Device is what device the volume is attached as
|
||||||
|
Device string `json:"device"`
|
||||||
|
|
||||||
|
// VolumeID is the ID of the attached volume
|
||||||
|
VolumeID string `json:"volumeId"`
|
||||||
|
|
||||||
|
// ServerID is the ID of the instance that has the volume attached
|
||||||
|
ServerID string `json:"serverId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// VolumeAttachmentPage stores a single, only page of VolumeAttachments
|
||||||
|
// results from a List call.
|
||||||
|
type VolumeAttachmentPage struct {
|
||||||
|
pagination.SinglePageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty determines whether or not a VolumeAttachmentsPage is empty.
|
||||||
|
func (page VolumeAttachmentPage) IsEmpty() (bool, error) {
|
||||||
|
va, err := ExtractVolumeAttachments(page)
|
||||||
|
return len(va) == 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractVolumeAttachments interprets a page of results as a slice of
|
||||||
|
// VolumeAttachments.
|
||||||
|
func ExtractVolumeAttachments(r pagination.Page) ([]VolumeAttachment, error) {
|
||||||
|
var s struct {
|
||||||
|
VolumeAttachments []VolumeAttachment `json:"volumeAttachments"`
|
||||||
|
}
|
||||||
|
err := (r.(VolumeAttachmentPage)).ExtractInto(&s)
|
||||||
|
return s.VolumeAttachments, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// VolumeAttachmentResult is the result from a volume attachment operation.
|
||||||
|
type VolumeAttachmentResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract is a method that attempts to interpret any VolumeAttachment resource
|
||||||
|
// response as a VolumeAttachment struct.
|
||||||
|
func (r VolumeAttachmentResult) Extract() (*VolumeAttachment, error) {
|
||||||
|
var s struct {
|
||||||
|
VolumeAttachment *VolumeAttachment `json:"volumeAttachment"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return s.VolumeAttachment, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateResult is the response from a Create operation. Call its Extract method to interpret it
|
||||||
|
// as a VolumeAttachment.
|
||||||
|
type CreateResult struct {
|
||||||
|
VolumeAttachmentResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResult is the response from a Get operation. Call its Extract method to interpret it
|
||||||
|
// as a VolumeAttachment.
|
||||||
|
type GetResult struct {
|
||||||
|
VolumeAttachmentResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteResult is the response from a Delete operation. Call its Extract method to determine if
|
||||||
|
// the call succeeded or failed.
|
||||||
|
type DeleteResult struct {
|
||||||
|
gophercloud.ErrResult
|
||||||
|
}
|
25
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach/urls.go
generated
vendored
Normal file
25
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach/urls.go
generated
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package volumeattach
|
||||||
|
|
||||||
|
import "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
const resourcePath = "os-volume_attachments"
|
||||||
|
|
||||||
|
func resourceURL(c *gophercloud.ServiceClient, serverID string) string {
|
||||||
|
return c.ServiceURL("servers", serverID, resourcePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func listURL(c *gophercloud.ServiceClient, serverID string) string {
|
||||||
|
return resourceURL(c, serverID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createURL(c *gophercloud.ServiceClient, serverID string) string {
|
||||||
|
return resourceURL(c, serverID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getURL(c *gophercloud.ServiceClient, serverID, aID string) string {
|
||||||
|
return c.ServiceURL("servers", serverID, resourcePath, aID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteURL(c *gophercloud.ServiceClient, serverID, aID string) string {
|
||||||
|
return getURL(c, serverID, aID)
|
||||||
|
}
|
7
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/doc.go
generated
vendored
Normal file
7
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
// Package flavors provides information and interaction with the flavor API
|
||||||
|
// resource in the OpenStack Compute service.
|
||||||
|
//
|
||||||
|
// A flavor is an available hardware configuration for a server. Each flavor
|
||||||
|
// has a unique combination of disk space, memory capacity and priority for CPU
|
||||||
|
// time.
|
||||||
|
package flavors
|
100
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/requests.go
generated
vendored
Normal file
100
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
package flavors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ListOptsBuilder allows extensions to add additional parameters to the
|
||||||
|
// List request.
|
||||||
|
type ListOptsBuilder interface {
|
||||||
|
ToFlavorListQuery() (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListOpts helps control the results returned by the List() function.
|
||||||
|
// For example, a flavor with a minDisk field of 10 will not be returned if you specify MinDisk set to 20.
|
||||||
|
// Typically, software will use the last ID of the previous call to List to set the Marker for the current call.
|
||||||
|
type ListOpts struct {
|
||||||
|
|
||||||
|
// ChangesSince, if provided, instructs List to return only those things which have changed since the timestamp provided.
|
||||||
|
ChangesSince string `q:"changes-since"`
|
||||||
|
|
||||||
|
// MinDisk and MinRAM, if provided, elides flavors which do not meet your criteria.
|
||||||
|
MinDisk int `q:"minDisk"`
|
||||||
|
MinRAM int `q:"minRam"`
|
||||||
|
|
||||||
|
// Marker and Limit control paging.
|
||||||
|
// Marker instructs List where to start listing from.
|
||||||
|
Marker string `q:"marker"`
|
||||||
|
|
||||||
|
// Limit instructs List to refrain from sending excessively large lists of flavors.
|
||||||
|
Limit int `q:"limit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToFlavorListQuery formats a ListOpts into a query string.
|
||||||
|
func (opts ListOpts) ToFlavorListQuery() (string, error) {
|
||||||
|
q, err := gophercloud.BuildQueryString(opts)
|
||||||
|
return q.String(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListDetail instructs OpenStack to provide a list of flavors.
|
||||||
|
// You may provide criteria by which List curtails its results for easier processing.
|
||||||
|
// See ListOpts for more details.
|
||||||
|
func ListDetail(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
|
||||||
|
url := listURL(client)
|
||||||
|
if opts != nil {
|
||||||
|
query, err := opts.ToFlavorListQuery()
|
||||||
|
if err != nil {
|
||||||
|
return pagination.Pager{Err: err}
|
||||||
|
}
|
||||||
|
url += query
|
||||||
|
}
|
||||||
|
return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
|
||||||
|
return FlavorPage{pagination.LinkedPageBase{PageResult: r}}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get instructs OpenStack to provide details on a single flavor, identified by its ID.
|
||||||
|
// Use ExtractFlavor to convert its result into a Flavor.
|
||||||
|
func Get(client *gophercloud.ServiceClient, id string) (r GetResult) {
|
||||||
|
_, r.Err = client.Get(getURL(client, id), &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDFromName is a convienience function that returns a flavor's ID given its name.
|
||||||
|
func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
|
||||||
|
count := 0
|
||||||
|
id := ""
|
||||||
|
allPages, err := ListDetail(client, nil).AllPages()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
all, err := ExtractFlavors(allPages)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range all {
|
||||||
|
if f.Name == name {
|
||||||
|
count++
|
||||||
|
id = f.ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch count {
|
||||||
|
case 0:
|
||||||
|
err := &gophercloud.ErrResourceNotFound{}
|
||||||
|
err.ResourceType = "flavor"
|
||||||
|
err.Name = name
|
||||||
|
return "", err
|
||||||
|
case 1:
|
||||||
|
return id, nil
|
||||||
|
default:
|
||||||
|
err := &gophercloud.ErrMultipleResourcesFound{}
|
||||||
|
err.ResourceType = "flavor"
|
||||||
|
err.Name = name
|
||||||
|
err.Count = count
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
114
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/results.go
generated
vendored
Normal file
114
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/results.go
generated
vendored
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
package flavors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetResult temporarily holds the response from a Get call.
|
||||||
|
type GetResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract provides access to the individual Flavor returned by the Get function.
|
||||||
|
func (r GetResult) Extract() (*Flavor, error) {
|
||||||
|
var s struct {
|
||||||
|
Flavor *Flavor `json:"flavor"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return s.Flavor, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flavor records represent (virtual) hardware configurations for server resources in a region.
|
||||||
|
type Flavor struct {
|
||||||
|
// The Id field contains the flavor's unique identifier.
|
||||||
|
// For example, this identifier will be useful when specifying which hardware configuration to use for a new server instance.
|
||||||
|
ID string `json:"id"`
|
||||||
|
// The Disk and RA< fields provide a measure of storage space offered by the flavor, in GB and MB, respectively.
|
||||||
|
Disk int `json:"disk"`
|
||||||
|
RAM int `json:"ram"`
|
||||||
|
// The Name field provides a human-readable moniker for the flavor.
|
||||||
|
Name string `json:"name"`
|
||||||
|
RxTxFactor float64 `json:"rxtx_factor"`
|
||||||
|
// Swap indicates how much space is reserved for swap.
|
||||||
|
// If not provided, this field will be set to 0.
|
||||||
|
Swap int `json:"swap"`
|
||||||
|
// VCPUs indicates how many (virtual) CPUs are available for this flavor.
|
||||||
|
VCPUs int `json:"vcpus"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Flavor) UnmarshalJSON(b []byte) error {
|
||||||
|
var flavor struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Disk int `json:"disk"`
|
||||||
|
RAM int `json:"ram"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
RxTxFactor float64 `json:"rxtx_factor"`
|
||||||
|
Swap interface{} `json:"swap"`
|
||||||
|
VCPUs int `json:"vcpus"`
|
||||||
|
}
|
||||||
|
err := json.Unmarshal(b, &flavor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
f.ID = flavor.ID
|
||||||
|
f.Disk = flavor.Disk
|
||||||
|
f.RAM = flavor.RAM
|
||||||
|
f.Name = flavor.Name
|
||||||
|
f.RxTxFactor = flavor.RxTxFactor
|
||||||
|
f.VCPUs = flavor.VCPUs
|
||||||
|
|
||||||
|
switch t := flavor.Swap.(type) {
|
||||||
|
case float64:
|
||||||
|
f.Swap = int(t)
|
||||||
|
case string:
|
||||||
|
switch t {
|
||||||
|
case "":
|
||||||
|
f.Swap = 0
|
||||||
|
default:
|
||||||
|
swap, err := strconv.ParseFloat(t, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f.Swap = int(swap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FlavorPage contains a single page of the response from a List call.
|
||||||
|
type FlavorPage struct {
|
||||||
|
pagination.LinkedPageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty determines if a page contains any results.
|
||||||
|
func (page FlavorPage) IsEmpty() (bool, error) {
|
||||||
|
flavors, err := ExtractFlavors(page)
|
||||||
|
return len(flavors) == 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NextPageURL uses the response's embedded link reference to navigate to the next page of results.
|
||||||
|
func (page FlavorPage) NextPageURL() (string, error) {
|
||||||
|
var s struct {
|
||||||
|
Links []gophercloud.Link `json:"flavors_links"`
|
||||||
|
}
|
||||||
|
err := page.ExtractInto(&s)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return gophercloud.ExtractNextURL(s.Links)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractFlavors provides access to the list of flavors in a page acquired from the List operation.
|
||||||
|
func ExtractFlavors(r pagination.Page) ([]Flavor, error) {
|
||||||
|
var s struct {
|
||||||
|
Flavors []Flavor `json:"flavors"`
|
||||||
|
}
|
||||||
|
err := (r.(FlavorPage)).ExtractInto(&s)
|
||||||
|
return s.Flavors, err
|
||||||
|
}
|
13
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/urls.go
generated
vendored
Normal file
13
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/flavors/urls.go
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package flavors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getURL(client *gophercloud.ServiceClient, id string) string {
|
||||||
|
return client.ServiceURL("flavors", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func listURL(client *gophercloud.ServiceClient) string {
|
||||||
|
return client.ServiceURL("flavors", "detail")
|
||||||
|
}
|
7
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/doc.go
generated
vendored
Normal file
7
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
// Package images provides information and interaction with the image API
|
||||||
|
// resource in the OpenStack Compute service.
|
||||||
|
//
|
||||||
|
// An image is a collection of files used to create or rebuild a server.
|
||||||
|
// Operators provide a number of pre-built OS images by default. You may also
|
||||||
|
// create custom images from cloud servers you have launched.
|
||||||
|
package images
|
102
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/requests.go
generated
vendored
Normal file
102
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
package images
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ListOptsBuilder allows extensions to add additional parameters to the
|
||||||
|
// List request.
|
||||||
|
type ListOptsBuilder interface {
|
||||||
|
ToImageListQuery() (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListOpts contain options for limiting the number of Images returned from a call to ListDetail.
|
||||||
|
type ListOpts struct {
|
||||||
|
// When the image last changed status (in date-time format).
|
||||||
|
ChangesSince string `q:"changes-since"`
|
||||||
|
// The number of Images to return.
|
||||||
|
Limit int `q:"limit"`
|
||||||
|
// UUID of the Image at which to set a marker.
|
||||||
|
Marker string `q:"marker"`
|
||||||
|
// The name of the Image.
|
||||||
|
Name string `q:"name"`
|
||||||
|
// The name of the Server (in URL format).
|
||||||
|
Server string `q:"server"`
|
||||||
|
// The current status of the Image.
|
||||||
|
Status string `q:"status"`
|
||||||
|
// The value of the type of image (e.g. BASE, SERVER, ALL)
|
||||||
|
Type string `q:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToImageListQuery formats a ListOpts into a query string.
|
||||||
|
func (opts ListOpts) ToImageListQuery() (string, error) {
|
||||||
|
q, err := gophercloud.BuildQueryString(opts)
|
||||||
|
return q.String(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListDetail enumerates the available images.
|
||||||
|
func ListDetail(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
|
||||||
|
url := listDetailURL(client)
|
||||||
|
if opts != nil {
|
||||||
|
query, err := opts.ToImageListQuery()
|
||||||
|
if err != nil {
|
||||||
|
return pagination.Pager{Err: err}
|
||||||
|
}
|
||||||
|
url += query
|
||||||
|
}
|
||||||
|
return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
|
||||||
|
return ImagePage{pagination.LinkedPageBase{PageResult: r}}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get acquires additional detail about a specific image by ID.
|
||||||
|
// Use ExtractImage() to interpret the result as an openstack Image.
|
||||||
|
func Get(client *gophercloud.ServiceClient, id string) (r GetResult) {
|
||||||
|
_, r.Err = client.Get(getURL(client, id), &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete deletes the specified image ID.
|
||||||
|
func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) {
|
||||||
|
_, r.Err = client.Delete(deleteURL(client, id), nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDFromName is a convienience function that returns an image's ID given its name.
|
||||||
|
func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
|
||||||
|
count := 0
|
||||||
|
id := ""
|
||||||
|
allPages, err := ListDetail(client, nil).AllPages()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
all, err := ExtractImages(allPages)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range all {
|
||||||
|
if f.Name == name {
|
||||||
|
count++
|
||||||
|
id = f.ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch count {
|
||||||
|
case 0:
|
||||||
|
err := &gophercloud.ErrResourceNotFound{}
|
||||||
|
err.ResourceType = "image"
|
||||||
|
err.Name = name
|
||||||
|
return "", err
|
||||||
|
case 1:
|
||||||
|
return id, nil
|
||||||
|
default:
|
||||||
|
err := &gophercloud.ErrMultipleResourcesFound{}
|
||||||
|
err.ResourceType = "image"
|
||||||
|
err.Name = name
|
||||||
|
err.Count = count
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
83
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/results.go
generated
vendored
Normal file
83
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/results.go
generated
vendored
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
package images
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetResult temporarily stores a Get response.
|
||||||
|
type GetResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteResult represents the result of an image.Delete operation.
|
||||||
|
type DeleteResult struct {
|
||||||
|
gophercloud.ErrResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract interprets a GetResult as an Image.
|
||||||
|
func (r GetResult) Extract() (*Image, error) {
|
||||||
|
var s struct {
|
||||||
|
Image *Image `json:"image"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return s.Image, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Image is used for JSON (un)marshalling.
|
||||||
|
// It provides a description of an OS image.
|
||||||
|
type Image struct {
|
||||||
|
// ID contains the image's unique identifier.
|
||||||
|
ID string
|
||||||
|
|
||||||
|
Created string
|
||||||
|
|
||||||
|
// MinDisk and MinRAM specify the minimum resources a server must provide to be able to install the image.
|
||||||
|
MinDisk int
|
||||||
|
MinRAM int
|
||||||
|
|
||||||
|
// Name provides a human-readable moniker for the OS image.
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// The Progress and Status fields indicate image-creation status.
|
||||||
|
// Any usable image will have 100% progress.
|
||||||
|
Progress int
|
||||||
|
Status string
|
||||||
|
|
||||||
|
Updated string
|
||||||
|
|
||||||
|
Metadata map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImagePage contains a single page of results from a List operation.
|
||||||
|
// Use ExtractImages to convert it into a slice of usable structs.
|
||||||
|
type ImagePage struct {
|
||||||
|
pagination.LinkedPageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty returns true if a page contains no Image results.
|
||||||
|
func (page ImagePage) IsEmpty() (bool, error) {
|
||||||
|
images, err := ExtractImages(page)
|
||||||
|
return len(images) == 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NextPageURL uses the response's embedded link reference to navigate to the next page of results.
|
||||||
|
func (page ImagePage) NextPageURL() (string, error) {
|
||||||
|
var s struct {
|
||||||
|
Links []gophercloud.Link `json:"images_links"`
|
||||||
|
}
|
||||||
|
err := page.ExtractInto(&s)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return gophercloud.ExtractNextURL(s.Links)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractImages converts a page of List results into a slice of usable Image structs.
|
||||||
|
func ExtractImages(r pagination.Page) ([]Image, error) {
|
||||||
|
var s struct {
|
||||||
|
Images []Image `json:"images"`
|
||||||
|
}
|
||||||
|
err := (r.(ImagePage)).ExtractInto(&s)
|
||||||
|
return s.Images, err
|
||||||
|
}
|
15
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/urls.go
generated
vendored
Normal file
15
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/images/urls.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
package images
|
||||||
|
|
||||||
|
import "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
func listDetailURL(client *gophercloud.ServiceClient) string {
|
||||||
|
return client.ServiceURL("images", "detail")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getURL(client *gophercloud.ServiceClient, id string) string {
|
||||||
|
return client.ServiceURL("images", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteURL(client *gophercloud.ServiceClient, id string) string {
|
||||||
|
return client.ServiceURL("images", id)
|
||||||
|
}
|
6
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/doc.go
generated
vendored
Normal file
6
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
// Package servers provides information and interaction with the server API
|
||||||
|
// resource in the OpenStack Compute service.
|
||||||
|
//
|
||||||
|
// A server is a virtual machine instance in the compute system. In order for
|
||||||
|
// one to be provisioned, a valid flavor and image are required.
|
||||||
|
package servers
|
71
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/errors.go
generated
vendored
Normal file
71
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/errors.go
generated
vendored
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
package servers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrNeitherImageIDNorImageNameProvided is the error when neither the image
|
||||||
|
// ID nor the image name is provided for a server operation
|
||||||
|
type ErrNeitherImageIDNorImageNameProvided struct{ gophercloud.ErrMissingInput }
|
||||||
|
|
||||||
|
func (e ErrNeitherImageIDNorImageNameProvided) Error() string {
|
||||||
|
return "One and only one of the image ID and the image name must be provided."
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrNeitherFlavorIDNorFlavorNameProvided is the error when neither the flavor
|
||||||
|
// ID nor the flavor name is provided for a server operation
|
||||||
|
type ErrNeitherFlavorIDNorFlavorNameProvided struct{ gophercloud.ErrMissingInput }
|
||||||
|
|
||||||
|
func (e ErrNeitherFlavorIDNorFlavorNameProvided) Error() string {
|
||||||
|
return "One and only one of the flavor ID and the flavor name must be provided."
|
||||||
|
}
|
||||||
|
|
||||||
|
type ErrNoClientProvidedForIDByName struct{ gophercloud.ErrMissingInput }
|
||||||
|
|
||||||
|
func (e ErrNoClientProvidedForIDByName) Error() string {
|
||||||
|
return "A service client must be provided to find a resource ID by name."
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrInvalidHowParameterProvided is the error when an unknown value is given
|
||||||
|
// for the `how` argument
|
||||||
|
type ErrInvalidHowParameterProvided struct{ gophercloud.ErrInvalidInput }
|
||||||
|
|
||||||
|
// ErrNoAdminPassProvided is the error when an administrative password isn't
|
||||||
|
// provided for a server operation
|
||||||
|
type ErrNoAdminPassProvided struct{ gophercloud.ErrMissingInput }
|
||||||
|
|
||||||
|
// ErrNoImageIDProvided is the error when an image ID isn't provided for a server
|
||||||
|
// operation
|
||||||
|
type ErrNoImageIDProvided struct{ gophercloud.ErrMissingInput }
|
||||||
|
|
||||||
|
// ErrNoIDProvided is the error when a server ID isn't provided for a server
|
||||||
|
// operation
|
||||||
|
type ErrNoIDProvided struct{ gophercloud.ErrMissingInput }
|
||||||
|
|
||||||
|
// ErrServer is a generic error type for servers HTTP operations.
|
||||||
|
type ErrServer struct {
|
||||||
|
gophercloud.ErrUnexpectedResponseCode
|
||||||
|
ID string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (se ErrServer) Error() string {
|
||||||
|
return fmt.Sprintf("Error while executing HTTP request for server [%s]", se.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error404 overrides the generic 404 error message.
|
||||||
|
func (se ErrServer) Error404(e gophercloud.ErrUnexpectedResponseCode) error {
|
||||||
|
se.ErrUnexpectedResponseCode = e
|
||||||
|
return &ErrServerNotFound{se}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrServerNotFound is the error when a 404 is received during server HTTP
|
||||||
|
// operations.
|
||||||
|
type ErrServerNotFound struct {
|
||||||
|
ErrServer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrServerNotFound) Error() string {
|
||||||
|
return fmt.Sprintf("I couldn't find server [%s]", e.ID)
|
||||||
|
}
|
737
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/requests.go
generated
vendored
Normal file
737
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,737 @@
|
||||||
|
package servers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/compute/v2/flavors"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/compute/v2/images"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ListOptsBuilder allows extensions to add additional parameters to the
|
||||||
|
// List request.
|
||||||
|
type ListOptsBuilder interface {
|
||||||
|
ToServerListQuery() (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListOpts allows the filtering and sorting of paginated collections through
|
||||||
|
// the API. Filtering is achieved by passing in struct field values that map to
|
||||||
|
// the server attributes you want to see returned. Marker and Limit are used
|
||||||
|
// for pagination.
|
||||||
|
type ListOpts struct {
|
||||||
|
// A time/date stamp for when the server last changed status.
|
||||||
|
ChangesSince string `q:"changes-since"`
|
||||||
|
|
||||||
|
// Name of the image in URL format.
|
||||||
|
Image string `q:"image"`
|
||||||
|
|
||||||
|
// Name of the flavor in URL format.
|
||||||
|
Flavor string `q:"flavor"`
|
||||||
|
|
||||||
|
// Name of the server as a string; can be queried with regular expressions.
|
||||||
|
// Realize that ?name=bob returns both bob and bobb. If you need to match bob
|
||||||
|
// only, you can use a regular expression matching the syntax of the
|
||||||
|
// underlying database server implemented for Compute.
|
||||||
|
Name string `q:"name"`
|
||||||
|
|
||||||
|
// Value of the status of the server so that you can filter on "ACTIVE" for example.
|
||||||
|
Status string `q:"status"`
|
||||||
|
|
||||||
|
// Name of the host as a string.
|
||||||
|
Host string `q:"host"`
|
||||||
|
|
||||||
|
// UUID of the server at which you want to set a marker.
|
||||||
|
Marker string `q:"marker"`
|
||||||
|
|
||||||
|
// Integer value for the limit of values to return.
|
||||||
|
Limit int `q:"limit"`
|
||||||
|
|
||||||
|
// Bool to show all tenants
|
||||||
|
AllTenants bool `q:"all_tenants"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToServerListQuery formats a ListOpts into a query string.
|
||||||
|
func (opts ListOpts) ToServerListQuery() (string, error) {
|
||||||
|
q, err := gophercloud.BuildQueryString(opts)
|
||||||
|
return q.String(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// List makes a request against the API to list servers accessible to you.
|
||||||
|
func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
|
||||||
|
url := listDetailURL(client)
|
||||||
|
if opts != nil {
|
||||||
|
query, err := opts.ToServerListQuery()
|
||||||
|
if err != nil {
|
||||||
|
return pagination.Pager{Err: err}
|
||||||
|
}
|
||||||
|
url += query
|
||||||
|
}
|
||||||
|
return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
|
||||||
|
return ServerPage{pagination.LinkedPageBase{PageResult: r}}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOptsBuilder describes struct types that can be accepted by the Create call.
|
||||||
|
// The CreateOpts struct in this package does.
|
||||||
|
type CreateOptsBuilder interface {
|
||||||
|
ToServerCreateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Network is used within CreateOpts to control a new server's network attachments.
|
||||||
|
type Network struct {
|
||||||
|
// UUID of a nova-network to attach to the newly provisioned server.
|
||||||
|
// Required unless Port is provided.
|
||||||
|
UUID string
|
||||||
|
|
||||||
|
// Port of a neutron network to attach to the newly provisioned server.
|
||||||
|
// Required unless UUID is provided.
|
||||||
|
Port string
|
||||||
|
|
||||||
|
// FixedIP [optional] specifies a fixed IPv4 address to be used on this network.
|
||||||
|
FixedIP string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Personality is an array of files that are injected into the server at launch.
|
||||||
|
type Personality []*File
|
||||||
|
|
||||||
|
// File is used within CreateOpts and RebuildOpts to inject a file into the server at launch.
|
||||||
|
// File implements the json.Marshaler interface, so when a Create or Rebuild operation is requested,
|
||||||
|
// json.Marshal will call File's MarshalJSON method.
|
||||||
|
type File struct {
|
||||||
|
// Path of the file
|
||||||
|
Path string
|
||||||
|
// Contents of the file. Maximum content size is 255 bytes.
|
||||||
|
Contents []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON marshals the escaped file, base64 encoding the contents.
|
||||||
|
func (f *File) MarshalJSON() ([]byte, error) {
|
||||||
|
file := struct {
|
||||||
|
Path string `json:"path"`
|
||||||
|
Contents string `json:"contents"`
|
||||||
|
}{
|
||||||
|
Path: f.Path,
|
||||||
|
Contents: base64.StdEncoding.EncodeToString(f.Contents),
|
||||||
|
}
|
||||||
|
return json.Marshal(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOpts specifies server creation parameters.
|
||||||
|
type CreateOpts struct {
|
||||||
|
// Name is the name to assign to the newly launched server.
|
||||||
|
Name string `json:"name" required:"true"`
|
||||||
|
|
||||||
|
// ImageRef [optional; required if ImageName is not provided] is the ID or full
|
||||||
|
// URL to the image that contains the server's OS and initial state.
|
||||||
|
// Also optional if using the boot-from-volume extension.
|
||||||
|
ImageRef string `json:"imageRef"`
|
||||||
|
|
||||||
|
// ImageName [optional; required if ImageRef is not provided] is the name of the
|
||||||
|
// image that contains the server's OS and initial state.
|
||||||
|
// Also optional if using the boot-from-volume extension.
|
||||||
|
ImageName string `json:"-"`
|
||||||
|
|
||||||
|
// FlavorRef [optional; required if FlavorName is not provided] is the ID or
|
||||||
|
// full URL to the flavor that describes the server's specs.
|
||||||
|
FlavorRef string `json:"flavorRef"`
|
||||||
|
|
||||||
|
// FlavorName [optional; required if FlavorRef is not provided] is the name of
|
||||||
|
// the flavor that describes the server's specs.
|
||||||
|
FlavorName string `json:"-"`
|
||||||
|
|
||||||
|
// SecurityGroups lists the names of the security groups to which this server should belong.
|
||||||
|
SecurityGroups []string `json:"-"`
|
||||||
|
|
||||||
|
// UserData contains configuration information or scripts to use upon launch.
|
||||||
|
// Create will base64-encode it for you.
|
||||||
|
UserData []byte `json:"-"`
|
||||||
|
|
||||||
|
// AvailabilityZone in which to launch the server.
|
||||||
|
AvailabilityZone string `json:"availability_zone,omitempty"`
|
||||||
|
|
||||||
|
// Networks dictates how this server will be attached to available networks.
|
||||||
|
// By default, the server will be attached to all isolated networks for the tenant.
|
||||||
|
Networks []Network `json:"-"`
|
||||||
|
|
||||||
|
// Metadata contains key-value pairs (up to 255 bytes each) to attach to the server.
|
||||||
|
Metadata map[string]string `json:"metadata,omitempty"`
|
||||||
|
|
||||||
|
// Personality includes files to inject into the server at launch.
|
||||||
|
// Create will base64-encode file contents for you.
|
||||||
|
Personality Personality `json:"-"`
|
||||||
|
|
||||||
|
// ConfigDrive enables metadata injection through a configuration drive.
|
||||||
|
ConfigDrive *bool `json:"config_drive,omitempty"`
|
||||||
|
|
||||||
|
// AdminPass sets the root user password. If not set, a randomly-generated
|
||||||
|
// password will be created and returned in the rponse.
|
||||||
|
AdminPass string `json:"adminPass,omitempty"`
|
||||||
|
|
||||||
|
// AccessIPv4 specifies an IPv4 address for the instance.
|
||||||
|
AccessIPv4 string `json:"accessIPv4,omitempty"`
|
||||||
|
|
||||||
|
// AccessIPv6 pecifies an IPv6 address for the instance.
|
||||||
|
AccessIPv6 string `json:"accessIPv6,omitempty"`
|
||||||
|
|
||||||
|
// ServiceClient will allow calls to be made to retrieve an image or
|
||||||
|
// flavor ID by name.
|
||||||
|
ServiceClient *gophercloud.ServiceClient `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToServerCreateMap assembles a request body based on the contents of a CreateOpts.
|
||||||
|
func (opts CreateOpts) ToServerCreateMap() (map[string]interface{}, error) {
|
||||||
|
sc := opts.ServiceClient
|
||||||
|
opts.ServiceClient = nil
|
||||||
|
b, err := gophercloud.BuildRequestBody(opts, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.UserData != nil {
|
||||||
|
encoded := base64.StdEncoding.EncodeToString(opts.UserData)
|
||||||
|
b["user_data"] = &encoded
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(opts.SecurityGroups) > 0 {
|
||||||
|
securityGroups := make([]map[string]interface{}, len(opts.SecurityGroups))
|
||||||
|
for i, groupName := range opts.SecurityGroups {
|
||||||
|
securityGroups[i] = map[string]interface{}{"name": groupName}
|
||||||
|
}
|
||||||
|
b["security_groups"] = securityGroups
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(opts.Networks) > 0 {
|
||||||
|
networks := make([]map[string]interface{}, len(opts.Networks))
|
||||||
|
for i, net := range opts.Networks {
|
||||||
|
networks[i] = make(map[string]interface{})
|
||||||
|
if net.UUID != "" {
|
||||||
|
networks[i]["uuid"] = net.UUID
|
||||||
|
}
|
||||||
|
if net.Port != "" {
|
||||||
|
networks[i]["port"] = net.Port
|
||||||
|
}
|
||||||
|
if net.FixedIP != "" {
|
||||||
|
networks[i]["fixed_ip"] = net.FixedIP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b["networks"] = networks
|
||||||
|
}
|
||||||
|
|
||||||
|
// If ImageRef isn't provided, check if ImageName was provided to ascertain
|
||||||
|
// the image ID.
|
||||||
|
if opts.ImageRef == "" {
|
||||||
|
if opts.ImageName != "" {
|
||||||
|
if sc == nil {
|
||||||
|
err := ErrNoClientProvidedForIDByName{}
|
||||||
|
err.Argument = "ServiceClient"
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
imageID, err := images.IDFromName(sc, opts.ImageName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b["imageRef"] = imageID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If FlavorRef isn't provided, use FlavorName to ascertain the flavor ID.
|
||||||
|
if opts.FlavorRef == "" {
|
||||||
|
if opts.FlavorName == "" {
|
||||||
|
err := ErrNeitherFlavorIDNorFlavorNameProvided{}
|
||||||
|
err.Argument = "FlavorRef/FlavorName"
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if sc == nil {
|
||||||
|
err := ErrNoClientProvidedForIDByName{}
|
||||||
|
err.Argument = "ServiceClient"
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
flavorID, err := flavors.IDFromName(sc, opts.FlavorName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b["flavorRef"] = flavorID
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]interface{}{"server": b}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create requests a server to be provisioned to the user in the current tenant.
|
||||||
|
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
|
||||||
|
reqBody, err := opts.ToServerCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = client.Post(listURL(client), reqBody, &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete requests that a server previously provisioned be removed from your account.
|
||||||
|
func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) {
|
||||||
|
_, r.Err = client.Delete(deleteURL(client, id), nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForceDelete forces the deletion of a server
|
||||||
|
func ForceDelete(client *gophercloud.ServiceClient, id string) (r ActionResult) {
|
||||||
|
_, r.Err = client.Post(actionURL(client, id), map[string]interface{}{"forceDelete": ""}, nil, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get requests details on a single server, by ID.
|
||||||
|
func Get(client *gophercloud.ServiceClient, id string) (r GetResult) {
|
||||||
|
_, r.Err = client.Get(getURL(client, id), &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200, 203},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateOptsBuilder allows extensions to add additional attributes to the Update request.
|
||||||
|
type UpdateOptsBuilder interface {
|
||||||
|
ToServerUpdateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateOpts specifies the base attributes that may be updated on an existing server.
|
||||||
|
type UpdateOpts struct {
|
||||||
|
// Name changes the displayed name of the server.
|
||||||
|
// The server host name will *not* change.
|
||||||
|
// Server names are not constrained to be unique, even within the same tenant.
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
|
||||||
|
// AccessIPv4 provides a new IPv4 address for the instance.
|
||||||
|
AccessIPv4 string `json:"accessIPv4,omitempty"`
|
||||||
|
|
||||||
|
// AccessIPv6 provides a new IPv6 address for the instance.
|
||||||
|
AccessIPv6 string `json:"accessIPv6,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToServerUpdateMap formats an UpdateOpts structure into a request body.
|
||||||
|
func (opts UpdateOpts) ToServerUpdateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "server")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update requests that various attributes of the indicated server be changed.
|
||||||
|
func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) {
|
||||||
|
b, err := opts.ToServerUpdateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = client.Put(updateURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangeAdminPassword alters the administrator or root password for a specified server.
|
||||||
|
func ChangeAdminPassword(client *gophercloud.ServiceClient, id, newPassword string) (r ActionResult) {
|
||||||
|
b := map[string]interface{}{
|
||||||
|
"changePassword": map[string]string{
|
||||||
|
"adminPass": newPassword,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, r.Err = client.Post(actionURL(client, id), b, nil, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// RebootMethod describes the mechanisms by which a server reboot can be requested.
|
||||||
|
type RebootMethod string
|
||||||
|
|
||||||
|
// These constants determine how a server should be rebooted.
|
||||||
|
// See the Reboot() function for further details.
|
||||||
|
const (
|
||||||
|
SoftReboot RebootMethod = "SOFT"
|
||||||
|
HardReboot RebootMethod = "HARD"
|
||||||
|
OSReboot = SoftReboot
|
||||||
|
PowerCycle = HardReboot
|
||||||
|
)
|
||||||
|
|
||||||
|
// RebootOptsBuilder is an interface that options must satisfy in order to be
|
||||||
|
// used when rebooting a server instance
|
||||||
|
type RebootOptsBuilder interface {
|
||||||
|
ToServerRebootMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RebootOpts satisfies the RebootOptsBuilder interface
|
||||||
|
type RebootOpts struct {
|
||||||
|
Type RebootMethod `json:"type" required:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToServerRebootMap allows RebootOpts to satisfiy the RebootOptsBuilder
|
||||||
|
// interface
|
||||||
|
func (opts *RebootOpts) ToServerRebootMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "reboot")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reboot requests that a given server reboot.
|
||||||
|
// Two methods exist for rebooting a server:
|
||||||
|
//
|
||||||
|
// HardReboot (aka PowerCycle) starts the server instance by physically cutting power to the machine, or if a VM,
|
||||||
|
// terminating it at the hypervisor level.
|
||||||
|
// It's done. Caput. Full stop.
|
||||||
|
// Then, after a brief while, power is rtored or the VM instance rtarted.
|
||||||
|
//
|
||||||
|
// SoftReboot (aka OSReboot) simply tells the OS to rtart under its own procedur.
|
||||||
|
// E.g., in Linux, asking it to enter runlevel 6, or executing "sudo shutdown -r now", or by asking Windows to rtart the machine.
|
||||||
|
func Reboot(client *gophercloud.ServiceClient, id string, opts RebootOptsBuilder) (r ActionResult) {
|
||||||
|
b, err := opts.ToServerRebootMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = client.Post(actionURL(client, id), b, nil, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// RebuildOptsBuilder is an interface that allows extensions to override the
|
||||||
|
// default behaviour of rebuild options
|
||||||
|
type RebuildOptsBuilder interface {
|
||||||
|
ToServerRebuildMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RebuildOpts represents the configuration options used in a server rebuild
|
||||||
|
// operation
|
||||||
|
type RebuildOpts struct {
|
||||||
|
// The server's admin password
|
||||||
|
AdminPass string `json:"adminPass" required:"true"`
|
||||||
|
// The ID of the image you want your server to be provisioned on
|
||||||
|
ImageID string `json:"imageRef"`
|
||||||
|
ImageName string `json:"-"`
|
||||||
|
//ImageName string `json:"-"`
|
||||||
|
// Name to set the server to
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
// AccessIPv4 [optional] provides a new IPv4 address for the instance.
|
||||||
|
AccessIPv4 string `json:"accessIPv4,omitempty"`
|
||||||
|
// AccessIPv6 [optional] provides a new IPv6 address for the instance.
|
||||||
|
AccessIPv6 string `json:"accessIPv6,omitempty"`
|
||||||
|
// Metadata [optional] contains key-value pairs (up to 255 bytes each) to attach to the server.
|
||||||
|
Metadata map[string]string `json:"metadata,omitempty"`
|
||||||
|
// Personality [optional] includes files to inject into the server at launch.
|
||||||
|
// Rebuild will base64-encode file contents for you.
|
||||||
|
Personality Personality `json:"personality,omitempty"`
|
||||||
|
ServiceClient *gophercloud.ServiceClient `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToServerRebuildMap formats a RebuildOpts struct into a map for use in JSON
|
||||||
|
func (opts RebuildOpts) ToServerRebuildMap() (map[string]interface{}, error) {
|
||||||
|
b, err := gophercloud.BuildRequestBody(opts, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If ImageRef isn't provided, check if ImageName was provided to ascertain
|
||||||
|
// the image ID.
|
||||||
|
if opts.ImageID == "" {
|
||||||
|
if opts.ImageName != "" {
|
||||||
|
if opts.ServiceClient == nil {
|
||||||
|
err := ErrNoClientProvidedForIDByName{}
|
||||||
|
err.Argument = "ServiceClient"
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
imageID, err := images.IDFromName(opts.ServiceClient, opts.ImageName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b["imageRef"] = imageID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]interface{}{"rebuild": b}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rebuild will reprovision the server according to the configuration options
|
||||||
|
// provided in the RebuildOpts struct.
|
||||||
|
func Rebuild(client *gophercloud.ServiceClient, id string, opts RebuildOptsBuilder) (r RebuildResult) {
|
||||||
|
b, err := opts.ToServerRebuildMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = client.Post(actionURL(client, id), b, &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResizeOptsBuilder is an interface that allows extensions to override the default structure of
|
||||||
|
// a Resize request.
|
||||||
|
type ResizeOptsBuilder interface {
|
||||||
|
ToServerResizeMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResizeOpts represents the configuration options used to control a Resize operation.
|
||||||
|
type ResizeOpts struct {
|
||||||
|
// FlavorRef is the ID of the flavor you wish your server to become.
|
||||||
|
FlavorRef string `json:"flavorRef" required:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToServerResizeMap formats a ResizeOpts as a map that can be used as a JSON request body for the
|
||||||
|
// Resize request.
|
||||||
|
func (opts ResizeOpts) ToServerResizeMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "resize")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resize instructs the provider to change the flavor of the server.
|
||||||
|
// Note that this implies rebuilding it.
|
||||||
|
// Unfortunately, one cannot pass rebuild parameters to the resize function.
|
||||||
|
// When the resize completes, the server will be in RESIZE_VERIFY state.
|
||||||
|
// While in this state, you can explore the use of the new server's configuration.
|
||||||
|
// If you like it, call ConfirmResize() to commit the resize permanently.
|
||||||
|
// Otherwise, call RevertResize() to restore the old configuration.
|
||||||
|
func Resize(client *gophercloud.ServiceClient, id string, opts ResizeOptsBuilder) (r ActionResult) {
|
||||||
|
b, err := opts.ToServerResizeMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = client.Post(actionURL(client, id), b, nil, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfirmResize confirms a previous resize operation on a server.
|
||||||
|
// See Resize() for more details.
|
||||||
|
func ConfirmResize(client *gophercloud.ServiceClient, id string) (r ActionResult) {
|
||||||
|
_, r.Err = client.Post(actionURL(client, id), map[string]interface{}{"confirmResize": nil}, nil, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{201, 202, 204},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// RevertResize cancels a previous resize operation on a server.
|
||||||
|
// See Resize() for more details.
|
||||||
|
func RevertResize(client *gophercloud.ServiceClient, id string) (r ActionResult) {
|
||||||
|
_, r.Err = client.Post(actionURL(client, id), map[string]interface{}{"revertResize": nil}, nil, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// RescueOptsBuilder is an interface that allows extensions to override the
|
||||||
|
// default structure of a Rescue request.
|
||||||
|
type RescueOptsBuilder interface {
|
||||||
|
ToServerRescueMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RescueOpts represents the configuration options used to control a Rescue
|
||||||
|
// option.
|
||||||
|
type RescueOpts struct {
|
||||||
|
// AdminPass is the desired administrative password for the instance in
|
||||||
|
// RESCUE mode. If it's left blank, the server will generate a password.
|
||||||
|
AdminPass string `json:"adminPass,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToServerRescueMap formats a RescueOpts as a map that can be used as a JSON
|
||||||
|
// request body for the Rescue request.
|
||||||
|
func (opts RescueOpts) ToServerRescueMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "rescue")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rescue instructs the provider to place the server into RESCUE mode.
|
||||||
|
func Rescue(client *gophercloud.ServiceClient, id string, opts RescueOptsBuilder) (r RescueResult) {
|
||||||
|
b, err := opts.ToServerRescueMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = client.Post(actionURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetMetadataOptsBuilder allows extensions to add additional parameters to the
|
||||||
|
// Reset request.
|
||||||
|
type ResetMetadataOptsBuilder interface {
|
||||||
|
ToMetadataResetMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MetadataOpts is a map that contains key-value pairs.
|
||||||
|
type MetadataOpts map[string]string
|
||||||
|
|
||||||
|
// ToMetadataResetMap assembles a body for a Reset request based on the contents of a MetadataOpts.
|
||||||
|
func (opts MetadataOpts) ToMetadataResetMap() (map[string]interface{}, error) {
|
||||||
|
return map[string]interface{}{"metadata": opts}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToMetadataUpdateMap assembles a body for an Update request based on the contents of a MetadataOpts.
|
||||||
|
func (opts MetadataOpts) ToMetadataUpdateMap() (map[string]interface{}, error) {
|
||||||
|
return map[string]interface{}{"metadata": opts}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetMetadata will create multiple new key-value pairs for the given server ID.
|
||||||
|
// Note: Using this operation will erase any already-existing metadata and create
|
||||||
|
// the new metadata provided. To keep any already-existing metadata, use the
|
||||||
|
// UpdateMetadatas or UpdateMetadata function.
|
||||||
|
func ResetMetadata(client *gophercloud.ServiceClient, id string, opts ResetMetadataOptsBuilder) (r ResetMetadataResult) {
|
||||||
|
b, err := opts.ToMetadataResetMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = client.Put(metadataURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metadata requests all the metadata for the given server ID.
|
||||||
|
func Metadata(client *gophercloud.ServiceClient, id string) (r GetMetadataResult) {
|
||||||
|
_, r.Err = client.Get(metadataURL(client, id), &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateMetadataOptsBuilder allows extensions to add additional parameters to the
|
||||||
|
// Create request.
|
||||||
|
type UpdateMetadataOptsBuilder interface {
|
||||||
|
ToMetadataUpdateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateMetadata updates (or creates) all the metadata specified by opts for the given server ID.
|
||||||
|
// This operation does not affect already-existing metadata that is not specified
|
||||||
|
// by opts.
|
||||||
|
func UpdateMetadata(client *gophercloud.ServiceClient, id string, opts UpdateMetadataOptsBuilder) (r UpdateMetadataResult) {
|
||||||
|
b, err := opts.ToMetadataUpdateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = client.Post(metadataURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// MetadatumOptsBuilder allows extensions to add additional parameters to the
|
||||||
|
// Create request.
|
||||||
|
type MetadatumOptsBuilder interface {
|
||||||
|
ToMetadatumCreateMap() (map[string]interface{}, string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MetadatumOpts is a map of length one that contains a key-value pair.
|
||||||
|
type MetadatumOpts map[string]string
|
||||||
|
|
||||||
|
// ToMetadatumCreateMap assembles a body for a Create request based on the contents of a MetadataumOpts.
|
||||||
|
func (opts MetadatumOpts) ToMetadatumCreateMap() (map[string]interface{}, string, error) {
|
||||||
|
if len(opts) != 1 {
|
||||||
|
err := gophercloud.ErrInvalidInput{}
|
||||||
|
err.Argument = "servers.MetadatumOpts"
|
||||||
|
err.Info = "Must have 1 and only 1 key-value pair"
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
metadatum := map[string]interface{}{"meta": opts}
|
||||||
|
var key string
|
||||||
|
for k := range metadatum["meta"].(MetadatumOpts) {
|
||||||
|
key = k
|
||||||
|
}
|
||||||
|
return metadatum, key, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateMetadatum will create or update the key-value pair with the given key for the given server ID.
|
||||||
|
func CreateMetadatum(client *gophercloud.ServiceClient, id string, opts MetadatumOptsBuilder) (r CreateMetadatumResult) {
|
||||||
|
b, key, err := opts.ToMetadatumCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = client.Put(metadatumURL(client, id, key), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metadatum requests the key-value pair with the given key for the given server ID.
|
||||||
|
func Metadatum(client *gophercloud.ServiceClient, id, key string) (r GetMetadatumResult) {
|
||||||
|
_, r.Err = client.Get(metadatumURL(client, id, key), &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteMetadatum will delete the key-value pair with the given key for the given server ID.
|
||||||
|
func DeleteMetadatum(client *gophercloud.ServiceClient, id, key string) (r DeleteMetadatumResult) {
|
||||||
|
_, r.Err = client.Delete(metadatumURL(client, id, key), nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAddresses makes a request against the API to list the servers IP addresses.
|
||||||
|
func ListAddresses(client *gophercloud.ServiceClient, id string) pagination.Pager {
|
||||||
|
return pagination.NewPager(client, listAddressesURL(client, id), func(r pagination.PageResult) pagination.Page {
|
||||||
|
return AddressPage{pagination.SinglePageBase(r)}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAddressesByNetwork makes a request against the API to list the servers IP addresses
|
||||||
|
// for the given network.
|
||||||
|
func ListAddressesByNetwork(client *gophercloud.ServiceClient, id, network string) pagination.Pager {
|
||||||
|
return pagination.NewPager(client, listAddressesByNetworkURL(client, id, network), func(r pagination.PageResult) pagination.Page {
|
||||||
|
return NetworkAddressPage{pagination.SinglePageBase(r)}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateImageOptsBuilder is the interface types must satisfy in order to be
|
||||||
|
// used as CreateImage options
|
||||||
|
type CreateImageOptsBuilder interface {
|
||||||
|
ToServerCreateImageMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateImageOpts satisfies the CreateImageOptsBuilder
|
||||||
|
type CreateImageOpts struct {
|
||||||
|
// Name of the image/snapshot
|
||||||
|
Name string `json:"name" required:"true"`
|
||||||
|
// Metadata contains key-value pairs (up to 255 bytes each) to attach to the created image.
|
||||||
|
Metadata map[string]string `json:"metadata,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToServerCreateImageMap formats a CreateImageOpts structure into a request body.
|
||||||
|
func (opts CreateImageOpts) ToServerCreateImageMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "createImage")
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateImage makes a request against the nova API to schedule an image to be created of the server
|
||||||
|
func CreateImage(client *gophercloud.ServiceClient, id string, opts CreateImageOptsBuilder) (r CreateImageResult) {
|
||||||
|
b, err := opts.ToServerCreateImageMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, err := client.Post(actionURL(client, id), b, nil, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{202},
|
||||||
|
})
|
||||||
|
r.Err = err
|
||||||
|
r.Header = resp.Header
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDFromName is a convienience function that returns a server's ID given its name.
|
||||||
|
func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
|
||||||
|
count := 0
|
||||||
|
id := ""
|
||||||
|
allPages, err := List(client, nil).AllPages()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
all, err := ExtractServers(allPages)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range all {
|
||||||
|
if f.Name == name {
|
||||||
|
count++
|
||||||
|
id = f.ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch count {
|
||||||
|
case 0:
|
||||||
|
return "", gophercloud.ErrResourceNotFound{Name: name, ResourceType: "server"}
|
||||||
|
case 1:
|
||||||
|
return id, nil
|
||||||
|
default:
|
||||||
|
return "", gophercloud.ErrMultipleResourcesFound{Name: name, Count: count, ResourceType: "server"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPassword makes a request against the nova API to get the encrypted administrative password.
|
||||||
|
func GetPassword(client *gophercloud.ServiceClient, serverId string) (r GetPasswordResult) {
|
||||||
|
_, r.Err = client.Get(passwordURL(client, serverId), &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
344
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/results.go
generated
vendored
Normal file
344
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/results.go
generated
vendored
Normal file
|
@ -0,0 +1,344 @@
|
||||||
|
package servers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rsa"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
type serverResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract interprets any serverResult as a Server, if possible.
|
||||||
|
func (r serverResult) Extract() (*Server, error) {
|
||||||
|
var s struct {
|
||||||
|
Server *Server `json:"server"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return s.Server, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateResult temporarily contains the response from a Create call.
|
||||||
|
type CreateResult struct {
|
||||||
|
serverResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResult temporarily contains the response from a Get call.
|
||||||
|
type GetResult struct {
|
||||||
|
serverResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateResult temporarily contains the response from an Update call.
|
||||||
|
type UpdateResult struct {
|
||||||
|
serverResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteResult temporarily contains the response from a Delete call.
|
||||||
|
type DeleteResult struct {
|
||||||
|
gophercloud.ErrResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// RebuildResult temporarily contains the response from a Rebuild call.
|
||||||
|
type RebuildResult struct {
|
||||||
|
serverResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActionResult represents the result of server action operations, like reboot
|
||||||
|
type ActionResult struct {
|
||||||
|
gophercloud.ErrResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// RescueResult represents the result of a server rescue operation
|
||||||
|
type RescueResult struct {
|
||||||
|
ActionResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateImageResult represents the result of an image creation operation
|
||||||
|
type CreateImageResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPasswordResult represent the result of a get os-server-password operation.
|
||||||
|
type GetPasswordResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractPassword gets the encrypted password.
|
||||||
|
// If privateKey != nil the password is decrypted with the private key.
|
||||||
|
// If privateKey == nil the encrypted password is returned and can be decrypted with:
|
||||||
|
// echo '<pwd>' | base64 -D | openssl rsautl -decrypt -inkey <private_key>
|
||||||
|
func (r GetPasswordResult) ExtractPassword(privateKey *rsa.PrivateKey) (string, error) {
|
||||||
|
var s struct {
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
if err == nil && privateKey != nil && s.Password != "" {
|
||||||
|
return decryptPassword(s.Password, privateKey)
|
||||||
|
}
|
||||||
|
return s.Password, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func decryptPassword(encryptedPassword string, privateKey *rsa.PrivateKey) (string, error) {
|
||||||
|
b64EncryptedPassword := make([]byte, base64.StdEncoding.DecodedLen(len(encryptedPassword)))
|
||||||
|
|
||||||
|
n, err := base64.StdEncoding.Decode(b64EncryptedPassword, []byte(encryptedPassword))
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("Failed to base64 decode encrypted password: %s", err)
|
||||||
|
}
|
||||||
|
password, err := rsa.DecryptPKCS1v15(nil, privateKey, b64EncryptedPassword[0:n])
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("Failed to decrypt password: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(password), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractImageID gets the ID of the newly created server image from the header
|
||||||
|
func (res CreateImageResult) ExtractImageID() (string, error) {
|
||||||
|
if res.Err != nil {
|
||||||
|
return "", res.Err
|
||||||
|
}
|
||||||
|
// Get the image id from the header
|
||||||
|
u, err := url.ParseRequestURI(res.Header.Get("Location"))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
imageID := path.Base(u.Path)
|
||||||
|
if imageID == "." || imageID == "/" {
|
||||||
|
return "", fmt.Errorf("Failed to parse the ID of newly created image: %s", u)
|
||||||
|
}
|
||||||
|
return imageID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract interprets any RescueResult as an AdminPass, if possible.
|
||||||
|
func (r RescueResult) Extract() (string, error) {
|
||||||
|
var s struct {
|
||||||
|
AdminPass string `json:"adminPass"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return s.AdminPass, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server exposes only the standard OpenStack fields corresponding to a given server on the user's account.
|
||||||
|
type Server struct {
|
||||||
|
// ID uniquely identifies this server amongst all other servers, including those not accessible to the current tenant.
|
||||||
|
ID string `json:"id"`
|
||||||
|
// TenantID identifies the tenant owning this server resource.
|
||||||
|
TenantID string `json:"tenant_id"`
|
||||||
|
// UserID uniquely identifies the user account owning the tenant.
|
||||||
|
UserID string `json:"user_id"`
|
||||||
|
// Name contains the human-readable name for the server.
|
||||||
|
Name string `json:"name"`
|
||||||
|
// Updated and Created contain ISO-8601 timestamps of when the state of the server last changed, and when it was created.
|
||||||
|
Updated string
|
||||||
|
Created string
|
||||||
|
HostID string
|
||||||
|
// Status contains the current operational status of the server, such as IN_PROGRESS or ACTIVE.
|
||||||
|
Status string
|
||||||
|
// Progress ranges from 0..100.
|
||||||
|
// A request made against the server completes only once Progress reaches 100.
|
||||||
|
Progress int
|
||||||
|
// AccessIPv4 and AccessIPv6 contain the IP addresses of the server, suitable for remote access for administration.
|
||||||
|
AccessIPv4, AccessIPv6 string
|
||||||
|
// Image refers to a JSON object, which itself indicates the OS image used to deploy the server.
|
||||||
|
Image map[string]interface{}
|
||||||
|
// Flavor refers to a JSON object, which itself indicates the hardware configuration of the deployed server.
|
||||||
|
Flavor map[string]interface{}
|
||||||
|
// Addresses includes a list of all IP addresses assigned to the server, keyed by pool.
|
||||||
|
Addresses map[string]interface{}
|
||||||
|
// Metadata includes a list of all user-specified key-value pairs attached to the server.
|
||||||
|
Metadata map[string]string
|
||||||
|
// Links includes HTTP references to the itself, useful for passing along to other APIs that might want a server reference.
|
||||||
|
Links []interface{}
|
||||||
|
// KeyName indicates which public key was injected into the server on launch.
|
||||||
|
KeyName string `json:"key_name"`
|
||||||
|
// AdminPass will generally be empty (""). However, it will contain the administrative password chosen when provisioning a new server without a set AdminPass setting in the first place.
|
||||||
|
// Note that this is the ONLY time this field will be valid.
|
||||||
|
AdminPass string `json:"adminPass"`
|
||||||
|
// SecurityGroups includes the security groups that this instance has applied to it
|
||||||
|
SecurityGroups []map[string]interface{} `json:"security_groups"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) UnmarshalJSON(b []byte) error {
|
||||||
|
type tmp Server
|
||||||
|
var server *struct {
|
||||||
|
tmp
|
||||||
|
Image interface{}
|
||||||
|
}
|
||||||
|
err := json.Unmarshal(b, &server)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*s = Server(server.tmp)
|
||||||
|
|
||||||
|
switch t := server.Image.(type) {
|
||||||
|
case map[string]interface{}:
|
||||||
|
s.Image = t
|
||||||
|
case string:
|
||||||
|
switch t {
|
||||||
|
case "":
|
||||||
|
s.Image = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerPage abstracts the raw results of making a List() request against the API.
|
||||||
|
// As OpenStack extensions may freely alter the response bodies of structures returned to the client, you may only safely access the
|
||||||
|
// data provided through the ExtractServers call.
|
||||||
|
type ServerPage struct {
|
||||||
|
pagination.LinkedPageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty returns true if a page contains no Server results.
|
||||||
|
func (page ServerPage) IsEmpty() (bool, error) {
|
||||||
|
servers, err := ExtractServers(page)
|
||||||
|
return len(servers) == 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NextPageURL uses the response's embedded link reference to navigate to the next page of results.
|
||||||
|
func (page ServerPage) NextPageURL() (string, error) {
|
||||||
|
var s struct {
|
||||||
|
Links []gophercloud.Link `json:"servers_links"`
|
||||||
|
}
|
||||||
|
err := page.ExtractInto(&s)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return gophercloud.ExtractNextURL(s.Links)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractServers interprets the results of a single page from a List() call, producing a slice of Server entities.
|
||||||
|
func ExtractServers(r pagination.Page) ([]Server, error) {
|
||||||
|
var s struct {
|
||||||
|
Servers []Server `json:"servers"`
|
||||||
|
}
|
||||||
|
err := (r.(ServerPage)).ExtractInto(&s)
|
||||||
|
return s.Servers, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// MetadataResult contains the result of a call for (potentially) multiple key-value pairs.
|
||||||
|
type MetadataResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMetadataResult temporarily contains the response from a metadata Get call.
|
||||||
|
type GetMetadataResult struct {
|
||||||
|
MetadataResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetMetadataResult temporarily contains the response from a metadata Reset call.
|
||||||
|
type ResetMetadataResult struct {
|
||||||
|
MetadataResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateMetadataResult temporarily contains the response from a metadata Update call.
|
||||||
|
type UpdateMetadataResult struct {
|
||||||
|
MetadataResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// MetadatumResult contains the result of a call for individual a single key-value pair.
|
||||||
|
type MetadatumResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMetadatumResult temporarily contains the response from a metadatum Get call.
|
||||||
|
type GetMetadatumResult struct {
|
||||||
|
MetadatumResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateMetadatumResult temporarily contains the response from a metadatum Create call.
|
||||||
|
type CreateMetadatumResult struct {
|
||||||
|
MetadatumResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteMetadatumResult temporarily contains the response from a metadatum Delete call.
|
||||||
|
type DeleteMetadatumResult struct {
|
||||||
|
gophercloud.ErrResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract interprets any MetadataResult as a Metadata, if possible.
|
||||||
|
func (r MetadataResult) Extract() (map[string]string, error) {
|
||||||
|
var s struct {
|
||||||
|
Metadata map[string]string `json:"metadata"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return s.Metadata, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract interprets any MetadatumResult as a Metadatum, if possible.
|
||||||
|
func (r MetadatumResult) Extract() (map[string]string, error) {
|
||||||
|
var s struct {
|
||||||
|
Metadatum map[string]string `json:"meta"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return s.Metadatum, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Address represents an IP address.
|
||||||
|
type Address struct {
|
||||||
|
Version int `json:"version"`
|
||||||
|
Address string `json:"addr"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddressPage abstracts the raw results of making a ListAddresses() request against the API.
|
||||||
|
// As OpenStack extensions may freely alter the response bodies of structures returned
|
||||||
|
// to the client, you may only safely access the data provided through the ExtractAddresses call.
|
||||||
|
type AddressPage struct {
|
||||||
|
pagination.SinglePageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty returns true if an AddressPage contains no networks.
|
||||||
|
func (r AddressPage) IsEmpty() (bool, error) {
|
||||||
|
addresses, err := ExtractAddresses(r)
|
||||||
|
return len(addresses) == 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractAddresses interprets the results of a single page from a ListAddresses() call,
|
||||||
|
// producing a map of addresses.
|
||||||
|
func ExtractAddresses(r pagination.Page) (map[string][]Address, error) {
|
||||||
|
var s struct {
|
||||||
|
Addresses map[string][]Address `json:"addresses"`
|
||||||
|
}
|
||||||
|
err := (r.(AddressPage)).ExtractInto(&s)
|
||||||
|
return s.Addresses, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetworkAddressPage abstracts the raw results of making a ListAddressesByNetwork() request against the API.
|
||||||
|
// As OpenStack extensions may freely alter the response bodies of structures returned
|
||||||
|
// to the client, you may only safely access the data provided through the ExtractAddresses call.
|
||||||
|
type NetworkAddressPage struct {
|
||||||
|
pagination.SinglePageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty returns true if a NetworkAddressPage contains no addresses.
|
||||||
|
func (r NetworkAddressPage) IsEmpty() (bool, error) {
|
||||||
|
addresses, err := ExtractNetworkAddresses(r)
|
||||||
|
return len(addresses) == 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractNetworkAddresses interprets the results of a single page from a ListAddressesByNetwork() call,
|
||||||
|
// producing a slice of addresses.
|
||||||
|
func ExtractNetworkAddresses(r pagination.Page) ([]Address, error) {
|
||||||
|
var s map[string][]Address
|
||||||
|
err := (r.(NetworkAddressPage)).ExtractInto(&s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var key string
|
||||||
|
for k := range s {
|
||||||
|
key = k
|
||||||
|
}
|
||||||
|
|
||||||
|
return s[key], err
|
||||||
|
}
|
51
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/urls.go
generated
vendored
Normal file
51
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/urls.go
generated
vendored
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
package servers
|
||||||
|
|
||||||
|
import "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
func createURL(client *gophercloud.ServiceClient) string {
|
||||||
|
return client.ServiceURL("servers")
|
||||||
|
}
|
||||||
|
|
||||||
|
func listURL(client *gophercloud.ServiceClient) string {
|
||||||
|
return createURL(client)
|
||||||
|
}
|
||||||
|
|
||||||
|
func listDetailURL(client *gophercloud.ServiceClient) string {
|
||||||
|
return client.ServiceURL("servers", "detail")
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteURL(client *gophercloud.ServiceClient, id string) string {
|
||||||
|
return client.ServiceURL("servers", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getURL(client *gophercloud.ServiceClient, id string) string {
|
||||||
|
return deleteURL(client, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateURL(client *gophercloud.ServiceClient, id string) string {
|
||||||
|
return deleteURL(client, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func actionURL(client *gophercloud.ServiceClient, id string) string {
|
||||||
|
return client.ServiceURL("servers", id, "action")
|
||||||
|
}
|
||||||
|
|
||||||
|
func metadatumURL(client *gophercloud.ServiceClient, id, key string) string {
|
||||||
|
return client.ServiceURL("servers", id, "metadata", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func metadataURL(client *gophercloud.ServiceClient, id string) string {
|
||||||
|
return client.ServiceURL("servers", id, "metadata")
|
||||||
|
}
|
||||||
|
|
||||||
|
func listAddressesURL(client *gophercloud.ServiceClient, id string) string {
|
||||||
|
return client.ServiceURL("servers", id, "ips")
|
||||||
|
}
|
||||||
|
|
||||||
|
func listAddressesByNetworkURL(client *gophercloud.ServiceClient, id, network string) string {
|
||||||
|
return client.ServiceURL("servers", id, "ips", network)
|
||||||
|
}
|
||||||
|
|
||||||
|
func passwordURL(client *gophercloud.ServiceClient, id string) string {
|
||||||
|
return client.ServiceURL("servers", id, "os-server-password")
|
||||||
|
}
|
20
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/util.go
generated
vendored
Normal file
20
vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers/util.go
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package servers
|
||||||
|
|
||||||
|
import "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
// WaitForStatus will continually poll a server until it successfully transitions to a specified
|
||||||
|
// status. It will do this for at most the number of seconds specified.
|
||||||
|
func WaitForStatus(c *gophercloud.ServiceClient, id, status string, secs int) error {
|
||||||
|
return gophercloud.WaitFor(secs, func() (bool, error) {
|
||||||
|
current, err := Get(c, id).Extract()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if current.Status == status {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
})
|
||||||
|
}
|
99
vendor/github.com/gophercloud/gophercloud/openstack/endpoint_location.go
generated
vendored
Normal file
99
vendor/github.com/gophercloud/gophercloud/openstack/endpoint_location.go
generated
vendored
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
tokens2 "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens"
|
||||||
|
tokens3 "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens"
|
||||||
|
)
|
||||||
|
|
||||||
|
// V2EndpointURL discovers the endpoint URL for a specific service from a ServiceCatalog acquired
|
||||||
|
// during the v2 identity service. The specified EndpointOpts are used to identify a unique,
|
||||||
|
// unambiguous endpoint to return. It's an error both when multiple endpoints match the provided
|
||||||
|
// criteria and when none do. The minimum that can be specified is a Type, but you will also often
|
||||||
|
// need to specify a Name and/or a Region depending on what's available on your OpenStack
|
||||||
|
// deployment.
|
||||||
|
func V2EndpointURL(catalog *tokens2.ServiceCatalog, opts gophercloud.EndpointOpts) (string, error) {
|
||||||
|
// Extract Endpoints from the catalog entries that match the requested Type, Name if provided, and Region if provided.
|
||||||
|
var endpoints = make([]tokens2.Endpoint, 0, 1)
|
||||||
|
for _, entry := range catalog.Entries {
|
||||||
|
if (entry.Type == opts.Type) && (opts.Name == "" || entry.Name == opts.Name) {
|
||||||
|
for _, endpoint := range entry.Endpoints {
|
||||||
|
if opts.Region == "" || endpoint.Region == opts.Region {
|
||||||
|
endpoints = append(endpoints, endpoint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report an error if the options were ambiguous.
|
||||||
|
if len(endpoints) > 1 {
|
||||||
|
err := &ErrMultipleMatchingEndpointsV2{}
|
||||||
|
err.Endpoints = endpoints
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the appropriate URL from the matching Endpoint.
|
||||||
|
for _, endpoint := range endpoints {
|
||||||
|
switch opts.Availability {
|
||||||
|
case gophercloud.AvailabilityPublic:
|
||||||
|
return gophercloud.NormalizeURL(endpoint.PublicURL), nil
|
||||||
|
case gophercloud.AvailabilityInternal:
|
||||||
|
return gophercloud.NormalizeURL(endpoint.InternalURL), nil
|
||||||
|
case gophercloud.AvailabilityAdmin:
|
||||||
|
return gophercloud.NormalizeURL(endpoint.AdminURL), nil
|
||||||
|
default:
|
||||||
|
err := &ErrInvalidAvailabilityProvided{}
|
||||||
|
err.Argument = "Availability"
|
||||||
|
err.Value = opts.Availability
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report an error if there were no matching endpoints.
|
||||||
|
err := &gophercloud.ErrEndpointNotFound{}
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// V3EndpointURL discovers the endpoint URL for a specific service from a Catalog acquired
|
||||||
|
// during the v3 identity service. The specified EndpointOpts are used to identify a unique,
|
||||||
|
// unambiguous endpoint to return. It's an error both when multiple endpoints match the provided
|
||||||
|
// criteria and when none do. The minimum that can be specified is a Type, but you will also often
|
||||||
|
// need to specify a Name and/or a Region depending on what's available on your OpenStack
|
||||||
|
// deployment.
|
||||||
|
func V3EndpointURL(catalog *tokens3.ServiceCatalog, opts gophercloud.EndpointOpts) (string, error) {
|
||||||
|
// Extract Endpoints from the catalog entries that match the requested Type, Interface,
|
||||||
|
// Name if provided, and Region if provided.
|
||||||
|
var endpoints = make([]tokens3.Endpoint, 0, 1)
|
||||||
|
for _, entry := range catalog.Entries {
|
||||||
|
if (entry.Type == opts.Type) && (opts.Name == "" || entry.Name == opts.Name) {
|
||||||
|
for _, endpoint := range entry.Endpoints {
|
||||||
|
if opts.Availability != gophercloud.AvailabilityAdmin &&
|
||||||
|
opts.Availability != gophercloud.AvailabilityPublic &&
|
||||||
|
opts.Availability != gophercloud.AvailabilityInternal {
|
||||||
|
err := &ErrInvalidAvailabilityProvided{}
|
||||||
|
err.Argument = "Availability"
|
||||||
|
err.Value = opts.Availability
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if (opts.Availability == gophercloud.Availability(endpoint.Interface)) &&
|
||||||
|
(opts.Region == "" || endpoint.Region == opts.Region) {
|
||||||
|
endpoints = append(endpoints, endpoint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report an error if the options were ambiguous.
|
||||||
|
if len(endpoints) > 1 {
|
||||||
|
return "", ErrMultipleMatchingEndpointsV3{Endpoints: endpoints}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the URL from the matching Endpoint.
|
||||||
|
for _, endpoint := range endpoints {
|
||||||
|
return gophercloud.NormalizeURL(endpoint.URL), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report an error if there were no matching endpoints.
|
||||||
|
err := &gophercloud.ErrEndpointNotFound{}
|
||||||
|
return "", err
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
tokens2 "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens"
|
||||||
|
tokens3 "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrEndpointNotFound is the error when no suitable endpoint can be found
|
||||||
|
// in the user's catalog
|
||||||
|
type ErrEndpointNotFound struct{ gophercloud.BaseError }
|
||||||
|
|
||||||
|
func (e ErrEndpointNotFound) Error() string {
|
||||||
|
return "No suitable endpoint could be found in the service catalog."
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrInvalidAvailabilityProvided is the error when an invalid endpoint
|
||||||
|
// availability is provided
|
||||||
|
type ErrInvalidAvailabilityProvided struct{ gophercloud.ErrInvalidInput }
|
||||||
|
|
||||||
|
func (e ErrInvalidAvailabilityProvided) Error() string {
|
||||||
|
return fmt.Sprintf("Unexpected availability in endpoint query: %s", e.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrMultipleMatchingEndpointsV2 is the error when more than one endpoint
|
||||||
|
// for the given options is found in the v2 catalog
|
||||||
|
type ErrMultipleMatchingEndpointsV2 struct {
|
||||||
|
gophercloud.BaseError
|
||||||
|
Endpoints []tokens2.Endpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrMultipleMatchingEndpointsV2) Error() string {
|
||||||
|
return fmt.Sprintf("Discovered %d matching endpoints: %#v", len(e.Endpoints), e.Endpoints)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrMultipleMatchingEndpointsV3 is the error when more than one endpoint
|
||||||
|
// for the given options is found in the v3 catalog
|
||||||
|
type ErrMultipleMatchingEndpointsV3 struct {
|
||||||
|
gophercloud.BaseError
|
||||||
|
Endpoints []tokens3.Endpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrMultipleMatchingEndpointsV3) Error() string {
|
||||||
|
return fmt.Sprintf("Discovered %d matching endpoints: %#v", len(e.Endpoints), e.Endpoints)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrNoAuthURL is the error when the OS_AUTH_URL environment variable is not
|
||||||
|
// found
|
||||||
|
type ErrNoAuthURL struct{ gophercloud.ErrInvalidInput }
|
||||||
|
|
||||||
|
func (e ErrNoAuthURL) Error() string {
|
||||||
|
return "Environment variable OS_AUTH_URL needs to be set."
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrNoUsername is the error when the OS_USERNAME environment variable is not
|
||||||
|
// found
|
||||||
|
type ErrNoUsername struct{ gophercloud.ErrInvalidInput }
|
||||||
|
|
||||||
|
func (e ErrNoUsername) Error() string {
|
||||||
|
return "Environment variable OS_USERNAME needs to be set."
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrNoPassword is the error when the OS_PASSWORD environment variable is not
|
||||||
|
// found
|
||||||
|
type ErrNoPassword struct{ gophercloud.ErrInvalidInput }
|
||||||
|
|
||||||
|
func (e ErrNoPassword) Error() string {
|
||||||
|
return "Environment variable OS_PASSWORD needs to be set."
|
||||||
|
}
|
7
vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tenants/doc.go
generated
vendored
Normal file
7
vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tenants/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
// Package tenants provides information and interaction with the
|
||||||
|
// tenants API resource for the OpenStack Identity service.
|
||||||
|
//
|
||||||
|
// See http://developer.openstack.org/api-ref-identity-v2.html#identity-auth-v2
|
||||||
|
// and http://developer.openstack.org/api-ref-identity-v2.html#admin-tenants
|
||||||
|
// for more information.
|
||||||
|
package tenants
|
29
vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tenants/requests.go
generated
vendored
Normal file
29
vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tenants/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
package tenants
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ListOpts filters the Tenants that are returned by the List call.
|
||||||
|
type ListOpts struct {
|
||||||
|
// Marker is the ID of the last Tenant on the previous page.
|
||||||
|
Marker string `q:"marker"`
|
||||||
|
// Limit specifies the page size.
|
||||||
|
Limit int `q:"limit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// List enumerates the Tenants to which the current token has access.
|
||||||
|
func List(client *gophercloud.ServiceClient, opts *ListOpts) pagination.Pager {
|
||||||
|
url := listURL(client)
|
||||||
|
if opts != nil {
|
||||||
|
q, err := gophercloud.BuildQueryString(opts)
|
||||||
|
if err != nil {
|
||||||
|
return pagination.Pager{Err: err}
|
||||||
|
}
|
||||||
|
url += q.String()
|
||||||
|
}
|
||||||
|
return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
|
||||||
|
return TenantPage{pagination.LinkedPageBase{PageResult: r}}
|
||||||
|
})
|
||||||
|
}
|
53
vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tenants/results.go
generated
vendored
Normal file
53
vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tenants/results.go
generated
vendored
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
package tenants
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Tenant is a grouping of users in the identity service.
|
||||||
|
type Tenant struct {
|
||||||
|
// ID is a unique identifier for this tenant.
|
||||||
|
ID string `json:"id"`
|
||||||
|
|
||||||
|
// Name is a friendlier user-facing name for this tenant.
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// Description is a human-readable explanation of this Tenant's purpose.
|
||||||
|
Description string `json:"description"`
|
||||||
|
|
||||||
|
// Enabled indicates whether or not a tenant is active.
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TenantPage is a single page of Tenant results.
|
||||||
|
type TenantPage struct {
|
||||||
|
pagination.LinkedPageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty determines whether or not a page of Tenants contains any results.
|
||||||
|
func (r TenantPage) IsEmpty() (bool, error) {
|
||||||
|
tenants, err := ExtractTenants(r)
|
||||||
|
return len(tenants) == 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NextPageURL extracts the "next" link from the tenants_links section of the result.
|
||||||
|
func (r TenantPage) NextPageURL() (string, error) {
|
||||||
|
var s struct {
|
||||||
|
Links []gophercloud.Link `json:"tenants_links"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return gophercloud.ExtractNextURL(s.Links)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractTenants returns a slice of Tenants contained in a single page of results.
|
||||||
|
func ExtractTenants(r pagination.Page) ([]Tenant, error) {
|
||||||
|
var s struct {
|
||||||
|
Tenants []Tenant `json:"tenants"`
|
||||||
|
}
|
||||||
|
err := (r.(TenantPage)).ExtractInto(&s)
|
||||||
|
return s.Tenants, err
|
||||||
|
}
|
7
vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tenants/urls.go
generated
vendored
Normal file
7
vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tenants/urls.go
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package tenants
|
||||||
|
|
||||||
|
import "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
func listURL(client *gophercloud.ServiceClient) string {
|
||||||
|
return client.ServiceURL("tenants")
|
||||||
|
}
|
5
vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tokens/doc.go
generated
vendored
Normal file
5
vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tokens/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
// Package tokens provides information and interaction with the token API
|
||||||
|
// resource for the OpenStack Identity service.
|
||||||
|
// For more information, see:
|
||||||
|
// http://developer.openstack.org/api-ref-identity-v2.html#identity-auth-v2
|
||||||
|
package tokens
|
99
vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tokens/requests.go
generated
vendored
Normal file
99
vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tokens/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
package tokens
|
||||||
|
|
||||||
|
import "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
type PasswordCredentialsV2 struct {
|
||||||
|
Username string `json:"username" required:"true"`
|
||||||
|
Password string `json:"password" required:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TokenCredentialsV2 struct {
|
||||||
|
ID string `json:"id,omitempty" required:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthOptionsV2 wraps a gophercloud AuthOptions in order to adhere to the AuthOptionsBuilder
|
||||||
|
// interface.
|
||||||
|
type AuthOptionsV2 struct {
|
||||||
|
PasswordCredentials *PasswordCredentialsV2 `json:"passwordCredentials,omitempty" xor:"TokenCredentials"`
|
||||||
|
|
||||||
|
// The TenantID and TenantName fields are optional for the Identity V2 API.
|
||||||
|
// Some providers allow you to specify a TenantName instead of the TenantId.
|
||||||
|
// Some require both. Your provider's authentication policies will determine
|
||||||
|
// how these fields influence authentication.
|
||||||
|
TenantID string `json:"tenantId,omitempty"`
|
||||||
|
TenantName string `json:"tenantName,omitempty"`
|
||||||
|
|
||||||
|
// TokenCredentials allows users to authenticate (possibly as another user) with an
|
||||||
|
// authentication token ID.
|
||||||
|
TokenCredentials *TokenCredentialsV2 `json:"token,omitempty" xor:"PasswordCredentials"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthOptionsBuilder describes any argument that may be passed to the Create call.
|
||||||
|
type AuthOptionsBuilder interface {
|
||||||
|
// ToTokenCreateMap assembles the Create request body, returning an error if parameters are
|
||||||
|
// missing or inconsistent.
|
||||||
|
ToTokenV2CreateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthOptions are the valid options for Openstack Identity v2 authentication.
|
||||||
|
// For field descriptions, see gophercloud.AuthOptions.
|
||||||
|
type AuthOptions struct {
|
||||||
|
IdentityEndpoint string `json:"-"`
|
||||||
|
Username string `json:"username,omitempty"`
|
||||||
|
Password string `json:"password,omitempty"`
|
||||||
|
TenantID string `json:"tenantId,omitempty"`
|
||||||
|
TenantName string `json:"tenantName,omitempty"`
|
||||||
|
AllowReauth bool `json:"-"`
|
||||||
|
TokenID string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToTokenV2CreateMap allows AuthOptions to satisfy the AuthOptionsBuilder
|
||||||
|
// interface in the v2 tokens package
|
||||||
|
func (opts AuthOptions) ToTokenV2CreateMap() (map[string]interface{}, error) {
|
||||||
|
v2Opts := AuthOptionsV2{
|
||||||
|
TenantID: opts.TenantID,
|
||||||
|
TenantName: opts.TenantName,
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.Password != "" {
|
||||||
|
v2Opts.PasswordCredentials = &PasswordCredentialsV2{
|
||||||
|
Username: opts.Username,
|
||||||
|
Password: opts.Password,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
v2Opts.TokenCredentials = &TokenCredentialsV2{
|
||||||
|
ID: opts.TokenID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := gophercloud.BuildRequestBody(v2Opts, "auth")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create authenticates to the identity service and attempts to acquire a Token.
|
||||||
|
// If successful, the CreateResult
|
||||||
|
// Generally, rather than interact with this call directly, end users should call openstack.AuthenticatedClient(),
|
||||||
|
// which abstracts all of the gory details about navigating service catalogs and such.
|
||||||
|
func Create(client *gophercloud.ServiceClient, auth AuthOptionsBuilder) (r CreateResult) {
|
||||||
|
b, err := auth.ToTokenV2CreateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = client.Post(CreateURL(client), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200, 203},
|
||||||
|
MoreHeaders: map[string]string{"X-Auth-Token": ""},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get validates and retrieves information for user's token.
|
||||||
|
func Get(client *gophercloud.ServiceClient, token string) (r GetResult) {
|
||||||
|
_, r.Err = client.Get(GetURL(client, token), &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200, 203},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
149
vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tokens/results.go
generated
vendored
Normal file
149
vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tokens/results.go
generated
vendored
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
package tokens
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/identity/v2/tenants"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Token provides only the most basic information related to an authentication token.
|
||||||
|
type Token struct {
|
||||||
|
// ID provides the primary means of identifying a user to the OpenStack API.
|
||||||
|
// OpenStack defines this field as an opaque value, so do not depend on its content.
|
||||||
|
// It is safe, however, to compare for equality.
|
||||||
|
ID string
|
||||||
|
|
||||||
|
// ExpiresAt provides a timestamp in ISO 8601 format, indicating when the authentication token becomes invalid.
|
||||||
|
// After this point in time, future API requests made using this authentication token will respond with errors.
|
||||||
|
// Either the caller will need to reauthenticate manually, or more preferably, the caller should exploit automatic re-authentication.
|
||||||
|
// See the AuthOptions structure for more details.
|
||||||
|
ExpiresAt time.Time
|
||||||
|
|
||||||
|
// Tenant provides information about the tenant to which this token grants access.
|
||||||
|
Tenant tenants.Tenant
|
||||||
|
}
|
||||||
|
|
||||||
|
// Role is a role for a user.
|
||||||
|
type Role struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// User is an OpenStack user.
|
||||||
|
type User struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
UserName string `json:"username"`
|
||||||
|
Roles []Role `json:"roles"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Endpoint represents a single API endpoint offered by a service.
|
||||||
|
// It provides the public and internal URLs, if supported, along with a region specifier, again if provided.
|
||||||
|
// The significance of the Region field will depend upon your provider.
|
||||||
|
//
|
||||||
|
// In addition, the interface offered by the service will have version information associated with it
|
||||||
|
// through the VersionId, VersionInfo, and VersionList fields, if provided or supported.
|
||||||
|
//
|
||||||
|
// In all cases, fields which aren't supported by the provider and service combined will assume a zero-value ("").
|
||||||
|
type Endpoint struct {
|
||||||
|
TenantID string `json:"tenantId"`
|
||||||
|
PublicURL string `json:"publicURL"`
|
||||||
|
InternalURL string `json:"internalURL"`
|
||||||
|
AdminURL string `json:"adminURL"`
|
||||||
|
Region string `json:"region"`
|
||||||
|
VersionID string `json:"versionId"`
|
||||||
|
VersionInfo string `json:"versionInfo"`
|
||||||
|
VersionList string `json:"versionList"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CatalogEntry provides a type-safe interface to an Identity API V2 service catalog listing.
|
||||||
|
// Each class of service, such as cloud DNS or block storage services, will have a single
|
||||||
|
// CatalogEntry representing it.
|
||||||
|
//
|
||||||
|
// Note: when looking for the desired service, try, whenever possible, to key off the type field.
|
||||||
|
// Otherwise, you'll tie the representation of the service to a specific provider.
|
||||||
|
type CatalogEntry struct {
|
||||||
|
// Name will contain the provider-specified name for the service.
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// Type will contain a type string if OpenStack defines a type for the service.
|
||||||
|
// Otherwise, for provider-specific services, the provider may assign their own type strings.
|
||||||
|
Type string `json:"type"`
|
||||||
|
|
||||||
|
// Endpoints will let the caller iterate over all the different endpoints that may exist for
|
||||||
|
// the service.
|
||||||
|
Endpoints []Endpoint `json:"endpoints"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceCatalog provides a view into the service catalog from a previous, successful authentication.
|
||||||
|
type ServiceCatalog struct {
|
||||||
|
Entries []CatalogEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateResult defers the interpretation of a created token.
|
||||||
|
// Use ExtractToken() to interpret it as a Token, or ExtractServiceCatalog() to interpret it as a service catalog.
|
||||||
|
type CreateResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResult is the deferred response from a Get call, which is the same with a Created token.
|
||||||
|
// Use ExtractUser() to interpret it as a User.
|
||||||
|
type GetResult struct {
|
||||||
|
CreateResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractToken returns the just-created Token from a CreateResult.
|
||||||
|
func (r CreateResult) ExtractToken() (*Token, error) {
|
||||||
|
var s struct {
|
||||||
|
Access struct {
|
||||||
|
Token struct {
|
||||||
|
Expires string `json:"expires"`
|
||||||
|
ID string `json:"id"`
|
||||||
|
Tenant tenants.Tenant `json:"tenant"`
|
||||||
|
} `json:"token"`
|
||||||
|
} `json:"access"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
expiresTs, err := time.Parse(gophercloud.RFC3339Milli, s.Access.Token.Expires)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Token{
|
||||||
|
ID: s.Access.Token.ID,
|
||||||
|
ExpiresAt: expiresTs,
|
||||||
|
Tenant: s.Access.Token.Tenant,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractServiceCatalog returns the ServiceCatalog that was generated along with the user's Token.
|
||||||
|
func (r CreateResult) ExtractServiceCatalog() (*ServiceCatalog, error) {
|
||||||
|
var s struct {
|
||||||
|
Access struct {
|
||||||
|
Entries []CatalogEntry `json:"serviceCatalog"`
|
||||||
|
} `json:"access"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return &ServiceCatalog{Entries: s.Access.Entries}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// createErr quickly packs an error in a CreateResult.
|
||||||
|
func createErr(err error) CreateResult {
|
||||||
|
return CreateResult{gophercloud.Result{Err: err}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractUser returns the User from a GetResult.
|
||||||
|
func (r GetResult) ExtractUser() (*User, error) {
|
||||||
|
var s struct {
|
||||||
|
Access struct {
|
||||||
|
User User `json:"user"`
|
||||||
|
} `json:"access"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return &s.Access.User, err
|
||||||
|
}
|
13
vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tokens/urls.go
generated
vendored
Normal file
13
vendor/github.com/gophercloud/gophercloud/openstack/identity/v2/tokens/urls.go
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package tokens
|
||||||
|
|
||||||
|
import "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
// CreateURL generates the URL used to create new Tokens.
|
||||||
|
func CreateURL(client *gophercloud.ServiceClient) string {
|
||||||
|
return client.ServiceURL("tokens")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetURL generates the URL used to Validate Tokens.
|
||||||
|
func GetURL(client *gophercloud.ServiceClient, token string) string {
|
||||||
|
return client.ServiceURL("tokens", token)
|
||||||
|
}
|
6
vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/tokens/doc.go
generated
vendored
Normal file
6
vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/tokens/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
// Package tokens provides information and interaction with the token API
|
||||||
|
// resource for the OpenStack Identity service.
|
||||||
|
//
|
||||||
|
// For more information, see:
|
||||||
|
// http://developer.openstack.org/api-ref-identity-v3.html#tokens-v3
|
||||||
|
package tokens
|
200
vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/tokens/requests.go
generated
vendored
Normal file
200
vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/tokens/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,200 @@
|
||||||
|
package tokens
|
||||||
|
|
||||||
|
import "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
// Scope allows a created token to be limited to a specific domain or project.
|
||||||
|
type Scope struct {
|
||||||
|
ProjectID string `json:"scope.project.id,omitempty" not:"ProjectName,DomainID,DomainName"`
|
||||||
|
ProjectName string `json:"scope.project.name,omitempty"`
|
||||||
|
DomainID string `json:"scope.project.id,omitempty" not:"ProjectName,ProjectID,DomainName"`
|
||||||
|
DomainName string `json:"scope.project.id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthOptionsBuilder describes any argument that may be passed to the Create call.
|
||||||
|
type AuthOptionsBuilder interface {
|
||||||
|
// ToTokenV3CreateMap assembles the Create request body, returning an error if parameters are
|
||||||
|
// missing or inconsistent.
|
||||||
|
ToTokenV3CreateMap(map[string]interface{}) (map[string]interface{}, error)
|
||||||
|
ToTokenV3ScopeMap() (map[string]interface{}, error)
|
||||||
|
CanReauth() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type AuthOptions struct {
|
||||||
|
// IdentityEndpoint specifies the HTTP endpoint that is required to work with
|
||||||
|
// the Identity API of the appropriate version. While it's ultimately needed by
|
||||||
|
// all of the identity services, it will often be populated by a provider-level
|
||||||
|
// function.
|
||||||
|
IdentityEndpoint string `json:"-"`
|
||||||
|
|
||||||
|
// Username is required if using Identity V2 API. Consult with your provider's
|
||||||
|
// control panel to discover your account's username. In Identity V3, either
|
||||||
|
// UserID or a combination of Username and DomainID or DomainName are needed.
|
||||||
|
Username string `json:"username,omitempty"`
|
||||||
|
UserID string `json:"id,omitempty"`
|
||||||
|
|
||||||
|
Password string `json:"password,omitempty"`
|
||||||
|
|
||||||
|
// At most one of DomainID and DomainName must be provided if using Username
|
||||||
|
// with Identity V3. Otherwise, either are optional.
|
||||||
|
DomainID string `json:"id,omitempty"`
|
||||||
|
DomainName string `json:"name,omitempty"`
|
||||||
|
|
||||||
|
// AllowReauth should be set to true if you grant permission for Gophercloud to
|
||||||
|
// cache your credentials in memory, and to allow Gophercloud to attempt to
|
||||||
|
// re-authenticate automatically if/when your token expires. If you set it to
|
||||||
|
// false, it will not cache these settings, but re-authentication will not be
|
||||||
|
// possible. This setting defaults to false.
|
||||||
|
AllowReauth bool `json:"-"`
|
||||||
|
|
||||||
|
// TokenID allows users to authenticate (possibly as another user) with an
|
||||||
|
// authentication token ID.
|
||||||
|
TokenID string `json:"-"`
|
||||||
|
|
||||||
|
Scope Scope `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opts *AuthOptions) ToTokenV3CreateMap(scope map[string]interface{}) (map[string]interface{}, error) {
|
||||||
|
gophercloudAuthOpts := gophercloud.AuthOptions{
|
||||||
|
Username: opts.Username,
|
||||||
|
UserID: opts.UserID,
|
||||||
|
Password: opts.Password,
|
||||||
|
DomainID: opts.DomainID,
|
||||||
|
DomainName: opts.DomainName,
|
||||||
|
AllowReauth: opts.AllowReauth,
|
||||||
|
TokenID: opts.TokenID,
|
||||||
|
}
|
||||||
|
|
||||||
|
return gophercloudAuthOpts.ToTokenV3CreateMap(scope)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opts *AuthOptions) ToTokenV3ScopeMap() (map[string]interface{}, error) {
|
||||||
|
if opts.Scope.ProjectName != "" {
|
||||||
|
// ProjectName provided: either DomainID or DomainName must also be supplied.
|
||||||
|
// ProjectID may not be supplied.
|
||||||
|
if opts.Scope.DomainID == "" && opts.Scope.DomainName == "" {
|
||||||
|
return nil, gophercloud.ErrScopeDomainIDOrDomainName{}
|
||||||
|
}
|
||||||
|
if opts.Scope.ProjectID != "" {
|
||||||
|
return nil, gophercloud.ErrScopeProjectIDOrProjectName{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.Scope.DomainID != "" {
|
||||||
|
// ProjectName + DomainID
|
||||||
|
return map[string]interface{}{
|
||||||
|
"project": map[string]interface{}{
|
||||||
|
"name": &opts.Scope.ProjectName,
|
||||||
|
"domain": map[string]interface{}{"id": &opts.Scope.DomainID},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.Scope.DomainName != "" {
|
||||||
|
// ProjectName + DomainName
|
||||||
|
return map[string]interface{}{
|
||||||
|
"project": map[string]interface{}{
|
||||||
|
"name": &opts.Scope.ProjectName,
|
||||||
|
"domain": map[string]interface{}{"name": &opts.Scope.DomainName},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
} else if opts.Scope.ProjectID != "" {
|
||||||
|
// ProjectID provided. ProjectName, DomainID, and DomainName may not be provided.
|
||||||
|
if opts.Scope.DomainID != "" {
|
||||||
|
return nil, gophercloud.ErrScopeProjectIDAlone{}
|
||||||
|
}
|
||||||
|
if opts.Scope.DomainName != "" {
|
||||||
|
return nil, gophercloud.ErrScopeProjectIDAlone{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectID
|
||||||
|
return map[string]interface{}{
|
||||||
|
"project": map[string]interface{}{
|
||||||
|
"id": &opts.Scope.ProjectID,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
} else if opts.Scope.DomainID != "" {
|
||||||
|
// DomainID provided. ProjectID, ProjectName, and DomainName may not be provided.
|
||||||
|
if opts.Scope.DomainName != "" {
|
||||||
|
return nil, gophercloud.ErrScopeDomainIDOrDomainName{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DomainID
|
||||||
|
return map[string]interface{}{
|
||||||
|
"domain": map[string]interface{}{
|
||||||
|
"id": &opts.Scope.DomainID,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
} else if opts.Scope.DomainName != "" {
|
||||||
|
return nil, gophercloud.ErrScopeDomainName{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opts *AuthOptions) CanReauth() bool {
|
||||||
|
return opts.AllowReauth
|
||||||
|
}
|
||||||
|
|
||||||
|
func subjectTokenHeaders(c *gophercloud.ServiceClient, subjectToken string) map[string]string {
|
||||||
|
return map[string]string{
|
||||||
|
"X-Subject-Token": subjectToken,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create authenticates and either generates a new token, or changes the Scope of an existing token.
|
||||||
|
func Create(c *gophercloud.ServiceClient, opts AuthOptionsBuilder) (r CreateResult) {
|
||||||
|
scope, err := opts.ToTokenV3ScopeMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := opts.ToTokenV3CreateMap(scope)
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.Post(tokenURL(c), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
MoreHeaders: map[string]string{"X-Auth-Token": ""},
|
||||||
|
})
|
||||||
|
r.Err = err
|
||||||
|
if resp != nil {
|
||||||
|
r.Header = resp.Header
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get validates and retrieves information about another token.
|
||||||
|
func Get(c *gophercloud.ServiceClient, token string) (r GetResult) {
|
||||||
|
resp, err := c.Get(tokenURL(c), &r.Body, &gophercloud.RequestOpts{
|
||||||
|
MoreHeaders: subjectTokenHeaders(c, token),
|
||||||
|
OkCodes: []int{200, 203},
|
||||||
|
})
|
||||||
|
if resp != nil {
|
||||||
|
r.Err = err
|
||||||
|
r.Header = resp.Header
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate determines if a specified token is valid or not.
|
||||||
|
func Validate(c *gophercloud.ServiceClient, token string) (bool, error) {
|
||||||
|
resp, err := c.Request("HEAD", tokenURL(c), &gophercloud.RequestOpts{
|
||||||
|
MoreHeaders: subjectTokenHeaders(c, token),
|
||||||
|
OkCodes: []int{204, 404},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp.StatusCode == 204, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Revoke immediately makes specified token invalid.
|
||||||
|
func Revoke(c *gophercloud.ServiceClient, token string) (r RevokeResult) {
|
||||||
|
_, r.Err = c.Delete(tokenURL(c), &gophercloud.RequestOpts{
|
||||||
|
MoreHeaders: subjectTokenHeaders(c, token),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
114
vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/tokens/results.go
generated
vendored
Normal file
114
vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/tokens/results.go
generated
vendored
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
package tokens
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
import "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
// Endpoint represents a single API endpoint offered by a service.
|
||||||
|
// It matches either a public, internal or admin URL.
|
||||||
|
// If supported, it contains a region specifier, again if provided.
|
||||||
|
// The significance of the Region field will depend upon your provider.
|
||||||
|
type Endpoint struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Region string `json:"region"`
|
||||||
|
Interface string `json:"interface"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CatalogEntry provides a type-safe interface to an Identity API V3 service catalog listing.
|
||||||
|
// Each class of service, such as cloud DNS or block storage services, could have multiple
|
||||||
|
// CatalogEntry representing it (one by interface type, e.g public, admin or internal).
|
||||||
|
//
|
||||||
|
// Note: when looking for the desired service, try, whenever possible, to key off the type field.
|
||||||
|
// Otherwise, you'll tie the representation of the service to a specific provider.
|
||||||
|
type CatalogEntry struct {
|
||||||
|
// Service ID
|
||||||
|
ID string `json:"id"`
|
||||||
|
// Name will contain the provider-specified name for the service.
|
||||||
|
Name string `json:"name"`
|
||||||
|
// Type will contain a type string if OpenStack defines a type for the service.
|
||||||
|
// Otherwise, for provider-specific services, the provider may assign their own type strings.
|
||||||
|
Type string `json:"type"`
|
||||||
|
// Endpoints will let the caller iterate over all the different endpoints that may exist for
|
||||||
|
// the service.
|
||||||
|
Endpoints []Endpoint `json:"endpoints"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceCatalog provides a view into the service catalog from a previous, successful authentication.
|
||||||
|
type ServiceCatalog struct {
|
||||||
|
Entries []CatalogEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
// commonResult is the deferred result of a Create or a Get call.
|
||||||
|
type commonResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract is a shortcut for ExtractToken.
|
||||||
|
// This function is deprecated and still present for backward compatibility.
|
||||||
|
func (r commonResult) Extract() (*Token, error) {
|
||||||
|
return r.ExtractToken()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractToken interprets a commonResult as a Token.
|
||||||
|
func (r commonResult) ExtractToken() (*Token, error) {
|
||||||
|
var s struct {
|
||||||
|
Token *Token `json:"token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Token == nil {
|
||||||
|
return nil, errors.New("'token' missing in JSON response")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the token itself from the stored headers.
|
||||||
|
s.Token.ID = r.Header.Get("X-Subject-Token")
|
||||||
|
|
||||||
|
return s.Token, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractServiceCatalog returns the ServiceCatalog that was generated along with the user's Token.
|
||||||
|
func (r CreateResult) ExtractServiceCatalog() (*ServiceCatalog, error) {
|
||||||
|
var s struct {
|
||||||
|
Token struct {
|
||||||
|
Entries []CatalogEntry `json:"catalog"`
|
||||||
|
} `json:"token"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return &ServiceCatalog{Entries: s.Token.Entries}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateResult defers the interpretation of a created token.
|
||||||
|
// Use ExtractToken() to interpret it as a Token, or ExtractServiceCatalog() to interpret it as a service catalog.
|
||||||
|
type CreateResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// createErr quickly creates a CreateResult that reports an error.
|
||||||
|
func createErr(err error) CreateResult {
|
||||||
|
return CreateResult{
|
||||||
|
commonResult: commonResult{Result: gophercloud.Result{Err: err}},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResult is the deferred response from a Get call.
|
||||||
|
type GetResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// RevokeResult is the deferred response from a Revoke call.
|
||||||
|
type RevokeResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token is a string that grants a user access to a controlled set of services in an OpenStack provider.
|
||||||
|
// Each Token is valid for a set length of time.
|
||||||
|
type Token struct {
|
||||||
|
// ID is the issued token.
|
||||||
|
ID string `json:"id"`
|
||||||
|
// ExpiresAt is the timestamp at which this token will no longer be accepted.
|
||||||
|
ExpiresAt gophercloud.JSONRFC3339Milli `json:"expires_at"`
|
||||||
|
}
|
7
vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/tokens/urls.go
generated
vendored
Normal file
7
vendor/github.com/gophercloud/gophercloud/openstack/identity/v3/tokens/urls.go
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package tokens
|
||||||
|
|
||||||
|
import "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
func tokenURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return c.ServiceURL("auth", "tokens")
|
||||||
|
}
|
11
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls/errors.go
generated
vendored
Normal file
11
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls/errors.go
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package firewalls
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func err(str string) error {
|
||||||
|
return fmt.Errorf("%s", str)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errPolicyRequired = err("A policy ID is required")
|
||||||
|
)
|
140
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls/requests.go
generated
vendored
Normal file
140
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
package firewalls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ListOptsBuilder allows extensions to add additional parameters to the
|
||||||
|
// List request.
|
||||||
|
type ListOptsBuilder interface {
|
||||||
|
ToFirewallListQuery() (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListOpts allows the filtering and sorting of paginated collections through
|
||||||
|
// the API. Filtering is achieved by passing in struct field values that map to
|
||||||
|
// the firewall attributes you want to see returned. SortKey allows you to sort
|
||||||
|
// by a particular firewall attribute. SortDir sets the direction, and is either
|
||||||
|
// `asc' or `desc'. Marker and Limit are used for pagination.
|
||||||
|
type ListOpts struct {
|
||||||
|
TenantID string `q:"tenant_id"`
|
||||||
|
Name string `q:"name"`
|
||||||
|
Description string `q:"description"`
|
||||||
|
AdminStateUp bool `q:"admin_state_up"`
|
||||||
|
Shared bool `q:"shared"`
|
||||||
|
PolicyID string `q:"firewall_policy_id"`
|
||||||
|
ID string `q:"id"`
|
||||||
|
Limit int `q:"limit"`
|
||||||
|
Marker string `q:"marker"`
|
||||||
|
SortKey string `q:"sort_key"`
|
||||||
|
SortDir string `q:"sort_dir"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToFirewallListQuery formats a ListOpts into a query string.
|
||||||
|
func (opts ListOpts) ToFirewallListQuery() (string, error) {
|
||||||
|
q, err := gophercloud.BuildQueryString(opts)
|
||||||
|
return q.String(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// List returns a Pager which allows you to iterate over a collection of
|
||||||
|
// firewalls. It accepts a ListOpts struct, which allows you to filter
|
||||||
|
// and sort the returned collection for greater efficiency.
|
||||||
|
//
|
||||||
|
// Default policy settings return only those firewalls that are owned by the
|
||||||
|
// tenant who submits the request, unless an admin user submits the request.
|
||||||
|
func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
|
||||||
|
url := rootURL(c)
|
||||||
|
if opts != nil {
|
||||||
|
query, err := opts.ToFirewallListQuery()
|
||||||
|
if err != nil {
|
||||||
|
return pagination.Pager{Err: err}
|
||||||
|
}
|
||||||
|
url += query
|
||||||
|
}
|
||||||
|
return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page {
|
||||||
|
return FirewallPage{pagination.LinkedPageBase{PageResult: r}}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOptsBuilder is the interface options structs have to satisfy in order
|
||||||
|
// to be used in the main Create operation in this package. Since many
|
||||||
|
// extensions decorate or modify the common logic, it is useful for them to
|
||||||
|
// satisfy a basic interface in order for them to be used.
|
||||||
|
type CreateOptsBuilder interface {
|
||||||
|
ToFirewallCreateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOpts contains all the values needed to create a new firewall.
|
||||||
|
type CreateOpts struct {
|
||||||
|
PolicyID string `json:"firewall_policy_id" required:"true"`
|
||||||
|
// Only required if the caller has an admin role and wants to create a firewall
|
||||||
|
// for another tenant.
|
||||||
|
TenantID string `json:"tenant_id,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
AdminStateUp *bool `json:"admin_state_up,omitempty"`
|
||||||
|
Shared *bool `json:"shared,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToFirewallCreateMap casts a CreateOpts struct to a map.
|
||||||
|
func (opts CreateOpts) ToFirewallCreateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "firewall")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create accepts a CreateOpts struct and uses the values to create a new firewall
|
||||||
|
func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
|
||||||
|
b, err := opts.ToFirewallCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = c.Post(rootURL(c), b, &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get retrieves a particular firewall based on its unique ID.
|
||||||
|
func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
|
||||||
|
_, r.Err = c.Get(resourceURL(c, id), &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateOptsBuilder is the interface options structs have to satisfy in order
|
||||||
|
// to be used in the main Update operation in this package. Since many
|
||||||
|
// extensions decorate or modify the common logic, it is useful for them to
|
||||||
|
// satisfy a basic interface in order for them to be used.
|
||||||
|
type UpdateOptsBuilder interface {
|
||||||
|
ToFirewallUpdateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateOpts contains the values used when updating a firewall.
|
||||||
|
type UpdateOpts struct {
|
||||||
|
PolicyID string `json:"firewall_policy_id" required:"true"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
AdminStateUp *bool `json:"admin_state_up,omitempty"`
|
||||||
|
Shared *bool `json:"shared,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToFirewallUpdateMap casts a CreateOpts struct to a map.
|
||||||
|
func (opts UpdateOpts) ToFirewallUpdateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "firewall")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update allows firewalls to be updated.
|
||||||
|
func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) {
|
||||||
|
b, err := opts.ToFirewallUpdateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = c.Put(resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete will permanently delete a particular firewall based on its unique ID.
|
||||||
|
func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) {
|
||||||
|
_, r.Err = c.Delete(resourceURL(c, id), nil)
|
||||||
|
return
|
||||||
|
}
|
87
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls/results.go
generated
vendored
Normal file
87
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls/results.go
generated
vendored
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
package firewalls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Firewall is an OpenStack firewall.
|
||||||
|
type Firewall struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
AdminStateUp bool `json:"admin_state_up"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
PolicyID string `json:"firewall_policy_id"`
|
||||||
|
TenantID string `json:"tenant_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type commonResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract is a function that accepts a result and extracts a firewall.
|
||||||
|
func (r commonResult) Extract() (*Firewall, error) {
|
||||||
|
var s struct {
|
||||||
|
Firewall *Firewall `json:"firewall"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return s.Firewall, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FirewallPage is the page returned by a pager when traversing over a
|
||||||
|
// collection of firewalls.
|
||||||
|
type FirewallPage struct {
|
||||||
|
pagination.LinkedPageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// NextPageURL is invoked when a paginated collection of firewalls has reached
|
||||||
|
// the end of a page and the pager seeks to traverse over a new one. In order
|
||||||
|
// to do this, it needs to construct the next page's URL.
|
||||||
|
func (r FirewallPage) NextPageURL() (string, error) {
|
||||||
|
var s struct {
|
||||||
|
Links []gophercloud.Link `json:"firewalls_links"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return gophercloud.ExtractNextURL(s.Links)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty checks whether a FirewallPage struct is empty.
|
||||||
|
func (r FirewallPage) IsEmpty() (bool, error) {
|
||||||
|
is, err := ExtractFirewalls(r)
|
||||||
|
return len(is) == 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractFirewalls accepts a Page struct, specifically a RouterPage struct,
|
||||||
|
// and extracts the elements into a slice of Router structs. In other words,
|
||||||
|
// a generic collection is mapped into a relevant slice.
|
||||||
|
func ExtractFirewalls(r pagination.Page) ([]Firewall, error) {
|
||||||
|
var s struct {
|
||||||
|
Firewalls []Firewall `json:"firewalls" json:"firewalls"`
|
||||||
|
}
|
||||||
|
err := (r.(FirewallPage)).ExtractInto(&s)
|
||||||
|
return s.Firewalls, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResult represents the result of a get operation.
|
||||||
|
type GetResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateResult represents the result of an update operation.
|
||||||
|
type UpdateResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteResult represents the result of a delete operation.
|
||||||
|
type DeleteResult struct {
|
||||||
|
gophercloud.ErrResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateResult represents the result of a create operation.
|
||||||
|
type CreateResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
16
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls/urls.go
generated
vendored
Normal file
16
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls/urls.go
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package firewalls
|
||||||
|
|
||||||
|
import "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
const (
|
||||||
|
rootPath = "fw"
|
||||||
|
resourcePath = "firewalls"
|
||||||
|
)
|
||||||
|
|
||||||
|
func rootURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return c.ServiceURL(rootPath, resourcePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return c.ServiceURL(rootPath, resourcePath, id)
|
||||||
|
}
|
173
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/policies/requests.go
generated
vendored
Normal file
173
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/policies/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
package policies
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ListOptsBuilder allows extensions to add additional parameters to the
|
||||||
|
// List request.
|
||||||
|
type ListOptsBuilder interface {
|
||||||
|
ToPolicyListQuery() (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListOpts allows the filtering and sorting of paginated collections through
|
||||||
|
// the API. Filtering is achieved by passing in struct field values that map to
|
||||||
|
// the firewall policy attributes you want to see returned. SortKey allows you
|
||||||
|
// to sort by a particular firewall policy attribute. SortDir sets the direction,
|
||||||
|
// and is either `asc' or `desc'. Marker and Limit are used for pagination.
|
||||||
|
type ListOpts struct {
|
||||||
|
TenantID string `q:"tenant_id"`
|
||||||
|
Name string `q:"name"`
|
||||||
|
Description string `q:"description"`
|
||||||
|
Shared *bool `q:"shared"`
|
||||||
|
Audited *bool `q:"audited"`
|
||||||
|
ID string `q:"id"`
|
||||||
|
Limit int `q:"limit"`
|
||||||
|
Marker string `q:"marker"`
|
||||||
|
SortKey string `q:"sort_key"`
|
||||||
|
SortDir string `q:"sort_dir"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToPolicyListQuery formats a ListOpts into a query string.
|
||||||
|
func (opts ListOpts) ToPolicyListQuery() (string, error) {
|
||||||
|
q, err := gophercloud.BuildQueryString(opts)
|
||||||
|
return q.String(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// List returns a Pager which allows you to iterate over a collection of
|
||||||
|
// firewall policies. It accepts a ListOpts struct, which allows you to filter
|
||||||
|
// and sort the returned collection for greater efficiency.
|
||||||
|
//
|
||||||
|
// Default policy settings return only those firewall policies that are owned by the
|
||||||
|
// tenant who submits the request, unless an admin user submits the request.
|
||||||
|
func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
|
||||||
|
url := rootURL(c)
|
||||||
|
if opts != nil {
|
||||||
|
query, err := opts.ToPolicyListQuery()
|
||||||
|
if err != nil {
|
||||||
|
return pagination.Pager{Err: err}
|
||||||
|
}
|
||||||
|
url += query
|
||||||
|
}
|
||||||
|
return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page {
|
||||||
|
return PolicyPage{pagination.LinkedPageBase{PageResult: r}}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOptsBuilder is the interface options structs have to satisfy in order
|
||||||
|
// to be used in the main Create operation in this package. Since many
|
||||||
|
// extensions decorate or modify the common logic, it is useful for them to
|
||||||
|
// satisfy a basic interface in order for them to be used.
|
||||||
|
type CreateOptsBuilder interface {
|
||||||
|
ToFirewallPolicyCreateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOpts contains all the values needed to create a new firewall policy.
|
||||||
|
type CreateOpts struct {
|
||||||
|
// Only required if the caller has an admin role and wants to create a firewall policy
|
||||||
|
// for another tenant.
|
||||||
|
TenantID string `json:"tenant_id,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Shared *bool `json:"shared,omitempty"`
|
||||||
|
Audited *bool `json:"audited,omitempty"`
|
||||||
|
Rules []string `json:"firewall_rules,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToFirewallPolicyCreateMap casts a CreateOpts struct to a map.
|
||||||
|
func (opts CreateOpts) ToFirewallPolicyCreateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "firewall_policy")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create accepts a CreateOpts struct and uses the values to create a new firewall policy
|
||||||
|
func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
|
||||||
|
b, err := opts.ToFirewallPolicyCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = c.Post(rootURL(c), b, &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get retrieves a particular firewall policy based on its unique ID.
|
||||||
|
func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
|
||||||
|
_, r.Err = c.Get(resourceURL(c, id), &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateOptsBuilder is the interface options structs have to satisfy in order
|
||||||
|
// to be used in the main Update operation in this package. Since many
|
||||||
|
// extensions decorate or modify the common logic, it is useful for them to
|
||||||
|
// satisfy a basic interface in order for them to be used.
|
||||||
|
type UpdateOptsBuilder interface {
|
||||||
|
ToFirewallPolicyUpdateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateOpts contains the values used when updating a firewall policy.
|
||||||
|
type UpdateOpts struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Shared *bool `json:"shared,omitempty"`
|
||||||
|
Audited *bool `json:"audited,omitempty"`
|
||||||
|
Rules []string `json:"firewall_rules,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToFirewallPolicyUpdateMap casts a CreateOpts struct to a map.
|
||||||
|
func (opts UpdateOpts) ToFirewallPolicyUpdateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "firewall_policy")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update allows firewall policies to be updated.
|
||||||
|
func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) {
|
||||||
|
b, err := opts.ToFirewallPolicyUpdateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = c.Put(resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete will permanently delete a particular firewall policy based on its unique ID.
|
||||||
|
func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) {
|
||||||
|
_, r.Err = c.Delete(resourceURL(c, id), nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type InsertRuleOptsBuilder interface {
|
||||||
|
ToFirewallPolicyInsertRuleMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type InsertRuleOpts struct {
|
||||||
|
ID string `json:"firewall_rule_id" required:"true"`
|
||||||
|
BeforeRuleID string `json:"insert_before,omitempty"`
|
||||||
|
AfterRuleID string `json:"insert_after,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opts InsertRuleOpts) ToFirewallPolicyInsertRuleMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddRule(c *gophercloud.ServiceClient, id string, opts InsertRuleOptsBuilder) (r InsertRuleResult) {
|
||||||
|
b, err := opts.ToFirewallPolicyInsertRuleMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = c.Put(insertURL(c, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func RemoveRule(c *gophercloud.ServiceClient, id, ruleID string) (r RemoveRuleResult) {
|
||||||
|
b := map[string]interface{}{"firewall_rule_id": ruleID}
|
||||||
|
_, r.Err = c.Put(removeURL(c, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
97
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/policies/results.go
generated
vendored
Normal file
97
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/policies/results.go
generated
vendored
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
package policies
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Policy is a firewall policy.
|
||||||
|
type Policy struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
TenantID string `json:"tenant_id"`
|
||||||
|
Audited bool `json:"audited"`
|
||||||
|
Shared bool `json:"shared"`
|
||||||
|
Rules []string `json:"firewall_rules,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type commonResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract is a function that accepts a result and extracts a firewall policy.
|
||||||
|
func (r commonResult) Extract() (*Policy, error) {
|
||||||
|
var s struct {
|
||||||
|
Policy *Policy `json:"firewall_policy"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return s.Policy, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// PolicyPage is the page returned by a pager when traversing over a
|
||||||
|
// collection of firewall policies.
|
||||||
|
type PolicyPage struct {
|
||||||
|
pagination.LinkedPageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// NextPageURL is invoked when a paginated collection of firewall policies has
|
||||||
|
// reached the end of a page and the pager seeks to traverse over a new one.
|
||||||
|
// In order to do this, it needs to construct the next page's URL.
|
||||||
|
func (r PolicyPage) NextPageURL() (string, error) {
|
||||||
|
var s struct {
|
||||||
|
Links []gophercloud.Link `json:"firewall_policies_links"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return gophercloud.ExtractNextURL(s.Links)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty checks whether a PolicyPage struct is empty.
|
||||||
|
func (r PolicyPage) IsEmpty() (bool, error) {
|
||||||
|
is, err := ExtractPolicies(r)
|
||||||
|
return len(is) == 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractPolicies accepts a Page struct, specifically a RouterPage struct,
|
||||||
|
// and extracts the elements into a slice of Router structs. In other words,
|
||||||
|
// a generic collection is mapped into a relevant slice.
|
||||||
|
func ExtractPolicies(r pagination.Page) ([]Policy, error) {
|
||||||
|
var s struct {
|
||||||
|
Policies []Policy `json:"firewall_policies"`
|
||||||
|
}
|
||||||
|
err := (r.(PolicyPage)).ExtractInto(&s)
|
||||||
|
return s.Policies, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResult represents the result of a get operation.
|
||||||
|
type GetResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateResult represents the result of an update operation.
|
||||||
|
type UpdateResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteResult represents the result of a delete operation.
|
||||||
|
type DeleteResult struct {
|
||||||
|
gophercloud.ErrResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateResult represents the result of a create operation.
|
||||||
|
type CreateResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertRuleResult represents the result of an InsertRule operation.
|
||||||
|
type InsertRuleResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveRuleResult represents the result of a RemoveRule operation.
|
||||||
|
type RemoveRuleResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
26
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/policies/urls.go
generated
vendored
Normal file
26
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/policies/urls.go
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package policies
|
||||||
|
|
||||||
|
import "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
const (
|
||||||
|
rootPath = "fw"
|
||||||
|
resourcePath = "firewall_policies"
|
||||||
|
insertPath = "insert_rule"
|
||||||
|
removePath = "remove_rule"
|
||||||
|
)
|
||||||
|
|
||||||
|
func rootURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return c.ServiceURL(rootPath, resourcePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return c.ServiceURL(rootPath, resourcePath, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func insertURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return c.ServiceURL(rootPath, resourcePath, id, insertPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return c.ServiceURL(rootPath, resourcePath, id, removePath)
|
||||||
|
}
|
12
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/rules/errors.go
generated
vendored
Normal file
12
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/rules/errors.go
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package rules
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func err(str string) error {
|
||||||
|
return fmt.Errorf("%s", str)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errProtocolRequired = err("A protocol is required (tcp, udp, icmp or any)")
|
||||||
|
errActionRequired = err("An action is required (allow or deny)")
|
||||||
|
)
|
160
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/rules/requests.go
generated
vendored
Normal file
160
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/rules/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
package rules
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ListOptsBuilder allows extensions to add additional parameters to the
|
||||||
|
// List request.
|
||||||
|
type ListOptsBuilder interface {
|
||||||
|
ToRuleListQuery() (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListOpts allows the filtering and sorting of paginated collections through
|
||||||
|
// the API. Filtering is achieved by passing in struct field values that map to
|
||||||
|
// the Firewall rule attributes you want to see returned. SortKey allows you to
|
||||||
|
// sort by a particular firewall rule attribute. SortDir sets the direction, and is
|
||||||
|
// either `asc' or `desc'. Marker and Limit are used for pagination.
|
||||||
|
type ListOpts struct {
|
||||||
|
TenantID string `q:"tenant_id"`
|
||||||
|
Name string `q:"name"`
|
||||||
|
Description string `q:"description"`
|
||||||
|
Protocol string `q:"protocol"`
|
||||||
|
Action string `q:"action"`
|
||||||
|
IPVersion int `q:"ip_version"`
|
||||||
|
SourceIPAddress string `q:"source_ip_address"`
|
||||||
|
DestinationIPAddress string `q:"destination_ip_address"`
|
||||||
|
SourcePort string `q:"source_port"`
|
||||||
|
DestinationPort string `q:"destination_port"`
|
||||||
|
Enabled bool `q:"enabled"`
|
||||||
|
ID string `q:"id"`
|
||||||
|
Limit int `q:"limit"`
|
||||||
|
Marker string `q:"marker"`
|
||||||
|
SortKey string `q:"sort_key"`
|
||||||
|
SortDir string `q:"sort_dir"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToRuleListQuery formats a ListOpts into a query string.
|
||||||
|
func (opts ListOpts) ToRuleListQuery() (string, error) {
|
||||||
|
q, err := gophercloud.BuildQueryString(opts)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return q.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// List returns a Pager which allows you to iterate over a collection of
|
||||||
|
// firewall rules. It accepts a ListOpts struct, which allows you to filter
|
||||||
|
// and sort the returned collection for greater efficiency.
|
||||||
|
//
|
||||||
|
// Default policy settings return only those firewall rules that are owned by the
|
||||||
|
// tenant who submits the request, unless an admin user submits the request.
|
||||||
|
func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
|
||||||
|
url := rootURL(c)
|
||||||
|
|
||||||
|
if opts != nil {
|
||||||
|
query, err := opts.ToRuleListQuery()
|
||||||
|
if err != nil {
|
||||||
|
return pagination.Pager{Err: err}
|
||||||
|
}
|
||||||
|
url += query
|
||||||
|
}
|
||||||
|
|
||||||
|
return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page {
|
||||||
|
return RulePage{pagination.LinkedPageBase{PageResult: r}}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOptsBuilder is the interface options structs have to satisfy in order
|
||||||
|
// to be used in the main Create operation in this package. Since many
|
||||||
|
// extensions decorate or modify the common logic, it is useful for them to
|
||||||
|
// satisfy a basic interface in order for them to be used.
|
||||||
|
type CreateOptsBuilder interface {
|
||||||
|
ToRuleCreateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOpts contains all the values needed to create a new firewall rule.
|
||||||
|
type CreateOpts struct {
|
||||||
|
Protocol string `json:"protocol" required:"true"`
|
||||||
|
Action string `json:"action" required:"true"`
|
||||||
|
TenantID string `json:"tenant_id,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
IPVersion gophercloud.IPVersion `json:"ip_version,omitempty"`
|
||||||
|
SourceIPAddress string `json:"source_ip_address,omitempty"`
|
||||||
|
DestinationIPAddress string `json:"destination_ip_address,omitempty"`
|
||||||
|
SourcePort string `json:"source_port,omitempty"`
|
||||||
|
DestinationPort string `json:"destination_port,omitempty"`
|
||||||
|
Shared *bool `json:"shared,omitempty"`
|
||||||
|
Enabled *bool `json:"enabled,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToRuleCreateMap casts a CreateOpts struct to a map.
|
||||||
|
func (opts CreateOpts) ToRuleCreateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "firewall_rule")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create accepts a CreateOpts struct and uses the values to create a new firewall rule
|
||||||
|
func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
|
||||||
|
b, err := opts.ToRuleCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = c.Post(rootURL(c), b, &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get retrieves a particular firewall rule based on its unique ID.
|
||||||
|
func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
|
||||||
|
_, r.Err = c.Get(resourceURL(c, id), &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateOptsBuilder is the interface options structs have to satisfy in order
|
||||||
|
// to be used in the main Update operation in this package. Since many
|
||||||
|
// extensions decorate or modify the common logic, it is useful for them to
|
||||||
|
// satisfy a basic interface in order for them to be used.
|
||||||
|
type UpdateOptsBuilder interface {
|
||||||
|
ToRuleUpdateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateOpts contains the values used when updating a firewall rule.
|
||||||
|
type UpdateOpts struct {
|
||||||
|
Protocol *string `json:"protocol,omitempty"`
|
||||||
|
Action *string `json:"action,omitempty"`
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
Description *string `json:"description,omitempty"`
|
||||||
|
IPVersion *gophercloud.IPVersion `json:"ip_version,omitempty"`
|
||||||
|
SourceIPAddress *string `json:"source_ip_address,omitempty"`
|
||||||
|
DestinationIPAddress *string `json:"destination_ip_address,omitempty"`
|
||||||
|
SourcePort *string `json:"source_port,omitempty"`
|
||||||
|
DestinationPort *string `json:"destination_port,omitempty"`
|
||||||
|
Shared *bool `json:"shared,omitempty"`
|
||||||
|
Enabled *bool `json:"enabled,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToRuleUpdateMap casts a UpdateOpts struct to a map.
|
||||||
|
func (opts UpdateOpts) ToRuleUpdateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "firewall_rule")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update allows firewall policies to be updated.
|
||||||
|
func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) {
|
||||||
|
b, err := opts.ToRuleUpdateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = c.Put(resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete will permanently delete a particular firewall rule based on its unique ID.
|
||||||
|
func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) {
|
||||||
|
_, r.Err = c.Delete(resourceURL(c, id), nil)
|
||||||
|
return
|
||||||
|
}
|
95
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/rules/results.go
generated
vendored
Normal file
95
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/rules/results.go
generated
vendored
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
package rules
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Rule represents a firewall rule
|
||||||
|
type Rule struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Protocol string `json:"protocol"`
|
||||||
|
Action string `json:"action"`
|
||||||
|
IPVersion int `json:"ip_version,omitempty"`
|
||||||
|
SourceIPAddress string `json:"source_ip_address,omitempty"`
|
||||||
|
DestinationIPAddress string `json:"destination_ip_address,omitempty"`
|
||||||
|
SourcePort string `json:"source_port,omitempty"`
|
||||||
|
DestinationPort string `json:"destination_port,omitempty"`
|
||||||
|
Shared bool `json:"shared,omitempty"`
|
||||||
|
Enabled bool `json:"enabled,omitempty"`
|
||||||
|
PolicyID string `json:"firewall_policy_id"`
|
||||||
|
Position int `json:"position"`
|
||||||
|
TenantID string `json:"tenant_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RulePage is the page returned by a pager when traversing over a
|
||||||
|
// collection of firewall rules.
|
||||||
|
type RulePage struct {
|
||||||
|
pagination.LinkedPageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// NextPageURL is invoked when a paginated collection of firewall rules has
|
||||||
|
// reached the end of a page and the pager seeks to traverse over a new one.
|
||||||
|
// In order to do this, it needs to construct the next page's URL.
|
||||||
|
func (r RulePage) NextPageURL() (string, error) {
|
||||||
|
var s struct {
|
||||||
|
Links []gophercloud.Link `json:"firewall_rules_links"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return gophercloud.ExtractNextURL(s.Links)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty checks whether a RulePage struct is empty.
|
||||||
|
func (r RulePage) IsEmpty() (bool, error) {
|
||||||
|
is, err := ExtractRules(r)
|
||||||
|
return len(is) == 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractRules accepts a Page struct, specifically a RouterPage struct,
|
||||||
|
// and extracts the elements into a slice of Router structs. In other words,
|
||||||
|
// a generic collection is mapped into a relevant slice.
|
||||||
|
func ExtractRules(r pagination.Page) ([]Rule, error) {
|
||||||
|
var s struct {
|
||||||
|
Rules []Rule `json:"firewall_rules"`
|
||||||
|
}
|
||||||
|
err := (r.(RulePage)).ExtractInto(&s)
|
||||||
|
return s.Rules, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type commonResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract is a function that accepts a result and extracts a firewall rule.
|
||||||
|
func (r commonResult) Extract() (*Rule, error) {
|
||||||
|
var s struct {
|
||||||
|
Rule *Rule `json:"firewall_rule"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return s.Rule, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResult represents the result of a get operation.
|
||||||
|
type GetResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateResult represents the result of an update operation.
|
||||||
|
type UpdateResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteResult represents the result of a delete operation.
|
||||||
|
type DeleteResult struct {
|
||||||
|
gophercloud.ErrResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateResult represents the result of a create operation.
|
||||||
|
type CreateResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
16
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/rules/urls.go
generated
vendored
Normal file
16
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/rules/urls.go
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package rules
|
||||||
|
|
||||||
|
import "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
const (
|
||||||
|
rootPath = "fw"
|
||||||
|
resourcePath = "firewall_rules"
|
||||||
|
)
|
||||||
|
|
||||||
|
func rootURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return c.ServiceURL(rootPath, resourcePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return c.ServiceURL(rootPath, resourcePath, id)
|
||||||
|
}
|
145
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips/requests.go
generated
vendored
Normal file
145
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
package floatingips
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ListOpts allows the filtering and sorting of paginated collections through
|
||||||
|
// the API. Filtering is achieved by passing in struct field values that map to
|
||||||
|
// the floating IP attributes you want to see returned. SortKey allows you to
|
||||||
|
// sort by a particular network attribute. SortDir sets the direction, and is
|
||||||
|
// either `asc' or `desc'. Marker and Limit are used for pagination.
|
||||||
|
type ListOpts struct {
|
||||||
|
ID string `q:"id"`
|
||||||
|
FloatingNetworkID string `q:"floating_network_id"`
|
||||||
|
PortID string `q:"port_id"`
|
||||||
|
FixedIP string `q:"fixed_ip_address"`
|
||||||
|
FloatingIP string `q:"floating_ip_address"`
|
||||||
|
TenantID string `q:"tenant_id"`
|
||||||
|
Limit int `q:"limit"`
|
||||||
|
Marker string `q:"marker"`
|
||||||
|
SortKey string `q:"sort_key"`
|
||||||
|
SortDir string `q:"sort_dir"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// List returns a Pager which allows you to iterate over a collection of
|
||||||
|
// floating IP resources. It accepts a ListOpts struct, which allows you to
|
||||||
|
// filter and sort the returned collection for greater efficiency.
|
||||||
|
func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
|
||||||
|
q, err := gophercloud.BuildQueryString(&opts)
|
||||||
|
if err != nil {
|
||||||
|
return pagination.Pager{Err: err}
|
||||||
|
}
|
||||||
|
u := rootURL(c) + q.String()
|
||||||
|
return pagination.NewPager(c, u, func(r pagination.PageResult) pagination.Page {
|
||||||
|
return FloatingIPPage{pagination.LinkedPageBase{PageResult: r}}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOptsBuilder is the interface type must satisfy to be used as Create
|
||||||
|
// options.
|
||||||
|
type CreateOptsBuilder interface {
|
||||||
|
ToFloatingIPCreateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOpts contains all the values needed to create a new floating IP
|
||||||
|
// resource. The only required fields are FloatingNetworkID and PortID which
|
||||||
|
// refer to the external network and internal port respectively.
|
||||||
|
type CreateOpts struct {
|
||||||
|
FloatingNetworkID string `json:"floating_network_id" required:"true"`
|
||||||
|
FloatingIP string `json:"floating_ip_address,omitempty"`
|
||||||
|
PortID string `json:"port_id,omitempty"`
|
||||||
|
FixedIP string `json:"fixed_ip_address,omitempty"`
|
||||||
|
TenantID string `json:"tenant_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToFloatingIPCreateMap allows CreateOpts to satisfy the CreateOptsBuilder
|
||||||
|
// interface
|
||||||
|
func (opts CreateOpts) ToFloatingIPCreateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "floatingip")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create accepts a CreateOpts struct and uses the values provided to create a
|
||||||
|
// new floating IP resource. You can create floating IPs on external networks
|
||||||
|
// only. If you provide a FloatingNetworkID which refers to a network that is
|
||||||
|
// not external (i.e. its `router:external' attribute is False), the operation
|
||||||
|
// will fail and return a 400 error.
|
||||||
|
//
|
||||||
|
// If you do not specify a FloatingIP address value, the operation will
|
||||||
|
// automatically allocate an available address for the new resource. If you do
|
||||||
|
// choose to specify one, it must fall within the subnet range for the external
|
||||||
|
// network - otherwise the operation returns a 400 error. If the FloatingIP
|
||||||
|
// address is already in use, the operation returns a 409 error code.
|
||||||
|
//
|
||||||
|
// You can associate the new resource with an internal port by using the PortID
|
||||||
|
// field. If you specify a PortID that is not valid, the operation will fail and
|
||||||
|
// return 404 error code.
|
||||||
|
//
|
||||||
|
// You must also configure an IP address for the port associated with the PortID
|
||||||
|
// you have provided - this is what the FixedIP refers to: an IP fixed to a port.
|
||||||
|
// Because a port might be associated with multiple IP addresses, you can use
|
||||||
|
// the FixedIP field to associate a particular IP address rather than have the
|
||||||
|
// API assume for you. If you specify an IP address that is not valid, the
|
||||||
|
// operation will fail and return a 400 error code. If the PortID and FixedIP
|
||||||
|
// are already associated with another resource, the operation will fail and
|
||||||
|
// returns a 409 error code.
|
||||||
|
func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
|
||||||
|
b, err := opts.ToFloatingIPCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = c.Post(rootURL(c), b, &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get retrieves a particular floating IP resource based on its unique ID.
|
||||||
|
func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
|
||||||
|
_, r.Err = c.Get(resourceURL(c, id), &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateOptsBuilder is the interface type must satisfy to be used as Update
|
||||||
|
// options.
|
||||||
|
type UpdateOptsBuilder interface {
|
||||||
|
ToFloatingIPUpdateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateOpts contains the values used when updating a floating IP resource. The
|
||||||
|
// only value that can be updated is which internal port the floating IP is
|
||||||
|
// linked to. To associate the floating IP with a new internal port, provide its
|
||||||
|
// ID. To disassociate the floating IP from all ports, provide an empty string.
|
||||||
|
type UpdateOpts struct {
|
||||||
|
PortID *string `json:"port_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToFloatingIPUpdateMap allows UpdateOpts to satisfy the UpdateOptsBuilder
|
||||||
|
// interface
|
||||||
|
func (opts UpdateOpts) ToFloatingIPUpdateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "floatingip")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update allows floating IP resources to be updated. Currently, the only way to
|
||||||
|
// "update" a floating IP is to associate it with a new internal port, or
|
||||||
|
// disassociated it from all ports. See UpdateOpts for instructions of how to
|
||||||
|
// do this.
|
||||||
|
func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) {
|
||||||
|
b, err := opts.ToFloatingIPUpdateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = c.Put(resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete will permanently delete a particular floating IP resource. Please
|
||||||
|
// ensure this is what you want - you can also disassociate the IP from existing
|
||||||
|
// internal ports.
|
||||||
|
func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) {
|
||||||
|
_, r.Err = c.Delete(resourceURL(c, id), nil)
|
||||||
|
return
|
||||||
|
}
|
107
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips/results.go
generated
vendored
Normal file
107
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips/results.go
generated
vendored
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
package floatingips
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FloatingIP represents a floating IP resource. A floating IP is an external
|
||||||
|
// IP address that is mapped to an internal port and, optionally, a specific
|
||||||
|
// IP address on a private network. In other words, it enables access to an
|
||||||
|
// instance on a private network from an external network. For this reason,
|
||||||
|
// floating IPs can only be defined on networks where the `router:external'
|
||||||
|
// attribute (provided by the external network extension) is set to True.
|
||||||
|
type FloatingIP struct {
|
||||||
|
// Unique identifier for the floating IP instance.
|
||||||
|
ID string `json:"id"`
|
||||||
|
|
||||||
|
// UUID of the external network where the floating IP is to be created.
|
||||||
|
FloatingNetworkID string `json:"floating_network_id"`
|
||||||
|
|
||||||
|
// Address of the floating IP on the external network.
|
||||||
|
FloatingIP string `json:"floating_ip_address"`
|
||||||
|
|
||||||
|
// UUID of the port on an internal network that is associated with the floating IP.
|
||||||
|
PortID string `json:"port_id"`
|
||||||
|
|
||||||
|
// The specific IP address of the internal port which should be associated
|
||||||
|
// with the floating IP.
|
||||||
|
FixedIP string `json:"fixed_ip_address"`
|
||||||
|
|
||||||
|
// Owner of the floating IP. Only admin users can specify a tenant identifier
|
||||||
|
// other than its own.
|
||||||
|
TenantID string `json:"tenant_id"`
|
||||||
|
|
||||||
|
// The condition of the API resource.
|
||||||
|
Status string `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type commonResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract a result and extracts a FloatingIP resource.
|
||||||
|
func (r commonResult) Extract() (*FloatingIP, error) {
|
||||||
|
var s struct {
|
||||||
|
FloatingIP *FloatingIP `json:"floatingip"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return s.FloatingIP, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateResult represents the result of a create operation.
|
||||||
|
type CreateResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResult represents the result of a get operation.
|
||||||
|
type GetResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateResult represents the result of an update operation.
|
||||||
|
type UpdateResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteResult represents the result of an update operation.
|
||||||
|
type DeleteResult struct {
|
||||||
|
gophercloud.ErrResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// FloatingIPPage is the page returned by a pager when traversing over a
|
||||||
|
// collection of floating IPs.
|
||||||
|
type FloatingIPPage struct {
|
||||||
|
pagination.LinkedPageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// NextPageURL is invoked when a paginated collection of floating IPs has reached
|
||||||
|
// the end of a page and the pager seeks to traverse over a new one. In order
|
||||||
|
// to do this, it needs to construct the next page's URL.
|
||||||
|
func (r FloatingIPPage) NextPageURL() (string, error) {
|
||||||
|
var s struct {
|
||||||
|
Links []gophercloud.Link `json:"floatingips_links"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return gophercloud.ExtractNextURL(s.Links)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty checks whether a NetworkPage struct is empty.
|
||||||
|
func (r FloatingIPPage) IsEmpty() (bool, error) {
|
||||||
|
is, err := ExtractFloatingIPs(r)
|
||||||
|
return len(is) == 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractFloatingIPs accepts a Page struct, specifically a FloatingIPPage struct,
|
||||||
|
// and extracts the elements into a slice of FloatingIP structs. In other words,
|
||||||
|
// a generic collection is mapped into a relevant slice.
|
||||||
|
func ExtractFloatingIPs(r pagination.Page) ([]FloatingIP, error) {
|
||||||
|
var s struct {
|
||||||
|
FloatingIPs []FloatingIP `json:"floatingips"`
|
||||||
|
}
|
||||||
|
err := (r.(FloatingIPPage)).ExtractInto(&s)
|
||||||
|
return s.FloatingIPs, err
|
||||||
|
}
|
13
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips/urls.go
generated
vendored
Normal file
13
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips/urls.go
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package floatingips
|
||||||
|
|
||||||
|
import "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
const resourcePath = "floatingips"
|
||||||
|
|
||||||
|
func rootURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return c.ServiceURL(resourcePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return c.ServiceURL(resourcePath, id)
|
||||||
|
}
|
223
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers/requests.go
generated
vendored
Normal file
223
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,223 @@
|
||||||
|
package routers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ListOpts allows the filtering and sorting of paginated collections through
|
||||||
|
// the API. Filtering is achieved by passing in struct field values that map to
|
||||||
|
// the floating IP attributes you want to see returned. SortKey allows you to
|
||||||
|
// sort by a particular network attribute. SortDir sets the direction, and is
|
||||||
|
// either `asc' or `desc'. Marker and Limit are used for pagination.
|
||||||
|
type ListOpts struct {
|
||||||
|
ID string `q:"id"`
|
||||||
|
Name string `q:"name"`
|
||||||
|
AdminStateUp *bool `q:"admin_state_up"`
|
||||||
|
Distributed *bool `q:"distributed"`
|
||||||
|
Status string `q:"status"`
|
||||||
|
TenantID string `q:"tenant_id"`
|
||||||
|
Limit int `q:"limit"`
|
||||||
|
Marker string `q:"marker"`
|
||||||
|
SortKey string `q:"sort_key"`
|
||||||
|
SortDir string `q:"sort_dir"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// List returns a Pager which allows you to iterate over a collection of
|
||||||
|
// routers. It accepts a ListOpts struct, which allows you to filter and sort
|
||||||
|
// the returned collection for greater efficiency.
|
||||||
|
//
|
||||||
|
// Default policy settings return only those routers that are owned by the
|
||||||
|
// tenant who submits the request, unless an admin user submits the request.
|
||||||
|
func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
|
||||||
|
q, err := gophercloud.BuildQueryString(&opts)
|
||||||
|
if err != nil {
|
||||||
|
return pagination.Pager{Err: err}
|
||||||
|
}
|
||||||
|
u := rootURL(c) + q.String()
|
||||||
|
return pagination.NewPager(c, u, func(r pagination.PageResult) pagination.Page {
|
||||||
|
return RouterPage{pagination.LinkedPageBase{PageResult: r}}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOptsBuilder is the interface options structs have to satisfy in order
|
||||||
|
// to be used in the main Create operation in this package. Since many
|
||||||
|
// extensions decorate or modify the common logic, it is useful for them to
|
||||||
|
// satisfy a basic interface in order for them to be used.
|
||||||
|
type CreateOptsBuilder interface {
|
||||||
|
ToRouterCreateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOpts contains all the values needed to create a new router. There are
|
||||||
|
// no required values.
|
||||||
|
type CreateOpts struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
AdminStateUp *bool `json:"admin_state_up,omitempty"`
|
||||||
|
Distributed *bool `json:"distributed,omitempty"`
|
||||||
|
TenantID string `json:"tenant_id,omitempty"`
|
||||||
|
GatewayInfo *GatewayInfo `json:"external_gateway_info,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opts CreateOpts) ToRouterCreateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "router")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create accepts a CreateOpts struct and uses the values to create a new
|
||||||
|
// logical router. When it is created, the router does not have an internal
|
||||||
|
// interface - it is not associated to any subnet.
|
||||||
|
//
|
||||||
|
// You can optionally specify an external gateway for a router using the
|
||||||
|
// GatewayInfo struct. The external gateway for the router must be plugged into
|
||||||
|
// an external network (it is external if its `router:external' field is set to
|
||||||
|
// true).
|
||||||
|
func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
|
||||||
|
b, err := opts.ToRouterCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = c.Post(rootURL(c), b, &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get retrieves a particular router based on its unique ID.
|
||||||
|
func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
|
||||||
|
_, r.Err = c.Get(resourceURL(c, id), &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateOptsBuilder interface {
|
||||||
|
ToRouterUpdateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateOpts contains the values used when updating a router.
|
||||||
|
type UpdateOpts struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
AdminStateUp *bool `json:"admin_state_up,omitempty"`
|
||||||
|
Distributed *bool `json:"distributed,omitempty"`
|
||||||
|
GatewayInfo *GatewayInfo `json:"external_gateway_info,omitempty"`
|
||||||
|
Routes []Route `json:"routes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opts UpdateOpts) ToRouterUpdateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "router")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update allows routers to be updated. You can update the name, administrative
|
||||||
|
// state, and the external gateway. For more information about how to set the
|
||||||
|
// external gateway for a router, see Create. This operation does not enable
|
||||||
|
// the update of router interfaces. To do this, use the AddInterface and
|
||||||
|
// RemoveInterface functions.
|
||||||
|
func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) {
|
||||||
|
b, err := opts.ToRouterUpdateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = c.Put(resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete will permanently delete a particular router based on its unique ID.
|
||||||
|
func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) {
|
||||||
|
_, r.Err = c.Delete(resourceURL(c, id), nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddInterfaceOptsBuilder is what types must satisfy to be used as AddInterface
|
||||||
|
// options.
|
||||||
|
type AddInterfaceOptsBuilder interface {
|
||||||
|
ToRouterAddInterfaceMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddInterfaceOpts allow you to work with operations that either add
|
||||||
|
// an internal interface from a router.
|
||||||
|
type AddInterfaceOpts struct {
|
||||||
|
SubnetID string `json:"subnet_id,omitempty" xor:"PortID"`
|
||||||
|
PortID string `json:"port_id,omitempty" xor:"SubnetID"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToRouterAddInterfaceMap allows InterfaceOpts to satisfy the InterfaceOptsBuilder
|
||||||
|
// interface
|
||||||
|
func (opts AddInterfaceOpts) ToRouterAddInterfaceMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddInterface attaches a subnet to an internal router interface. You must
|
||||||
|
// specify either a SubnetID or PortID in the request body. If you specify both,
|
||||||
|
// the operation will fail and an error will be returned.
|
||||||
|
//
|
||||||
|
// If you specify a SubnetID, the gateway IP address for that particular subnet
|
||||||
|
// is used to create the router interface. Alternatively, if you specify a
|
||||||
|
// PortID, the IP address associated with the port is used to create the router
|
||||||
|
// interface.
|
||||||
|
//
|
||||||
|
// If you reference a port that is associated with multiple IP addresses, or
|
||||||
|
// if the port is associated with zero IP addresses, the operation will fail and
|
||||||
|
// a 400 Bad Request error will be returned.
|
||||||
|
//
|
||||||
|
// If you reference a port already in use, the operation will fail and a 409
|
||||||
|
// Conflict error will be returned.
|
||||||
|
//
|
||||||
|
// The PortID that is returned after using Extract() on the result of this
|
||||||
|
// operation can either be the same PortID passed in or, on the other hand, the
|
||||||
|
// identifier of a new port created by this operation. After the operation
|
||||||
|
// completes, the device ID of the port is set to the router ID, and the
|
||||||
|
// device owner attribute is set to `network:router_interface'.
|
||||||
|
func AddInterface(c *gophercloud.ServiceClient, id string, opts AddInterfaceOptsBuilder) (r InterfaceResult) {
|
||||||
|
b, err := opts.ToRouterAddInterfaceMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = c.Put(addInterfaceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveInterfaceOptsBuilder is what types must satisfy to be used as RemoveInterface
|
||||||
|
// options.
|
||||||
|
type RemoveInterfaceOptsBuilder interface {
|
||||||
|
ToRouterRemoveInterfaceMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveInterfaceOpts allow you to work with operations that either add or remote
|
||||||
|
// an internal interface from a router.
|
||||||
|
type RemoveInterfaceOpts struct {
|
||||||
|
SubnetID string `json:"subnet_id,omitempty" or:"PortID"`
|
||||||
|
PortID string `json:"port_id,omitempty" or:"SubnetID"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToRouterRemoveInterfaceMap allows RemoveInterfaceOpts to satisfy the RemoveInterfaceOptsBuilder
|
||||||
|
// interface
|
||||||
|
func (opts RemoveInterfaceOpts) ToRouterRemoveInterfaceMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveInterface removes an internal router interface, which detaches a
|
||||||
|
// subnet from the router. You must specify either a SubnetID or PortID, since
|
||||||
|
// these values are used to identify the router interface to remove.
|
||||||
|
//
|
||||||
|
// Unlike AddInterface, you can also specify both a SubnetID and PortID. If you
|
||||||
|
// choose to specify both, the subnet ID must correspond to the subnet ID of
|
||||||
|
// the first IP address on the port specified by the port ID. Otherwise, the
|
||||||
|
// operation will fail and return a 409 Conflict error.
|
||||||
|
//
|
||||||
|
// If the router, subnet or port which are referenced do not exist or are not
|
||||||
|
// visible to you, the operation will fail and a 404 Not Found error will be
|
||||||
|
// returned. After this operation completes, the port connecting the router
|
||||||
|
// with the subnet is removed from the subnet for the network.
|
||||||
|
func RemoveInterface(c *gophercloud.ServiceClient, id string, opts RemoveInterfaceOptsBuilder) (r InterfaceResult) {
|
||||||
|
b, err := opts.ToRouterRemoveInterfaceMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = c.Put(removeInterfaceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
152
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers/results.go
generated
vendored
Normal file
152
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers/results.go
generated
vendored
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
package routers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GatewayInfo represents the information of an external gateway for any
|
||||||
|
// particular network router.
|
||||||
|
type GatewayInfo struct {
|
||||||
|
NetworkID string `json:"network_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Route is a possible route in a router.
|
||||||
|
type Route struct {
|
||||||
|
NextHop string `json:"nexthop"`
|
||||||
|
DestinationCIDR string `json:"destination"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Router represents a Neutron router. A router is a logical entity that
|
||||||
|
// forwards packets across internal subnets and NATs (network address
|
||||||
|
// translation) them on external networks through an appropriate gateway.
|
||||||
|
//
|
||||||
|
// A router has an interface for each subnet with which it is associated. By
|
||||||
|
// default, the IP address of such interface is the subnet's gateway IP. Also,
|
||||||
|
// whenever a router is associated with a subnet, a port for that router
|
||||||
|
// interface is added to the subnet's network.
|
||||||
|
type Router struct {
|
||||||
|
// Indicates whether or not a router is currently operational.
|
||||||
|
Status string `json:"status"`
|
||||||
|
|
||||||
|
// Information on external gateway for the router.
|
||||||
|
GatewayInfo GatewayInfo `json:"external_gateway_info"`
|
||||||
|
|
||||||
|
// Administrative state of the router.
|
||||||
|
AdminStateUp bool `json:"admin_state_up"`
|
||||||
|
|
||||||
|
// Whether router is disitrubted or not..
|
||||||
|
Distributed bool `json:"distributed"`
|
||||||
|
|
||||||
|
// Human readable name for the router. Does not have to be unique.
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// Unique identifier for the router.
|
||||||
|
ID string `json:"id"`
|
||||||
|
|
||||||
|
// Owner of the router. Only admin users can specify a tenant identifier
|
||||||
|
// other than its own.
|
||||||
|
TenantID string `json:"tenant_id"`
|
||||||
|
|
||||||
|
Routes []Route `json:"routes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RouterPage is the page returned by a pager when traversing over a
|
||||||
|
// collection of routers.
|
||||||
|
type RouterPage struct {
|
||||||
|
pagination.LinkedPageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// NextPageURL is invoked when a paginated collection of routers has reached
|
||||||
|
// the end of a page and the pager seeks to traverse over a new one. In order
|
||||||
|
// to do this, it needs to construct the next page's URL.
|
||||||
|
func (r RouterPage) NextPageURL() (string, error) {
|
||||||
|
var s struct {
|
||||||
|
Links []gophercloud.Link `json:"routers_links"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return gophercloud.ExtractNextURL(s.Links)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty checks whether a RouterPage struct is empty.
|
||||||
|
func (r RouterPage) IsEmpty() (bool, error) {
|
||||||
|
is, err := ExtractRouters(r)
|
||||||
|
return len(is) == 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractRouters accepts a Page struct, specifically a RouterPage struct,
|
||||||
|
// and extracts the elements into a slice of Router structs. In other words,
|
||||||
|
// a generic collection is mapped into a relevant slice.
|
||||||
|
func ExtractRouters(r pagination.Page) ([]Router, error) {
|
||||||
|
var s struct {
|
||||||
|
Routers []Router `json:"routers"`
|
||||||
|
}
|
||||||
|
err := (r.(RouterPage)).ExtractInto(&s)
|
||||||
|
return s.Routers, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type commonResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract is a function that accepts a result and extracts a router.
|
||||||
|
func (r commonResult) Extract() (*Router, error) {
|
||||||
|
var s struct {
|
||||||
|
Router *Router `json:"router"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return s.Router, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateResult represents the result of a create operation.
|
||||||
|
type CreateResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResult represents the result of a get operation.
|
||||||
|
type GetResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateResult represents the result of an update operation.
|
||||||
|
type UpdateResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteResult represents the result of a delete operation.
|
||||||
|
type DeleteResult struct {
|
||||||
|
gophercloud.ErrResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// InterfaceInfo represents information about a particular router interface. As
|
||||||
|
// mentioned above, in order for a router to forward to a subnet, it needs an
|
||||||
|
// interface.
|
||||||
|
type InterfaceInfo struct {
|
||||||
|
// The ID of the subnet which this interface is associated with.
|
||||||
|
SubnetID string `json:"subnet_id"`
|
||||||
|
|
||||||
|
// The ID of the port that is a part of the subnet.
|
||||||
|
PortID string `json:"port_id"`
|
||||||
|
|
||||||
|
// The UUID of the interface.
|
||||||
|
ID string `json:"id"`
|
||||||
|
|
||||||
|
// Owner of the interface.
|
||||||
|
TenantID string `json:"tenant_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// InterfaceResult represents the result of interface operations, such as
|
||||||
|
// AddInterface() and RemoveInterface().
|
||||||
|
type InterfaceResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract is a function that accepts a result and extracts an information struct.
|
||||||
|
func (r InterfaceResult) Extract() (*InterfaceInfo, error) {
|
||||||
|
var s InterfaceInfo
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return &s, err
|
||||||
|
}
|
21
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers/urls.go
generated
vendored
Normal file
21
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers/urls.go
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package routers
|
||||||
|
|
||||||
|
import "github.com/gophercloud/gophercloud"
|
||||||
|
|
||||||
|
const resourcePath = "routers"
|
||||||
|
|
||||||
|
func rootURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return c.ServiceURL(resourcePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return c.ServiceURL(resourcePath, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func addInterfaceURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return c.ServiceURL(resourcePath, id, "add_router_interface")
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeInterfaceURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return c.ServiceURL(resourcePath, id, "remove_router_interface")
|
||||||
|
}
|
115
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/members/requests.go
generated
vendored
Normal file
115
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/members/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
package members
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ListOpts allows the filtering and sorting of paginated collections through
|
||||||
|
// the API. Filtering is achieved by passing in struct field values that map to
|
||||||
|
// the floating IP attributes you want to see returned. SortKey allows you to
|
||||||
|
// sort by a particular network attribute. SortDir sets the direction, and is
|
||||||
|
// either `asc' or `desc'. Marker and Limit are used for pagination.
|
||||||
|
type ListOpts struct {
|
||||||
|
Status string `q:"status"`
|
||||||
|
Weight int `q:"weight"`
|
||||||
|
AdminStateUp *bool `q:"admin_state_up"`
|
||||||
|
TenantID string `q:"tenant_id"`
|
||||||
|
PoolID string `q:"pool_id"`
|
||||||
|
Address string `q:"address"`
|
||||||
|
ProtocolPort int `q:"protocol_port"`
|
||||||
|
ID string `q:"id"`
|
||||||
|
Limit int `q:"limit"`
|
||||||
|
Marker string `q:"marker"`
|
||||||
|
SortKey string `q:"sort_key"`
|
||||||
|
SortDir string `q:"sort_dir"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// List returns a Pager which allows you to iterate over a collection of
|
||||||
|
// pools. It accepts a ListOpts struct, which allows you to filter and sort
|
||||||
|
// the returned collection for greater efficiency.
|
||||||
|
//
|
||||||
|
// Default policy settings return only those pools that are owned by the
|
||||||
|
// tenant who submits the request, unless an admin user submits the request.
|
||||||
|
func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
|
||||||
|
q, err := gophercloud.BuildQueryString(&opts)
|
||||||
|
if err != nil {
|
||||||
|
return pagination.Pager{Err: err}
|
||||||
|
}
|
||||||
|
u := rootURL(c) + q.String()
|
||||||
|
return pagination.NewPager(c, u, func(r pagination.PageResult) pagination.Page {
|
||||||
|
return MemberPage{pagination.LinkedPageBase{PageResult: r}}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateOptsBuilder interface {
|
||||||
|
ToLBMemberCreateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOpts contains all the values needed to create a new pool member.
|
||||||
|
type CreateOpts struct {
|
||||||
|
// The IP address of the member.
|
||||||
|
Address string `json:"address" required:"true"`
|
||||||
|
// The port on which the application is hosted.
|
||||||
|
ProtocolPort int `json:"protocol_port" required:"true"`
|
||||||
|
// The pool to which this member will belong.
|
||||||
|
PoolID string `json:"pool_id" required:"true"`
|
||||||
|
// Only required if the caller has an admin role and wants to create a pool
|
||||||
|
// for another tenant.
|
||||||
|
TenantID string `json:"tenant_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opts CreateOpts) ToLBMemberCreateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "member")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create accepts a CreateOpts struct and uses the values to create a new
|
||||||
|
// load balancer pool member.
|
||||||
|
func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
|
||||||
|
b, err := opts.ToLBMemberCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = c.Post(rootURL(c), b, &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get retrieves a particular pool member based on its unique ID.
|
||||||
|
func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
|
||||||
|
_, r.Err = c.Get(resourceURL(c, id), &r.Body, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateOptsBuilder interface {
|
||||||
|
ToLBMemberUpdateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateOpts contains the values used when updating a pool member.
|
||||||
|
type UpdateOpts struct {
|
||||||
|
// The administrative state of the member, which is up (true) or down (false).
|
||||||
|
AdminStateUp *bool `json:"admin_state_up,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opts UpdateOpts) ToLBMemberUpdateMap() (map[string]interface{}, error) {
|
||||||
|
return gophercloud.BuildRequestBody(opts, "member")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update allows members to be updated.
|
||||||
|
func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) {
|
||||||
|
b, err := opts.ToLBMemberUpdateMap()
|
||||||
|
if err != nil {
|
||||||
|
r.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, r.Err = c.Put(resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||||
|
OkCodes: []int{200, 201, 202},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete will permanently delete a particular member based on its unique ID.
|
||||||
|
func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) {
|
||||||
|
_, r.Err = c.Delete(resourceURL(c, id), nil)
|
||||||
|
return
|
||||||
|
}
|
104
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/members/results.go
generated
vendored
Normal file
104
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/members/results.go
generated
vendored
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
package members
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gophercloud/gophercloud"
|
||||||
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Member represents the application running on a backend server.
|
||||||
|
type Member struct {
|
||||||
|
// The status of the member. Indicates whether the member is operational.
|
||||||
|
Status string
|
||||||
|
|
||||||
|
// Weight of member.
|
||||||
|
Weight int
|
||||||
|
|
||||||
|
// The administrative state of the member, which is up (true) or down (false).
|
||||||
|
AdminStateUp bool `json:"admin_state_up"`
|
||||||
|
|
||||||
|
// Owner of the member. Only an administrative user can specify a tenant ID
|
||||||
|
// other than its own.
|
||||||
|
TenantID string `json:"tenant_id"`
|
||||||
|
|
||||||
|
// The pool to which the member belongs.
|
||||||
|
PoolID string `json:"pool_id"`
|
||||||
|
|
||||||
|
// The IP address of the member.
|
||||||
|
Address string
|
||||||
|
|
||||||
|
// The port on which the application is hosted.
|
||||||
|
ProtocolPort int `json:"protocol_port"`
|
||||||
|
|
||||||
|
// The unique ID for the member.
|
||||||
|
ID string
|
||||||
|
}
|
||||||
|
|
||||||
|
// MemberPage is the page returned by a pager when traversing over a
|
||||||
|
// collection of pool members.
|
||||||
|
type MemberPage struct {
|
||||||
|
pagination.LinkedPageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// NextPageURL is invoked when a paginated collection of members has reached
|
||||||
|
// the end of a page and the pager seeks to traverse over a new one. In order
|
||||||
|
// to do this, it needs to construct the next page's URL.
|
||||||
|
func (r MemberPage) NextPageURL() (string, error) {
|
||||||
|
var s struct {
|
||||||
|
Links []gophercloud.Link `json:"members_links"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return gophercloud.ExtractNextURL(s.Links)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty checks whether a MemberPage struct is empty.
|
||||||
|
func (r MemberPage) IsEmpty() (bool, error) {
|
||||||
|
is, err := ExtractMembers(r)
|
||||||
|
return len(is) == 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractMembers accepts a Page struct, specifically a MemberPage struct,
|
||||||
|
// and extracts the elements into a slice of Member structs. In other words,
|
||||||
|
// a generic collection is mapped into a relevant slice.
|
||||||
|
func ExtractMembers(r pagination.Page) ([]Member, error) {
|
||||||
|
var s struct {
|
||||||
|
Members []Member `json:"members"`
|
||||||
|
}
|
||||||
|
err := (r.(MemberPage)).ExtractInto(&s)
|
||||||
|
return s.Members, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type commonResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract is a function that accepts a result and extracts a router.
|
||||||
|
func (r commonResult) Extract() (*Member, error) {
|
||||||
|
var s struct {
|
||||||
|
Member *Member `json:"member"`
|
||||||
|
}
|
||||||
|
err := r.ExtractInto(&s)
|
||||||
|
return s.Member, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateResult represents the result of a create operation.
|
||||||
|
type CreateResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResult represents the result of a get operation.
|
||||||
|
type GetResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateResult represents the result of an update operation.
|
||||||
|
type UpdateResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteResult represents the result of a delete operation.
|
||||||
|
type DeleteResult struct {
|
||||||
|
gophercloud.ErrResult
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue