Update storageos api dependency to 0.3.4

pull/6/head
Simon Croome 2018-02-06 13:28:00 +00:00
parent 68da45623f
commit 8d0ba4a978
37 changed files with 1414 additions and 1201 deletions

16
Godeps/Godeps.json generated
View File

@ -2592,11 +2592,23 @@
},
{
"ImportPath": "github.com/storageos/go-api",
"Rev": "74f9beb613cacf0cc282facc2e1550a3231e126f"
"Comment": "0.3.4",
"Rev": "3a4032328d99c1b43fbda3d85bd3c80fa06e1707"
},
{
"ImportPath": "github.com/storageos/go-api/netutil",
"Comment": "0.3.4",
"Rev": "3a4032328d99c1b43fbda3d85bd3c80fa06e1707"
},
{
"ImportPath": "github.com/storageos/go-api/serror",
"Comment": "0.3.4",
"Rev": "3a4032328d99c1b43fbda3d85bd3c80fa06e1707"
},
{
"ImportPath": "github.com/storageos/go-api/types",
"Rev": "74f9beb613cacf0cc282facc2e1550a3231e126f"
"Comment": "0.3.4",
"Rev": "3a4032328d99c1b43fbda3d85bd3c80fa06e1707"
},
{
"ImportPath": "github.com/stretchr/objx",

106
Godeps/LICENSES generated
View File

@ -82052,6 +82052,112 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================================================
================================================================================
= vendor/github.com/storageos/go-api/netutil licensed under: =
MIT License
Copyright (c) 2015-2017 StorageOS
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Copyright (c) 2013-2017, go-dockerclient authors
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
= vendor/github.com/storageos/go-api/LICENCE d8f852a0f38554263e64363f57b07fc4
================================================================================
================================================================================
= vendor/github.com/storageos/go-api/serror licensed under: =
MIT License
Copyright (c) 2015-2017 StorageOS
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Copyright (c) 2013-2017, go-dockerclient authors
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
= vendor/github.com/storageos/go-api/LICENCE d8f852a0f38554263e64363f57b07fc4
================================================================================
================================================================================
= vendor/github.com/storageos/go-api/types licensed under: =

View File

@ -6,61 +6,28 @@ go_library(
"client.go",
"controller.go",
"event.go",
"health.go",
"logger.go",
"login.go",
"namespace.go",
"policy.go",
"pool.go",
"rule.go",
"server_version.go",
"template.go",
"user.go",
"util.go",
"validation.go",
"volume.go",
] + select({
"@io_bazel_rules_go//go/platform:android": [
"client_unix.go",
],
"@io_bazel_rules_go//go/platform:darwin": [
"client_unix.go",
],
"@io_bazel_rules_go//go/platform:dragonfly": [
"client_unix.go",
],
"@io_bazel_rules_go//go/platform:freebsd": [
"client_unix.go",
],
"@io_bazel_rules_go//go/platform:linux": [
"client_unix.go",
],
"@io_bazel_rules_go//go/platform:nacl": [
"client_unix.go",
],
"@io_bazel_rules_go//go/platform:netbsd": [
"client_unix.go",
],
"@io_bazel_rules_go//go/platform:openbsd": [
"client_unix.go",
],
"@io_bazel_rules_go//go/platform:plan9": [
"client_unix.go",
],
"@io_bazel_rules_go//go/platform:solaris": [
"client_unix.go",
],
"@io_bazel_rules_go//go/platform:windows": [
"client_windows.go",
],
"//conditions:default": [],
}),
],
importpath = "github.com/storageos/go-api",
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/gorilla/websocket:go_default_library",
"//vendor/github.com/storageos/go-api/netutil:go_default_library",
"//vendor/github.com/storageos/go-api/serror:go_default_library",
"//vendor/github.com/storageos/go-api/types:go_default_library",
] + select({
"@io_bazel_rules_go//go/platform:windows": [
"//vendor/github.com/Microsoft/go-winio:go_default_library",
],
"//conditions:default": [],
}),
],
)
filegroup(
@ -74,6 +41,8 @@ filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//vendor/github.com/storageos/go-api/netutil:all-srcs",
"//vendor/github.com/storageos/go-api/serror:all-srcs",
"//vendor/github.com/storageos/go-api/types:all-srcs",
],
tags = ["automanaged"],

View File

@ -1,2 +1,5 @@
# StorageOS API client library
## Swagger Spec
Swagger specification for this repo is available in the [StorageOS public documentation](https://github.com/storageos/storageos.github.io/blob/master/swagger.yaml).

View File

@ -4,16 +4,16 @@ import (
"bytes"
"context"
"crypto/tls"
"crypto/x509"
"encoding/json"
"errors"
"fmt"
"github.com/storageos/go-api/netutil"
"github.com/storageos/go-api/serror"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
"os"
"reflect"
"strconv"
"strings"
@ -22,17 +22,11 @@ import (
const (
userAgent = "go-storageosclient"
unixProtocol = "unix"
namedPipeProtocol = "npipe"
DefaultVersionStr = "1"
DefaultVersion = 1
defaultNamespace = "default"
)
var (
// ErrInvalidEndpoint is returned when the endpoint is not a valid HTTP URL.
ErrInvalidEndpoint = errors.New("invalid endpoint")
// ErrConnectionRefused is returned when the client cannot connect to the given endpoint.
ErrConnectionRefused = errors.New("cannot connect to StorageOS API endpoint")
@ -42,8 +36,14 @@ var (
// ErrInvalidVersion is returned when a versioned client was requested but no version specified.
ErrInvalidVersion = errors.New("invalid version")
// DefaultPort is the default API port
DefaultPort = "5705"
// DataplaneHealthPort is the the port used by the dataplane health-check service
DataplaneHealthPort = "5704"
// DefaultHost is the default API host
DefaultHost = "tcp://localhost:5705"
DefaultHost = "tcp://localhost:" + DefaultPort
)
// APIVersion is an internal representation of a version of the Remote API.
@ -73,15 +73,13 @@ type Client struct {
SkipServerVersionCheck bool
HTTPClient *http.Client
TLSConfig *tls.Config
Dialer Dialer
endpoint string
endpointURL *url.URL
username string
secret string
requestedAPIVersion APIVersion
serverAPIVersion APIVersion
expectedAPIVersion APIVersion
nativeHTTPClient *http.Client
useTLS bool
}
// ClientVersion returns the API version of the client
@ -99,20 +97,8 @@ type Dialer interface {
// NewClient returns a Client instance ready for communication with the given
// server endpoint. It will use the latest remote API version available in the
// server.
func NewClient(endpoint string) (*Client, error) {
client, err := NewVersionedClient(endpoint, "")
if err != nil {
return nil, err
}
client.SkipServerVersionCheck = true
return client, nil
}
// NewTLSClient returns a Client instance ready for TLS communications with the given
// server endpoint, key and certificates . It will use the latest remote API version
// available in the server.
func NewTLSClient(endpoint string, cert, key, ca string) (*Client, error) {
client, err := NewVersionedTLSClient(endpoint, cert, key, ca, "")
func NewClient(nodes string) (*Client, error) {
client, err := NewVersionedClient(nodes, "")
if err != nil {
return nil, err
}
@ -122,17 +108,24 @@ func NewTLSClient(endpoint string, cert, key, ca string) (*Client, error) {
// NewVersionedClient returns a Client instance ready for communication with
// the given server endpoint, using a specific remote API version.
func NewVersionedClient(endpoint string, apiVersionString string) (*Client, error) {
u, err := parseEndpoint(endpoint, false)
func NewVersionedClient(nodestring string, apiVersionString string) (*Client, error) {
nodes := strings.Split(nodestring, ",")
d, err := netutil.NewMultiDialer(nodes, nil)
if err != nil {
return nil, err
}
var useTLS bool
if len(nodes) > 0 {
if u, err := url.Parse(nodes[0]); err != nil && u.Scheme == "https" {
useTLS = true
}
}
c := &Client{
HTTPClient: defaultClient(),
Dialer: &net.Dialer{},
endpoint: endpoint,
endpointURL: u,
HTTPClient: defaultClient(d),
useTLS: useTLS,
}
if apiVersionString != "" {
@ -143,85 +136,6 @@ func NewVersionedClient(endpoint string, apiVersionString string) (*Client, erro
c.requestedAPIVersion = APIVersion(version)
}
c.initializeNativeClient()
return c, nil
}
// NewVersionedTLSClient returns a Client instance ready for TLS communications with the givens
// server endpoint, key and certificates, using a specific remote API version.
func NewVersionedTLSClient(endpoint string, cert, key, ca, apiVersionString string) (*Client, error) {
var certPEMBlock []byte
var keyPEMBlock []byte
var caPEMCert []byte
if _, err := os.Stat(cert); !os.IsNotExist(err) {
certPEMBlock, err = ioutil.ReadFile(cert)
if err != nil {
return nil, err
}
}
if _, err := os.Stat(key); !os.IsNotExist(err) {
keyPEMBlock, err = ioutil.ReadFile(key)
if err != nil {
return nil, err
}
}
if _, err := os.Stat(ca); !os.IsNotExist(err) {
caPEMCert, err = ioutil.ReadFile(ca)
if err != nil {
return nil, err
}
}
return NewVersionedTLSClientFromBytes(endpoint, certPEMBlock, keyPEMBlock, caPEMCert, apiVersionString)
}
// NewVersionedTLSClientFromBytes returns a Client instance ready for TLS communications with the givens
// server endpoint, key and certificates (passed inline to the function as opposed to being
// read from a local file), using a specific remote API version.
func NewVersionedTLSClientFromBytes(endpoint string, certPEMBlock, keyPEMBlock, caPEMCert []byte, apiVersionString string) (*Client, error) {
u, err := parseEndpoint(endpoint, true)
if err != nil {
return nil, err
}
tlsConfig := &tls.Config{}
if certPEMBlock != nil && keyPEMBlock != nil {
tlsCert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock)
if err != nil {
return nil, err
}
tlsConfig.Certificates = []tls.Certificate{tlsCert}
}
if caPEMCert == nil {
tlsConfig.InsecureSkipVerify = true
} else {
caPool := x509.NewCertPool()
if !caPool.AppendCertsFromPEM(caPEMCert) {
return nil, errors.New("Could not add RootCA pem")
}
tlsConfig.RootCAs = caPool
}
tr := defaultTransport()
tr.TLSClientConfig = tlsConfig
if err != nil {
return nil, err
}
c := &Client{
HTTPClient: &http.Client{Transport: tr},
TLSConfig: tlsConfig,
Dialer: &net.Dialer{},
endpoint: endpoint,
endpointURL: u,
}
if apiVersionString != "" {
version, err := strconv.Atoi(apiVersionString)
if err != nil {
return nil, err
}
c.requestedAPIVersion = APIVersion(version)
}
c.initializeNativeClient()
return c, nil
}
@ -265,13 +179,6 @@ func (c *Client) checkAPIVersion() error {
return nil
}
// Endpoint returns the current endpoint. It's useful for getting the endpoint
// when using functions that get this data from the environment (like
// NewClientFromEnv.
func (c *Client) Endpoint() string {
return c.endpoint
}
// Ping pings the API server
//
// See https://goo.gl/wYfgY1 for more details.
@ -341,15 +248,7 @@ func (c *Client) do(method, urlpath string, doOptions doOptions) (*http.Response
}
httpClient := c.HTTPClient
protocol := c.endpointURL.Scheme
var u string
switch protocol {
case unixProtocol, namedPipeProtocol:
httpClient = c.nativeHTTPClient
u = c.getFakeNativeURL(urlpath, doOptions.unversioned)
default:
u = c.getAPIPath(urlpath, query, doOptions.unversioned)
}
u := c.getAPIPath(urlpath, query, doOptions.unversioned)
req, err := http.NewRequest(method, u, params)
if err != nil {
@ -376,6 +275,11 @@ func (c *Client) do(method, urlpath string, doOptions doOptions) (*http.Response
resp, err := httpClient.Do(req.WithContext(ctx))
if err != nil {
// If it is a custom error, return it. It probably knows more than us
if serror.IsStorageOSError(err) {
return nil, err
}
if strings.Contains(err.Error(), "connection refused") {
return nil, ErrConnectionRefused
}
@ -397,27 +301,18 @@ func chooseError(ctx context.Context, err error) error {
}
}
func (c *Client) getURL(path string, unversioned bool) string {
urlStr := strings.TrimRight(c.endpointURL.String(), "/")
path = strings.TrimLeft(path, "/")
if c.endpointURL.Scheme == unixProtocol || c.endpointURL.Scheme == namedPipeProtocol {
urlStr = ""
}
if unversioned {
return fmt.Sprintf("%s/%s", urlStr, path)
}
return fmt.Sprintf("%s/%s/%s", urlStr, c.requestedAPIVersion, path)
}
func (c *Client) getAPIPath(path string, query url.Values, unversioned bool) string {
var apiPath string
urlStr := strings.TrimRight(c.endpointURL.String(), "/")
path = strings.TrimLeft(path, "/")
if c.endpointURL.Scheme == unixProtocol || c.endpointURL.Scheme == namedPipeProtocol {
urlStr = ""
// The custom dialer contacts the hosts for us, making this hosname irrelevant
var urlStr string
if c.useTLS {
urlStr = "https://storageos-cluster"
} else {
urlStr = "http://storageos-cluster"
}
var apiPath string
path = strings.TrimLeft(path, "/")
if unversioned {
apiPath = fmt.Sprintf("%s/%s", urlStr, path)
} else {
@ -431,30 +326,6 @@ func (c *Client) getAPIPath(path string, query url.Values, unversioned bool) str
return apiPath
}
// getFakeNativeURL returns the URL needed to make an HTTP request over a UNIX
// domain socket to the given path.
func (c *Client) getFakeNativeURL(path string, unversioned bool) string {
u := *c.endpointURL // Copy.
// Override URL so that net/http will not complain.
u.Scheme = "http"
u.Host = "unix.sock" // Doesn't matter what this is - it's not used.
u.Path = ""
urlStr := strings.TrimRight(u.String(), "/")
path = strings.TrimLeft(path, "/")
if unversioned {
return fmt.Sprintf("%s/%s", urlStr, path)
}
return fmt.Sprintf("%s/%s/%s", urlStr, c.requestedAPIVersion, path)
}
type jsonMessage struct {
Status string `json:"status,omitempty"`
Progress string `json:"progress,omitempty"`
Error string `json:"error,omitempty"`
Stream string `json:"stream,omitempty"`
}
func queryString(opts interface{}) string {
if opts == nil {
return ""
@ -530,63 +401,50 @@ type Error struct {
}
func newError(resp *http.Response) *Error {
type jsonError struct {
Message string `json:"message"`
}
defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return &Error{Status: resp.StatusCode, Message: fmt.Sprintf("cannot read body, err: %v", err)}
}
return &Error{Status: resp.StatusCode, Message: string(data)}
// attempt to unmarshal the error if in json format
jerr := &jsonError{}
err = json.Unmarshal(data, jerr)
if err != nil {
return &Error{Status: resp.StatusCode, Message: string(data)} // Failed, just return string
}
return &Error{Status: resp.StatusCode, Message: jerr.Message}
}
func (e *Error) Error() string {
return fmt.Sprintf("API error (%d): %s", e.Status, e.Message)
}
var niceStatus string
func parseEndpoint(endpoint string, tls bool) (*url.URL, error) {
if endpoint != "" && !strings.Contains(endpoint, "://") {
endpoint = "tcp://" + endpoint
switch e.Status {
case 400, 500:
niceStatus = "Server failed to process your request. Was the data correct?"
case 401:
niceStatus = "Unauthenticated access of secure endpoint, please retry after authentication"
case 403:
niceStatus = "Forbidden request. Your user cannot perform this action"
case 404:
niceStatus = "Requested object not found. Does this item exist?"
}
u, err := url.Parse(endpoint)
if err != nil {
return nil, ErrInvalidEndpoint
}
if tls && u.Scheme != "unix" {
u.Scheme = "https"
}
switch u.Scheme {
case unixProtocol, namedPipeProtocol:
return u, nil
case "http", "https", "tcp":
_, port, err := net.SplitHostPort(u.Host)
if err != nil {
if e, ok := err.(*net.AddrError); ok {
if e.Err == "missing port in address" {
return u, nil
}
}
return nil, ErrInvalidEndpoint
}
number, err := strconv.ParseInt(port, 10, 64)
if err == nil && number > 0 && number < 65536 {
if u.Scheme == "tcp" {
if tls {
u.Scheme = "https"
} else {
u.Scheme = "http"
}
}
return u, nil
}
return nil, ErrInvalidEndpoint
default:
return nil, ErrInvalidEndpoint
if niceStatus != "" {
return fmt.Sprintf("API error (%s): %s", niceStatus, e.Message)
}
return fmt.Sprintf("API error (%s): %s", http.StatusText(e.Status), e.Message)
}
// defaultTransport returns a new http.Transport with the same default values
// as http.DefaultTransport, but with idle connections and keepalives disabled.
func defaultTransport() *http.Transport {
transport := defaultPooledTransport()
func defaultTransport(d Dialer) *http.Transport {
transport := defaultPooledTransport(d)
transport.DisableKeepAlives = true
transport.MaxIdleConnsPerHost = -1
return transport
@ -596,14 +454,11 @@ func defaultTransport() *http.Transport {
// values to http.DefaultTransport. Do not use this for transient transports as
// it can leak file descriptors over time. Only use this for transports that
// will be re-used for the same host(s).
func defaultPooledTransport() *http.Transport {
func defaultPooledTransport(d Dialer) *http.Transport {
transport := &http.Transport{
Proxy: http.ProxyFromEnvironment,
Dial: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).Dial,
TLSHandshakeTimeout: 10 * time.Second,
Proxy: http.ProxyFromEnvironment,
Dial: d.Dial,
TLSHandshakeTimeout: 5 * time.Second,
DisableKeepAlives: false,
MaxIdleConnsPerHost: 1,
}
@ -613,8 +468,16 @@ func defaultPooledTransport() *http.Transport {
// defaultClient returns a new http.Client with similar default values to
// http.Client, but with a non-shared Transport, idle connections disabled, and
// keepalives disabled.
func defaultClient() *http.Client {
// If a custom dialer is not provided, one with sane defaults will be created.
func defaultClient(d Dialer) *http.Client {
if d == nil {
d = &net.Dialer{
Timeout: 5 * time.Second,
KeepAlive: 5 * time.Second,
}
}
return &http.Client{
Transport: defaultTransport(),
Transport: defaultTransport(d),
}
}

View File

@ -1,25 +0,0 @@
// +build !windows
// Copyright 2016 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package storageos
import (
"net"
"net/http"
)
// initializeNativeClient initializes the native Unix domain socket client on
// Unix-style operating systems
func (c *Client) initializeNativeClient() {
if c.endpointURL.Scheme != unixProtocol {
return
}
socketPath := c.endpointURL.Path
tr := defaultTransport()
tr.Dial = func(network, addr string) (net.Conn, error) {
return c.Dialer.Dial(unixProtocol, socketPath)
}
c.nativeHTTPClient = &http.Client{Transport: tr}
}

View File

@ -1,40 +0,0 @@
// +build windows
// Copyright 2016 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package storageos
import (
"net"
"net/http"
"time"
"github.com/Microsoft/go-winio"
)
const namedPipeConnectTimeout = 2 * time.Second
type pipeDialer struct {
dialFunc func(network, addr string) (net.Conn, error)
}
func (p pipeDialer) Dial(network, address string) (net.Conn, error) {
return p.dialFunc(network, address)
}
// initializeNativeClient initializes the native Named Pipe client for Windows
func (c *Client) initializeNativeClient() {
if c.endpointURL.Scheme != namedPipeProtocol {
return
}
namedPipePath := c.endpointURL.Path
dialFunc := func(network, addr string) (net.Conn, error) {
timeout := namedPipeConnectTimeout
return winio.DialPipe(namedPipePath, &timeout)
}
tr := defaultTransport()
tr.Dial = dialFunc
c.Dialer = &pipeDialer{dialFunc}
c.nativeHTTPClient = &http.Client{Transport: tr}
}

View File

@ -26,7 +26,6 @@ func (c *Client) ControllerList(opts types.ListOptions) ([]*types.Controller, er
listOpts := doOptions{
fieldSelector: opts.FieldSelector,
labelSelector: opts.LabelSelector,
namespace: opts.Namespace,
context: opts.Context,
}

71
vendor/github.com/storageos/go-api/health.go generated vendored Normal file
View File

@ -0,0 +1,71 @@
package storageos
import (
"context"
"encoding/json"
"fmt"
"net/http"
"github.com/storageos/go-api/types"
)
var (
// HealthAPIPrefix is a partial path to the HTTP endpoint.
HealthAPIPrefix = "health"
)
// CPHealth returns the health of the control plane server at a given url.
func (c *Client) CPHealth(ctx context.Context, hostname string) (*types.CPHealthStatus, error) {
url := fmt.Sprintf("http://%s:%s/v1/%s", hostname, DefaultPort, HealthAPIPrefix)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
req.Header.Set("User-Agent", userAgent)
if c.username != "" && c.secret != "" {
req.SetBasicAuth(c.username, c.secret)
}
resp, err := c.HTTPClient.Do(req.WithContext(ctx))
if err != nil {
return nil, err
}
defer resp.Body.Close()
var status *types.CPHealthStatus
if err := json.NewDecoder(resp.Body).Decode(&status); err != nil {
return nil, err
}
return status, nil
}
// DPHealth returns the health of the data plane server at a given url.
func (c *Client) DPHealth(ctx context.Context, hostname string) (*types.DPHealthStatus, error) {
url := fmt.Sprintf("http://%s:%s/v1/%s", hostname, DataplaneHealthPort, HealthAPIPrefix)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
req.Header.Set("User-Agent", userAgent)
if c.username != "" && c.secret != "" {
req.SetBasicAuth(c.username, c.secret)
}
resp, err := c.HTTPClient.Do(req.WithContext(ctx))
if err != nil {
return nil, err
}
defer resp.Body.Close()
var status *types.DPHealthStatus
if err := json.NewDecoder(resp.Body).Decode(&status); err != nil {
return nil, err
}
return status, nil
}

62
vendor/github.com/storageos/go-api/logger.go generated vendored Normal file
View File

@ -0,0 +1,62 @@
package storageos
import (
"context"
"encoding/json"
"net/url"
"github.com/storageos/go-api/types"
)
var (
// LoggerAPIPrefix is a partial path to the HTTP endpoint.
LoggerAPIPrefix = "logs"
)
// LoggerConfig returns every cluster node's logging configuration.
func (c *Client) LoggerConfig(opts types.ListOptions) ([]*types.Logger, error) {
listOpts := doOptions{
fieldSelector: opts.FieldSelector,
labelSelector: opts.LabelSelector,
context: opts.Context,
}
if opts.LabelSelector != "" {
query := url.Values{}
query.Add("labelSelector", opts.LabelSelector)
listOpts.values = query
}
resp, err := c.do("GET", LoggerAPIPrefix+"/cluster/config", listOpts)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var loggers []*types.Logger
if err := json.NewDecoder(resp.Body).Decode(&loggers); err != nil {
return nil, err
}
return loggers, nil
}
// LoggerUpdate patches updates to logging configuration. Fields to update must
// be listed in the Fields value, and if a list of Nodes is given it will only
// apply to the nodes listed. Returns the updated configuration.
func (c *Client) LoggerUpdate(opts types.LoggerUpdateOptions) ([]*types.Logger, error) {
resp, err := c.do("PATCH", LoggerAPIPrefix+"/cluster/config", doOptions{
data: opts,
context: context.Background(),
})
if err != nil {
return nil, err
}
defer resp.Body.Close()
var loggers []*types.Logger
if err := json.NewDecoder(resp.Body).Decode(&loggers); err != nil {
return nil, err
}
return loggers, nil
}

46
vendor/github.com/storageos/go-api/login.go generated vendored Normal file
View File

@ -0,0 +1,46 @@
package storageos
import (
"encoding/json"
"errors"
)
var (
// LoginAPIPrefix is a partial path to the HTTP endpoint.
LoginAPIPrefix = "auth/login"
ErrLoginFailed = errors.New("Failed to get token from API endpoint")
)
// Login attemps to get a token from the API
func (c *Client) Login() (token string, err error) {
resp, err := c.do("POST", LoginAPIPrefix, doOptions{data: struct {
User string `json:"username"`
Pass string `json:"password"`
}{c.username, c.secret}})
if err != nil {
if _, ok := err.(*Error); ok {
return "", ErrLoginFailed
}
return "", err
}
if resp.StatusCode != 200 {
return "", ErrLoginFailed
}
unmarsh := struct {
Token string `json:"token"`
}{}
if err := json.NewDecoder(resp.Body).Decode(&unmarsh); err != nil {
return "", err
}
if unmarsh.Token == "" {
return "", ErrLoginFailed
}
return unmarsh.Token, nil
}

27
vendor/github.com/storageos/go-api/netutil/BUILD generated vendored Normal file
View File

@ -0,0 +1,27 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"errors.go",
"multidialer.go",
"parsers.go",
],
importpath = "github.com/storageos/go-api/netutil",
visibility = ["//visibility:public"],
deps = ["//vendor/github.com/storageos/go-api/serror:go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

26
vendor/github.com/storageos/go-api/netutil/errors.go generated vendored Normal file
View File

@ -0,0 +1,26 @@
package netutil
import (
"errors"
"fmt"
"github.com/storageos/go-api/serror"
"strings"
)
func errAllFailed(addrs []string) error {
msg := fmt.Sprintf("failed to dial all known cluster members, (%s)", strings.Join(addrs, ","))
help := "ensure that the value of $STORAGEOS_HOST (or the -H flag) is correct, and that there are healthy StorageOS nodes in this cluster"
return serror.NewTypedStorageOSError(serror.APIUncontactable, nil, msg, help)
}
func newInvalidNodeError(err error) error {
msg := fmt.Sprintf("invalid node format: %s", err)
help := "please check the format of $STORAGEOS_HOST (or the -H flag) complies with the StorageOS JOIN format"
return serror.NewTypedStorageOSError(serror.InvalidHostConfig, err, msg, help)
}
var errNoAddresses = errors.New("the MultiDialer instance has not been initialised with client addresses")
var errUnsupportedScheme = errors.New("unsupported URL scheme")
var errInvalidPortNumber = errors.New("invalid port number")

View File

@ -0,0 +1,109 @@
package netutil
import (
"context"
"math/rand"
"net"
"time"
)
var DefaultDialPort = "5705"
func init() {
rand.Seed(time.Now().UnixNano())
}
// Dialer is an interface that matches *net.Dialer. The intention is to allow either the stdlib
// dialer or a custom implementation to be passed to the MultiDialer constructor. This also makes
// the component easier to test.
type Dialer interface {
DialContext(context.Context, string, string) (net.Conn, error)
}
// MultiDialer is a custom net Dialer (to be used in a net.Transport field) that attemps to dial
// out to any (potentialy many) of a set of pre-defined addresses. The intended use of this
// function is to extend the functionality of the stdlib http.Client to transparently support
// requests to any member of a given storageos cluster.
type MultiDialer struct {
Addresses []string
Dialer *net.Dialer
}
// NewMultiDialer returns a new MultiDialer instance, configured to dial out to the given set of
// nodes. Nodes can be provided using a URL format (e.g. http://google.com:80), or a host-port pair
// (e.g. localhost:4567).
//
// If a port number is omitted, the value of DefaultDialPort is used.
// Given hostnames are resolved to IP addresses, and IP addresses are used verbatim.
//
// If called with a non-nil dialer, the MultiDialer instance will use this for internall dial
// requests. If this value is nil, the function will initialise one with sane defaults.
func NewMultiDialer(nodes []string, dialer *net.Dialer) (*MultiDialer, error) {
// If a dialer is not provided, initialise one with sane defaults
if dialer == nil {
dialer = &net.Dialer{
Timeout: 5 * time.Second,
KeepAlive: 5 * time.Second,
}
}
addrs, err := addrsFromNodes(nodes)
if err != nil {
return nil, err
}
return &MultiDialer{
Addresses: addrs,
Dialer: dialer,
}, nil
}
// DialContext will dial each of the MultiDialer's internal addresses in a random order until one
// successfully returns a connection, it has run out of addresses (returning ErrAllFailed), or the
// given context has been closed.
//
// Due to the intrinsic behaviour of this function, any address passed to this function will be
// ignored.
func (m *MultiDialer) DialContext(ctx context.Context, network, ignoredAddress string) (net.Conn, error) {
if len(m.Addresses) == 0 {
return nil, newInvalidNodeError(errNoAddresses)
}
// Shuffle a copy of the addresses (for even load balancing)
addrs := make([]string, len(m.Addresses))
copy(addrs, m.Addresses)
// FisherYates shuffle algorithm
for i := len(addrs) - 1; i > 0; i-- {
j := rand.Intn(i + 1)
addrs[i], addrs[j] = addrs[j], addrs[i]
}
// Try to dial each of these addresses in turn, or return on closed context
for _, addr := range addrs {
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
// Create new child context for a single dial
dctx, cancel := context.WithTimeout(ctx, time.Second)
defer cancel()
conn, err := m.Dialer.DialContext(dctx, network, addr)
if err != nil {
continue
}
return conn, nil
}
}
// We failed to dail all of the addresses we have
return nil, errAllFailed(m.Addresses)
}
// Dial returns the result of a call to m.DialContext passing in the background context
func (m *MultiDialer) Dial(network, addr string) (net.Conn, error) {
return m.DialContext(context.Background(), network, addr)
}

142
vendor/github.com/storageos/go-api/netutil/parsers.go generated vendored Normal file
View File

@ -0,0 +1,142 @@
package netutil
import (
"net"
"net/url"
"strconv"
"strings"
)
// addrsFromNodes takes a list of node hosts and attempts to return a list of hosts in ip:port
// format along with any error encountered.
//
// The function accepts node hosts in URL, ip, ip:port, resolvable-name and resolvable-name:port
// formats and will append the default port value if needed.
func addrsFromNodes(nodes []string) ([]string, error) {
var addrs []string
for _, n := range nodes {
switch {
// Assume that the node is provided as a URL
case strings.Contains(n, "://"):
newAddrs, err := parseURL(n)
if err != nil {
return nil, newInvalidNodeError(err)
}
addrs = append(addrs, newAddrs...)
// Assume the node is in hostname:port or ip:port format
case strings.Contains(n, ":"):
newAddrs, err := parseHostPort(n)
if err != nil {
return nil, newInvalidNodeError(err)
}
addrs = append(addrs, newAddrs...)
// Assume hostname or ip
default:
newAddrs, err := parseHost(n)
if err != nil {
return nil, newInvalidNodeError(err)
}
addrs = append(addrs, newAddrs...)
}
}
return addrs, nil
}
func validPort(port string) bool {
intPort, err := strconv.Atoi(port)
return (err == nil) &&
(intPort > 0) &&
(intPort <= 65535)
}
// parseURL takes a valid URL and verifies that it is using a correct scheme, has a resolvable
// address (or is an IP) and has a valid port (or adds the default if the port is omitted). The
// function then returns a list of addresses in ip:port format along with any error encountered.
//
// The function may return multiple addresses depending on the dns answer received when resolving
// the host.
func parseURL(node string) ([]string, error) {
url, err := url.Parse(node)
if err != nil {
return nil, err
}
// Verify a valid scheme
switch url.Scheme {
case "tcp", "http", "https":
host, port, err := net.SplitHostPort(url.Host)
if err != nil {
// We could be here as there is no port, lets try one last time with default port added
host, port, err = net.SplitHostPort(url.Host + ":" + DefaultDialPort)
if err != nil {
return nil, err
}
}
if !validPort(port) {
return nil, errInvalidPortNumber
}
// LookupHost works for IP addr too
addrs, err := net.LookupHost(host)
if err != nil {
return nil, err
}
for i, a := range addrs {
addrs[i] = a + ":" + port
}
return addrs, nil
default:
return nil, errUnsupportedScheme
}
}
// parseHostPort takes a string in host:port format and checks it has a resolvable address (or is
// an IP) and a valid port (or adds the default if the port is omitted). The function then returns
// a list of addresses in ip:port format along with any error encountered.
//
// The function may return multiple addresses depending on the dns answer received when resolving
// the host.
func parseHostPort(node string) ([]string, error) {
host, port, err := net.SplitHostPort(node)
if err != nil {
return nil, err
}
if !validPort(port) {
return nil, errInvalidPortNumber
}
// LookupHost works for IP addr too
addrs, err := net.LookupHost(host)
if err != nil {
return nil, err
}
for i, a := range addrs {
addrs[i] = a + ":" + port
}
return addrs, nil
}
// parseHostPort takes a hostname string and checks it is resolvable to an address (or is already
// an IP) The function then returns a list of addresses in ip:port format (where port is the
// default port) along with any error encountered.
//
// The function may return multiple addresses depending on the dns answer received when resolving
// the host.
func parseHost(node string) ([]string, error) {
return parseHostPort(node + ":" + DefaultDialPort)
}

103
vendor/github.com/storageos/go-api/policy.go generated vendored Normal file
View File

@ -0,0 +1,103 @@
package storageos
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/storageos/go-api/types"
"net/http"
"net/url"
)
var (
// PolicyAPIPrefix is a partial path to the HTTP endpoint.
PolicyAPIPrefix = "policies"
// ErrNoSuchPolicy is the error returned when the policy does not exist.
ErrNoSuchPolicy = errors.New("no such policy")
)
// nopMarshaler is an alias to a []byte that implements json.Marshaler
// it bypasses the base64 encoded string representation that json will give byte slices.
// It should only be used to wrap []byte types containing pre-rendered valid json that will later
// (out of the caller's control) be run through json.Marshal
type nopMarshaler []byte
func (n *nopMarshaler) MarshalJSON() ([]byte, error) {
return *n, nil
}
// PolicyCreate creates a policy on the server.
func (c *Client) PolicyCreate(jsonl []byte, ctx context.Context) error {
nopm := nopMarshaler(jsonl)
_, err := c.do("POST", PolicyAPIPrefix, doOptions{
data: &nopm,
context: ctx,
headers: map[string]string{"Content-Type": "application/x-jsonlines"},
})
return err
}
// Policy returns a policy on the server by ID.
func (c *Client) Policy(id string) (*types.Policy, error) {
path := fmt.Sprintf("%s/%s", PolicyAPIPrefix, id)
resp, err := c.do("GET", path, doOptions{})
if err != nil {
if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
return nil, ErrNoSuchPolicy
}
return nil, err
}
defer resp.Body.Close()
var policy *types.Policy
if err := json.NewDecoder(resp.Body).Decode(&policy); err != nil {
return nil, err
}
return policy, nil
}
// PolicyList returns the list of policies on the server.
func (c *Client) PolicyList(opts types.ListOptions) (types.PolicySet, error) {
listOpts := doOptions{
fieldSelector: opts.FieldSelector,
labelSelector: opts.LabelSelector,
namespace: opts.Namespace,
context: opts.Context,
}
if opts.LabelSelector != "" {
query := url.Values{}
query.Add("labelSelector", opts.LabelSelector)
listOpts.values = query
}
resp, err := c.do("GET", PolicyAPIPrefix, listOpts)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var policies types.PolicySet
if err := json.NewDecoder(resp.Body).Decode(&policies); err != nil {
return nil, err
}
return policies, nil
}
// PolicyDelete deletes a policy on the server by ID.
func (c *Client) PolicyDelete(opts types.DeleteOptions) error {
resp, err := c.do("DELETE", PolicyAPIPrefix+"/"+opts.Name, doOptions{})
if err != nil {
if e, ok := err.(*Error); ok {
if e.Status == http.StatusNotFound {
return ErrNoSuchPolicy
}
}
return err
}
defer resp.Body.Close()
return nil
}

View File

@ -72,10 +72,15 @@ func (c *Client) Rule(namespace string, ref string) (*types.Rule, error) {
// RuleCreate creates a rule on the server and returns the new object.
func (c *Client) RuleCreate(opts types.RuleCreateOptions) (*types.Rule, error) {
resp, err := c.do("POST", RuleAPIPrefix, doOptions{
data: opts,
namespace: opts.Namespace,
context: opts.Context,
path, err := namespacedPath(opts.Namespace, RuleAPIPrefix)
if err != nil {
return nil, err
}
resp, err := c.do("POST", path, doOptions{
data: opts,
// namespace: opts.Namespace,
context: opts.Context,
})
if err != nil {
return nil, err

28
vendor/github.com/storageos/go-api/serror/BUILD generated vendored Normal file
View File

@ -0,0 +1,28 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"error_kind.go",
"kind_lookup_map.go",
"storageos_error.go",
"storageoserrorkind_string.go",
"typed_error.go",
],
importpath = "github.com/storageos/go-api/serror",
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,11 @@
package serror
//go:generate stringer -type=StorageOSErrorKind error_kind.go
type StorageOSErrorKind int
// Known error kinds
const (
UnknownError StorageOSErrorKind = iota
APIUncontactable
InvalidHostConfig
)

View File

@ -0,0 +1,37 @@
package serror
import (
"encoding/json"
"fmt"
"strings"
)
var kindLookupMap map[string]StorageOSErrorKind
func init() {
kindLookupMap = make(map[string]StorageOSErrorKind)
// Populate the lookup map with all the known constants
for i := StorageOSErrorKind(0); !strings.HasPrefix(i.String(), "StorageOSErrorKind("); i++ {
kindLookupMap[i.String()] = i
}
}
func (s *StorageOSErrorKind) UnmarshalJSON(b []byte) error {
str := ""
if err := json.Unmarshal(b, &str); err != nil {
return err
}
v, ok := kindLookupMap[str]
if !ok {
return fmt.Errorf("Failed to unmarshal ErrorKind %s", s)
}
*s = v
return nil
}
func (s *StorageOSErrorKind) MarshalJSON() ([]byte, error) {
return json.Marshal(s.String())
}

View File

@ -0,0 +1,34 @@
package serror
import (
"encoding/json"
)
type StorageOSError interface {
// embedding error provides compatibility with standard error handling code
error
// Encoding/decoding methods to help errors traverse API boundaries
json.Marshaler
json.Unmarshaler
Err() error // Returns the underlying error that caused this event
String() string // A short string representing the error (for logging etc)
Help() string // A larger string that should provide informative debug instruction to users
Kind() StorageOSErrorKind // A type representing a set of known error conditions, helpful to switch on
Extra() map[string]string // A container for error specific information
// TODO: should we include callstack traces here? We could have a debug mode for it.
}
func ErrorKind(err error) StorageOSErrorKind {
if serr, ok := err.(StorageOSError); ok {
return serr.Kind()
}
return UnknownError
}
func IsStorageOSError(err error) bool {
_, ok := err.(StorageOSError)
return ok
}

View File

@ -0,0 +1,16 @@
// Code generated by "stringer -type=StorageOSErrorKind error_kind.go"; DO NOT EDIT.
package serror
import "strconv"
const _StorageOSErrorKind_name = "UnknownErrorAPIUncontactableInvalidHostConfig"
var _StorageOSErrorKind_index = [...]uint8{0, 12, 28, 45}
func (i StorageOSErrorKind) String() string {
if i < 0 || i >= StorageOSErrorKind(len(_StorageOSErrorKind_index)-1) {
return "StorageOSErrorKind(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _StorageOSErrorKind_name[_StorageOSErrorKind_index[i]:_StorageOSErrorKind_index[i+1]]
}

View File

@ -0,0 +1,64 @@
package serror
import (
"encoding/json"
)
func NewTypedStorageOSError(kind StorageOSErrorKind, err error, msg string, help string) StorageOSError {
return &typedStorageOSError{
internal: &internal_TypedStorageOSError{
ErrorKind: &kind,
Cause: err,
ErrMessage: msg,
HelpMessage: help,
},
}
}
func NewUntypedStorageOSError(err error, msg string, help string) StorageOSError {
var kind StorageOSErrorKind = UnknownError
return &typedStorageOSError{
internal: &internal_TypedStorageOSError{
ErrorKind: &kind,
Cause: err,
ErrMessage: msg,
HelpMessage: help,
},
}
}
type internal_TypedStorageOSError struct {
ErrorKind *StorageOSErrorKind `json:"error_kind"`
Cause error `json:"caused_by"`
ErrMessage string `json:"error_message"`
HelpMessage string `json:"help_message"`
ExtraMap map[string]string `json:"extra"`
}
type typedStorageOSError struct {
internal *internal_TypedStorageOSError
}
func (t *typedStorageOSError) MarshalJSON() ([]byte, error) {
return json.Marshal(t.internal)
}
func (t *typedStorageOSError) UnmarshalJSON(d []byte) error {
internal := &internal_TypedStorageOSError{}
err := json.Unmarshal(d, internal)
if err != nil {
return err
}
t.internal = internal
return nil
}
func (t *typedStorageOSError) Error() string { return t.String() }
func (t *typedStorageOSError) Err() error { return t.internal.Cause }
func (t *typedStorageOSError) String() string { return t.internal.ErrMessage }
func (t *typedStorageOSError) Help() string { return t.internal.HelpMessage }
func (t *typedStorageOSError) Kind() StorageOSErrorKind { return *t.internal.ErrorKind }
func (t *typedStorageOSError) Extra() map[string]string { return t.internal.ExtraMap }

View File

@ -1,12 +0,0 @@
layout:
models:
- name: definition
source: asset:model
target: "{{ joinFilePath .Target .ModelPackage }}"
file_name: "{{ (snakize (pascalize .Name)) }}.go"
operations:
- name: handler
source: asset:serverOperation
target: "{{ joinFilePath .Target .APIPackage .Package }}"
file_name: "{{ (snakize (pascalize .Name)) }}.go"

View File

@ -1,854 +0,0 @@
# A Swagger 2.0 (a.k.a. OpenAPI) definition of the StorageOS API.
#
# This is used for generating API documentation and the types used by the
# client/server. See api/README.md for more information.
#
# Some style notes:
# - This file is used by ReDoc, which allows GitHub Flavored Markdown in
# descriptions.
# - There is no maximum line length, for ease of editing and pretty diffs.
# - operationIds are in the format "NounVerb", with a singular noun.
swagger: "2.0"
schemes:
- "http"
- "https"
produces:
- "application/json"
- "text/plain"
consumes:
- "application/json"
- "text/plain"
basePath: "/v1"
info:
title: "StorageOS API"
version: "0.7"
x-logo:
url: "http://storageos.wpengine.com/wp-content/uploads/2017/03/cropped-logo-1.png"
description: |
The StorageOS API is an HTTP API used for managing volumes and StorageOS services. It is the API that the StorageOS UI, CLI and platform integrations use to communicate with the StorageOS backend.
# Errors
The API uses standard HTTP status codes to indicate the success or failure of the API call. The body of the response will be JSON in the following format:
```
{
"message": "page not found"
}
```
# The tags on paths define the menu sections in the ReDoc documentation, so
# the usage of tags must make sense for that:
# - They should be singular, not plural.
# - There should not be too many tags, or the menu becomes unwieldy. For
# example, it is preferable to add a path to the "System" tag instead of
# creating a tag with a single path in it.
# - The order of tags in this list defines the order in the menu.
tags:
# Primary objects
- name: "Volume"
x-displayName: "Volumes"
description: |
Create and manage volumes.
- name: "Pool"
x-displayName: "Pools"
description: |
Create and manage distributed capacity pools.
definitions:
ErrorResponse:
description: "Represents an error."
type: "object"
required: ["message"]
properties:
message:
description: "The error message."
type: "string"
x-nullable: false
example:
message: "Something went wrong."
Deployment:
type: "object"
description: "Volume master or replica deployment details."
properties:
ID:
type: "string"
readOnly: true
Controller:
type: "string"
readOnly: true
Inode:
type: "integer"
format: "uint32"
readOnly: true
Status:
type: "string"
readOnly: true
Health:
type: "string"
readOnly: true
CreatedAt:
type: "string"
format: "datetime"
readOnly: true
VolumeCreateOptions:
type: "object"
description: "Parameters available for creating new volumes."
required: [Name]
properties:
Name:
description: "Volume name."
type: "string"
x-nullable: false
Description:
type: "string"
x-nullable: false
description: "Volume description."
Size:
type: "integer"
description: "Size in GB (if 0 or not specified, then defaults to 10 GB)."
x-nullable: false
Pool:
type: "string"
description: "Name of capacity pool to provision the volume in, or the name of the current pool."
Labels:
type: "object"
description: "User-defined key/value metadata."
x-nullable: false
additionalProperties:
type: "string"
VolumeUpdateOptions:
type: "object"
description: "Parameters available for updating existing volumes."
properties:
Description:
type: "string"
x-nullable: false
description: "Volume description."
Size:
type: "integer"
description: "Size in GB."
x-nullable: false
Labels:
type: "object"
description: "User-defined key/value metadata."
x-nullable: false
additionalProperties:
type: "string"
# VolumeMountOptions:
# type: "object"
# description: "Parameters available for mounting volumes."
# properties:
# ID:
# type: "string"
# x-nullable: false
# description: "Volume unique ID."
# Name:
# description: "Volume name."
# type: "string"
# x-nullable: false
# Namespace:
# description: "The object scope, such as for teams and projects."
# type: "string"
# x-nullable: false
# Client:
# type: "string"
# x-nullable: false
# description: "Hostname of the client performing the mount."
#
# VolumeUnmountOptions:
# type: "object"
# description: "Parameters available for unmounting volumes."
# properties:
# ID:
# type: "string"
# x-nullable: false
# description: "Volume unique ID."
# Name:
# description: "Volume name."
# type: "string"
# x-nullable: false
# Namespace:
# description: "The object scope, such as for teams and projects."
# type: "string"
# x-nullable: false
# Client:
# type: "string"
# x-nullable: false
# description: "Hostname of the client performing the unmount."
# ListOptions:
# type: "object"
# description: "Parameters for finding volumes."
# properties:
# LabelSelector:
# description: "A selector to restrict the list of returned objects by their labels. Defaults to everything."
# type: "string"
# FieldSelector:
# type: "string"
# description: "A selector to restrict the list of returned objects by their fields. Defaults to everything."
# TimeoutSeconds:
# type: "integer"
# description: "Timeout for the list call."
# Namespace:
# type: "string"
# description: "Object name and auth scope, such as for teams and projects"
Volume:
type: "object"
description: "A storage volume."
required: [Name, Size]
properties:
ID:
description: "Volume unique ID."
type: "string"
x-nullable: false
readOnly: true
Name:
description: "Volume name."
type: "string"
x-nullable: false
Description:
type: "string"
x-nullable: false
description: "Volume description."
Size:
type: integer
description: "Size in GB."
x-nullable: false
Pool:
type: "string"
description: "Name of capacity pool to provision the volume in, or the name of the current pool."
Labels:
type: "object"
description: "User-defined key/value metadata."
x-nullable: false
additionalProperties:
type: "string"
Master:
$ref: "#/definitions/Deployment"
Replicas:
type: "array"
description: "Volume deployment information for the replica volumes."
items:
$ref: "#/definitions/Deployment"
readOnly: true
Status:
type: "string"
description: "Short status, one of: pending, evaluating, deploying, active, unavailable, failed, updating, deleting."
readOnly: true
StatusMessage:
type: "string"
description: "Status message explaining current status."
readOnly: true
Health:
type: "string"
description: "Volume health, one of: healthy, degraded or dead."
readOnly: true
Inode:
type: "integer"
format: "uint32"
description: "Block device inode."
readOnly: true
Deleted:
type: "boolean"
description: "Flag indicating if the volume has been deleted and is waiting for scrubbing."
readOnly: true
Mounted:
type: "boolean"
description: "Flag indicating if the volume is mounted and in use."
readOnly: true
MountedBy:
type: "string"
description: "Reference to the node that has the volume mounted."
readOnly: true
Mountpoint:
type: "string"
description: "Mountpoint where the volume was mounted."
readOnly: true
MountedAt:
type: "string"
format: "dateTime"
description: "When the volume was mounted."
readOnly: true
CreatedBy:
type: "string"
description: "User that created the volume."
readOnly: true
CreatedAt:
type: "string"
format: "dateTime"
description: "When the volume was created."
readOnly: true
example:
Name: vol01
Size: 5
Labels:
com.example.some-label: "some-value"
com.example.some-other-label: "some-other-value"
PoolCreateOptions:
type: "object"
description: "Parameters available for creating new pools."
required: [Name]
properties:
Name:
description: "Pool name."
type: "string"
x-nullable: false
Description:
type: "string"
x-nullable: false
description: "Pool description."
Default:
type: "boolean"
description: "Default determines whether this pool is the default if a volume is provisioned without a pool specified. There can only be one default pool."
x-nullable: false
DefaultDriver:
type: "string"
x-nullable: false
description: "DefaultDriver specifies the storage driver to use by default if there are multiple drivers in the pool and no driver was specified in the provisioning request or assigned by rules. If no driver was specified and no default set, driver weight is used to determine the default."
ControllerNames:
type: "array"
description: "ControllerNames is a list of controller names that are participating in the storage pool."
items:
type: "string"
DriverNames:
type: "array"
description: "DriverNames is a list of backend storage drivers that are available in the storage pool."
items:
type: "string"
Active:
type: "boolean"
x-nullable: false
description: "Flag describing whether rule is active."
default: false
Labels:
type: "object"
description: "Labels define a list of labels that describe the pool."
additionalProperties:
type: "string"
Pool:
type: "object"
description: |
Pools are used to define distributed capacity that can be used to provision
volumes from. Typically, each server that makes storage available will be
added to one or more pools.
Capacity drivers are also added to the pool to determine which backend
storage driver to use. Currently this is limited to a single type of
driver per pool, but in the future we will allow multiple, allowing for
dynamic tiering and snapshots from one driver type to another.
required: [Name]
properties:
ID:
description: "Pool unique ID."
type: "string"
x-nullable: false
readOnly: true
Name:
description: "Pool name."
type: "string"
x-nullable: false
Description:
type: "string"
x-nullable: false
description: "Pool description."
Default:
type: "boolean"
x-nullable: false
description: |
Default determines whether this pool is the default if a volume is
provisioned without a pool specified. There can only be one default
pool.
DefaultDriver:
type: "string"
description: |
DefaultDriver specifies the storage driver to use by default if there
are multiple drivers in the pool and no driver was specified in the
provisioning request or assigned by rules. If no driver was specified
and no default set, driver weight is used to determine the default.
ControllerNames:
type: "array"
description: "ControllerNames is a list of controller names that are participating in the storage pool."
items:
type: "string"
DriverNames:
type: "array"
description: "DriverNames is a list of backend storage drivers that are available in the storage pool."
items:
type: "string"
DriverInstances:
$ref: "#/definitions/DriverInstances"
Active:
type: "boolean"
x-nullable: false
description: "Flag describing whether rule is active."
default: false
CapacityStats:
$ref: "#/definitions/CapacityStats"
Labels:
type: "object"
description: "Labels define a list of labels that describe the pool."
additionalProperties:
type: "string"
Rule:
type: "object"
description: "A policy rule."
required: [Name]
properties:
ID:
description: "Rule unique ID."
type: "string"
x-nullable: false
readOnly: true
Name:
description: "Rule name."
type: "string"
x-nullable: false
Description:
type: "string"
x-nullable: false
description: "Rule description."
Active:
type: "boolean"
x-nullable: false
description: "Flag describing whether rule is active."
default: false
Weight:
type: "integer"
x-nullable: false
description: |
"Weight is used to determine order during rule processing. Rules with heavier weights are processed later."
default: 0
Operator:
type: "string"
description: "Operator is used to compare objects or labels."
enum:
- "!"
- "="
- "=="
- "in"
- "!="
- "notin"
- "exists"
- "gt"
- "lt"
RuleAction:
type: "string"
description: "RuleAction controls whether the action is to add or remove a label from the matching object(s)."
enum:
- "add"
- "remove"
default: "add"
Selectors:
type: "object"
description: "Selectors defines the list of labels that should trigger a rule."
additionalProperties:
type: "string"
Labels:
type: "object"
description: "Labels define the list of labels that will be added or removed from the matching object(s).."
additionalProperties:
type: "string"
CapacityStats:
type: "object"
description: "CapacityStats is used to report capacity statistics on pools and controllers."
properties:
TotalCapacityBytes:
description: "TotalCapacityBytes is the object's total capacity in bytes."
type: "integer"
readOnly: true
AvailableCapacityBytes:
description: "AvailableCapacityBytes is the object's available capacity in bytes."
type: "integer"
readOnly: true
ProvisionedCapacityBytes:
description: "ProvisionedCapacityBytes is the object's provisioned capacity in bytes."
type: "integer"
readOnly: true
DriverInstances:
type: "object"
description: "DriverInstances shows the internal configuration and state of each driver on all the nodes in the pool. Data within DriverInstances can not be modified directly."
properties:
ID:
description: "Instance unique ID."
type: "string"
x-nullable: false
readOnly: true
Name:
description: "Instance name."
type: "string"
x-nullable: false
readOnly: true
Description:
description: "Instance description."
type: "string"
x-nullable: false
readOnly: true
Active:
description: "Flag describing whether the template is active."
type: "boolean"
x-nullable: false
readOnly: true
Config:
description: "Config is JSON struct that is passed directly to the driver. There is no specific format, and the driver is responsible for validation."
type: "object"
readOnly: true
additionalProperties:
type: "string"
Labels:
description: "Labels define a list of labels that describe the driver instance. These are inherited from the pool when the driver instance is created."
type: "object"
readOnly: true
additionalProperties:
type: "string"
ControllerName:
description: "ControllerName specifies the controller that this instance is running on."
type: "string"
x-nullable: false
readOnly: true
PoolID:
description: "PoolID refers to the pool that this driver instance relates to."
type: "string"
x-nullable: false
readOnly: true
DriverName:
description: "DriverName specifies which capacity driver this is an instance of."
type: "string"
x-nullable: false
readOnly: true
CapacityStats:
$ref: "#/definitions/CapacityStats"
parameters:
Name:
name: "name"
in: "path"
type: "string"
description: "Volume name or ID."
required: true
Namespace:
name: "namespace"
in: "path"
type: "string"
description: "Object name and auth scope, such as for teams and projects."
required: true
NamespaceQuery:
name: "namespace"
in: "query"
type: "string"
description: "Object name and auth scope, such as for teams and projects."
default: "default"
LabelSelector:
name: "labelSelector"
in: "query"
description: "A selector to restrict the list of returned objects by their labels. Defaults to everything."
type: "string"
FieldSelector:
name: "fieldSelector"
in: "query"
type: "string"
description: "A selector to restrict the list of returned objects by their fields. Defaults to everything."
TimeoutSeconds:
name: "timeoutSeconds"
in: "query"
type: "integer"
description: "Timeout for the list call."
paths:
/namespaces/{namespace}/volumes:
get:
summary: "List volumes"
description: "List of volumes that match the query."
produces:
- "application/json"
tags: ["Volume"]
parameters:
- name: "namespace"
in: "path"
required: true
description: "The object scope, such as for teams and projects."
type: "string"
- $ref: "#/parameters/LabelSelector"
- $ref: "#/parameters/FieldSelector"
- $ref: "#/parameters/TimeoutSeconds"
- $ref: "#/parameters/NamespaceQuery"
responses:
200:
description: "Success"
schema:
type: "array"
items:
$ref: "#/definitions/Volume"
500:
description: "Server error"
schema:
$ref: "#/definitions/ErrorResponse"
post:
summary: "Create volume"
description: "Provisions a new volume."
produces:
- "application/json"
tags: ["Volume"]
parameters:
- $ref: "#/parameters/Namespace"
- name: "VolumeCreateOptions"
in: "body"
schema:
$ref: "#/definitions/VolumeCreateOptions"
responses:
201:
description: "Volume created successfully"
schema:
$ref: "#/definitions/Volume"
401:
description: "Unauthorized"
409:
description: "Volume with name already exists"
500:
description: "Server error"
schema:
$ref: "#/definitions/ErrorResponse"
/namespaces/{namespace}/volumes/{name}:
get:
summary: "Get a volume"
description: "Gets a volume by name or ID. Returns to whole volume object."
produces:
- "application/json"
tags: ["Volume"]
parameters:
- $ref: "#/parameters/Name"
- $ref: "#/parameters/Namespace"
responses:
200:
description: "Success"
schema:
$ref: "#/definitions/Volume"
401:
description: "Unauthorized"
404:
description: "Not found"
schema:
$ref: "#/definitions/ErrorResponse"
407:
description: "Volume already exists"
500:
description: "Server error"
schema:
$ref: "#/definitions/ErrorResponse"
put:
summary: "Update volume"
description: "Updates an existing volume."
produces:
- "application/json"
tags: ["Volume"]
parameters:
- $ref: "#/parameters/Name"
- $ref: "#/parameters/Namespace"
- name: "VolumeUpdateOptions"
in: "body"
schema:
$ref: "#/definitions/VolumeUpdateOptions"
responses:
200:
description: "Success"
schema:
$ref: "#/definitions/Volume"
401:
description: "Unauthorized"
500:
description: "Server error"
schema:
$ref: "#/definitions/ErrorResponse"
delete:
summary: "Delete volume"
description: "Deletes a volume."
produces:
- "application/json"
tags: ["Volume"]
parameters:
- name: "namespace"
in: "path"
required: true
description: "The object scope, such as for teams and projects."
type: "string"
- name: "name"
in: "path"
required: true
description: "Volume name or ID."
type: "string"
responses:
200:
description: "Success"
401:
description: "Unauthorized"
407:
description: "Volume in use"
500:
description: "Server error"
schema:
$ref: "#/definitions/ErrorResponse"
/namespaces/{namespace}/volumes/{name}/mount:
post:
summary: "Mount volume"
description: "Updates the mount reference for the volume."
produces:
- "application/json"
tags: ["Volume"]
parameters:
- $ref: "#/parameters/Name"
- $ref: "#/parameters/Namespace"
- name: "client"
in: "body"
description: "Hostname of the client mounting the volume"
required: true
schema:
type: "string"
responses:
200:
description: "Success"
schema:
$ref: "#/definitions/Volume"
401:
description: "Unauthorized"
407:
description: "Volume already mounted"
500:
description: "Server error"
schema:
$ref: "#/definitions/ErrorResponse"
/namespaces/{namespace}/volumes/{name}/unmount:
post:
summary: "Mount volume"
description: "Updates the mount reference for the volume."
produces:
- "application/json"
tags: ["Volume"]
parameters:
- $ref: "#/parameters/Name"
- $ref: "#/parameters/Namespace"
- name: "client"
in: "body"
description: "Hostname of the client mounting the volume"
required: true
schema:
type: "string"
responses:
200:
description: "Success"
schema:
$ref: "#/definitions/Volume"
401:
description: "Unauthorized"
407:
description: "Volume not mounted"
500:
description: "Server error"
schema:
$ref: "#/definitions/ErrorResponse"
/pools:
get:
summary: "List pools"
description: "List of pools that match the query."
produces:
- "application/json"
tags: ["Pool"]
#parameters:
# - $ref: "#/parameters/LabelSelector"
# - $ref: "#/parameters/FieldSelector"
# - $ref: "#/parameters/TimeoutSeconds"
# - $ref: "#/parameters/NamespaceQuery"
responses:
200:
description: "Success"
schema:
type: "array"
items:
$ref: "#/definitions/Pool"
500:
description: "Server error"
schema:
$ref: "#/definitions/ErrorResponse"
post:
summary: "Create pool"
description: "Provisions a new pool."
produces:
- "application/json"
tags: ["Pool"]
parameters:
- name: "PoolCreateOptions"
in: "body"
schema:
$ref: "#/definitions/PoolCreateOptions"
responses:
201:
description: "Pool created successfully"
schema:
$ref: "#/definitions/Pool"
401:
description: "Unauthorized"
409:
description: "Pool with name already exists"
500:
description: "Server error"
schema:
$ref: "#/definitions/ErrorResponse"
/pools/{name}:
get:
summary: "Get a pool"
description: "Gets a pool by name or ID. Returns to whole pool object."
produces:
- "application/json"
tags: ["Pool"]
parameters:
- $ref: "#/parameters/Name"
responses:
200:
description: "Success"
schema:
$ref: "#/definitions/Pool"
401:
description: "Unauthorized"
404:
description: "Not found"
schema:
$ref: "#/definitions/ErrorResponse"
407:
description: "Pool already exists"
500:
description: "Server error"
schema:
$ref: "#/definitions/ErrorResponse"
delete:
summary: "Delete pool"
description: "Deletes a pool."
produces:
- "application/json"
tags: ["Pool"]
parameters:
- name: "name"
in: "path"
required: true
description: "Pool name or ID."
type: "string"
responses:
200:
description: "Success"
401:
description: "Unauthorized"
407:
description: "Pool in use"
500:
description: "Server error"
schema:
$ref: "#/definitions/ErrorResponse"

View File

@ -13,13 +13,17 @@ go_library(
"error_response.go",
"events.go",
"list_options.go",
"logger.go",
"namespace.go",
"node.go",
"operator.go",
"policy.go",
"pool.go",
"pool_create_options.go",
"rule.go",
"template.go",
"template_create_options.go",
"user.go",
"version.go",
"volume.go",
"volume_create_options.go",

View File

@ -41,6 +41,7 @@ type Controller struct {
Scheduler bool `json:"scheduler"`
Name string `json:"name"`
Address string `json:"address"`
DeviceDir string `json:"deviceDir"`
APIPort int `json:"apiPort"`
NatsPort int `json:"natsPort"`
NatsClusterPort int `json:"natsClusterPort"`
@ -59,6 +60,9 @@ type Controller struct {
VersionInfo map[string]VersionInfo `json:"versionInfo"`
Version string `json:"version"`
// Cordon true if in an unschedulable state
Cordon bool `json:"unschedulable"`
// high level stats that combine info from all driver instances
CapacityStats CapacityStats `json:"capacityStats"`
}

View File

@ -19,6 +19,9 @@ type ControllerUpdateOptions struct {
// Labels are user-defined key/value metadata.
Labels map[string]string `json:"labels"`
// Cordon sets the controler into an unschedulable state if true
Cordon bool `json:"unschedulable"`
// Context can be set with a timeout or can be used to cancel a request.
Context context.Context `json:"-"`
}

View File

@ -18,6 +18,10 @@ type Deployment struct {
// Read Only: true
Controller string `json:"controller"`
// Controller name
// Read Only: true
ControllerName string `json:"controllerName"`
// Health
// Read Only: true
Health string `json:"health"`

40
vendor/github.com/storageos/go-api/types/logger.go generated vendored Normal file
View File

@ -0,0 +1,40 @@
package types
import "context"
// Logger is the runtime configuration of the node's logging services.
// swagger:model Logger
type Logger struct {
// Node name
Node string `json:"node"`
// Log level
Level string `json:"level"`
// Log filter
Filter string `json:"filter"`
// Log filters by category
// Read Only: true
Categories map[string]string `json:"categories"`
}
// LoggerUpdateOptions are the available parameters for updating loggers.
type LoggerUpdateOptions struct {
// Log level
Level string `json:"level"`
// Log filter
Filter string `json:"filter"`
// List of nodes to update. All if not set.
Nodes []string `json:"nodes"`
// List of fields to update. Must be set.
Fields []string `json:"fields"`
// Context can be set with a timeout or can be used to cancel a request.
Context context.Context `json:"-"`
}

97
vendor/github.com/storageos/go-api/types/node.go generated vendored Normal file
View File

@ -0,0 +1,97 @@
package types
import (
"encoding/json"
)
type SubModuleStatus struct {
Status string `json:"status"`
UpdatedAt string `json:"updatedAt"`
ChangedAt string `json:"changedAt"`
Message string `json:"message"`
}
type NamedSubModuleStatus struct {
Name string
SubModuleStatus
}
type CPHealthStatus struct {
KV SubModuleStatus
KVWrite SubModuleStatus
NATS SubModuleStatus
Scheduler SubModuleStatus
}
func (c *CPHealthStatus) ToNamedSubmodules() []NamedSubModuleStatus {
return []NamedSubModuleStatus{
{Name: "nats", SubModuleStatus: c.NATS},
{Name: "kv", SubModuleStatus: c.KV},
{Name: "kv_write", SubModuleStatus: c.KVWrite},
{Name: "scheduler", SubModuleStatus: c.Scheduler},
}
}
func (c *CPHealthStatus) UnmarshalJSON(data []byte) error {
unmarsh := struct {
Submodules struct {
KV SubModuleStatus `json:"kv"`
KVWrite SubModuleStatus `json:"kv_write"`
NATS SubModuleStatus `json:"nats"`
Scheduler SubModuleStatus `json:"scheduler"`
} `json:"submodules"`
}{}
if err := json.Unmarshal(data, &unmarsh); err != nil {
return err
}
c.KV = unmarsh.Submodules.KV
c.KVWrite = unmarsh.Submodules.KVWrite
c.NATS = unmarsh.Submodules.NATS
c.Scheduler = unmarsh.Submodules.Scheduler
return nil
}
type DPHealthStatus struct {
DirectFSClient SubModuleStatus
DirectFSServer SubModuleStatus
Director SubModuleStatus
FSDriver SubModuleStatus
FS SubModuleStatus
}
func (d *DPHealthStatus) ToNamedSubmodules() []NamedSubModuleStatus {
return []NamedSubModuleStatus{
{Name: "dfs_client", SubModuleStatus: d.DirectFSClient},
{Name: "dfs_server", SubModuleStatus: d.DirectFSServer},
{Name: "director", SubModuleStatus: d.Director},
{Name: "fs_driver", SubModuleStatus: d.FSDriver},
{Name: "fs", SubModuleStatus: d.FS},
}
}
func (d *DPHealthStatus) UnmarshalJSON(data []byte) error {
unmarsh := struct {
Submodules struct {
DirectFSClient SubModuleStatus `json:"directfs-client"`
DirectFSServer SubModuleStatus `json:"directfs-server"`
Director SubModuleStatus `json:"director"`
FSDriver SubModuleStatus `json:"filesystem-driver"`
FS SubModuleStatus `json:"fs"`
} `json:"submodules"`
}{}
if err := json.Unmarshal(data, &unmarsh); err != nil {
return err
}
d.DirectFSClient = unmarsh.Submodules.DirectFSClient
d.DirectFSServer = unmarsh.Submodules.DirectFSServer
d.Director = unmarsh.Submodules.Director
d.FSDriver = unmarsh.Submodules.FSDriver
d.FS = unmarsh.Submodules.FS
return nil
}

45
vendor/github.com/storageos/go-api/types/policy.go generated vendored Normal file
View File

@ -0,0 +1,45 @@
package types
import (
"encoding/json"
)
type Policy struct {
Spec struct {
User string `json:"user,omitempty"`
Group string `json:"group,omitempty"`
Readonly bool `json:"readonly,omitempty"`
APIGroup string `json:"apiGroup,omitempty"`
Resource string `json:"resource,omitempty"`
Namespace string `json:"namespace,omitempty"`
NonResourcePath string `json:"nonResourcePath,omitempty"`
} `json:"spec"`
}
// PolicyWithId is used as an internal type to render table formated versions of the json response
type PolicyWithID struct {
Policy
ID string
}
// MarshalJSON returns a marshaled copy of the internal policy object, so it is still valid to use
// with the REST API
func (p *PolicyWithID) MarshalJSON() ([]byte, error) {
return json.Marshal(p.Policy)
}
// PolicySet is a representation of the data structure returned from the REST API
type PolicySet map[string]Policy
func (p PolicySet) GetPoliciesWithID() []*PolicyWithID {
rtn := make([]*PolicyWithID, 0, len(p))
for k, v := range p {
rtn = append(rtn, &PolicyWithID{
Policy: v,
ID: k,
})
}
return rtn
}

79
vendor/github.com/storageos/go-api/types/user.go generated vendored Normal file
View File

@ -0,0 +1,79 @@
package types
import (
"context"
"encoding/json"
"strings"
)
type User struct {
UUID string `json:"id"`
Username string `json:"username"`
Groups []string `json:"groups"`
Password string `json:"password,omitempty"`
Role string `json:"role"`
}
func (u *User) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
UUID string `json:"id"`
Username string `json:"username"`
Groups string `json:"groups"`
Password string `json:"password,omitempty"`
Role string `json:"role"`
}{
UUID: u.UUID,
Username: u.Username,
Groups: strings.Join(u.Groups, ","),
Password: u.Password,
Role: u.Role,
})
}
func (u *User) UnmarshalJSON(data []byte) error {
temp := &struct {
UUID string `json:"id"`
Username string `json:"username"`
Groups string `json:"groups"`
Password string `json:"password"`
Role string `json:"role"`
}{}
if err := json.Unmarshal(data, temp); err != nil {
return err
}
u.UUID = temp.UUID
u.Username = temp.Username
u.Password = temp.Password
u.Role = temp.Role
u.Groups = strings.Split(temp.Groups, ",")
return nil
}
type UserCreateOptions struct {
Username string `json:"username"`
Groups []string `json:"groups"`
Password string `json:"password"`
Role string `json:"role"`
// Context can be set with a timeout or can be used to cancel a request.
Context context.Context `json:"-"`
}
func (u UserCreateOptions) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
Username string `json:"username"`
Groups string `json:"groups"`
Password string `json:"password"`
Role string `json:"role"`
}{
Username: u.Username,
Groups: strings.Join(u.Groups, ","),
Password: u.Password,
Role: u.Role,
})
}

View File

@ -43,6 +43,9 @@ type Volume struct {
// Namespace is the object name and authentication scope, such as for teams and projects.
Namespace string `json:"namespace"`
// node selector (where volumes should land)
NodeSelector string `json:"nodeSelector"`
// Volume deployment information for the master volume.
// Read Only: true
Master *Deployment `json:"master,omitempty"`
@ -51,6 +54,9 @@ type Volume struct {
// Read Only: true
Mounted bool `json:"mounted"`
// MountDevice, where the device is located
MountDevice string `json:"mountDevice"`
// Mountpoint, where the volume is mounted
Mountpoint string `json:"mountpoint"`
@ -78,6 +84,10 @@ type Volume struct {
// Read Only: true
StatusMessage string `json:"statusMessage"`
// mkfs performed on new volumes
MkfsDone bool `json:"mkfsDone"`
MkfsDoneAt time.Time `json:"mkfsDoneAt"`
// When the volume was created.
// Read Only: true
CreatedAt time.Time `json:"createdAt"`

View File

@ -25,6 +25,9 @@ type VolumeCreateOptions struct {
// Namespace is the object scope, such as for teams and projects.
Namespace string `json:"namespace"`
// node selector (where volumes should land)
NodeSelector string `json:"nodeSelector"`
// Labels are user-defined key/value metadata.
Labels map[string]string `json:"labels"`

View File

@ -23,6 +23,9 @@ type VolumeUpdateOptions struct {
// Namespace is the object scope, such as for teams and projects.
Namespace string `json:"namespace"`
// node selector (where volumes should land)
NodeSelector string `json:"nodeSelector"`
// Labels are user-defined key/value metadata.
Labels map[string]string `json:"labels"`

119
vendor/github.com/storageos/go-api/user.go generated vendored Normal file
View File

@ -0,0 +1,119 @@
package storageos
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/url"
"github.com/storageos/go-api/types"
)
var (
// UserAPIPrefix is a partial path to the HTTP endpoint.
UserAPIPrefix = "users"
// ErrNoSuchUser is the error returned when the user does not exist.
ErrNoSuchUser = errors.New("no such user")
)
// UserList returns the list of available users.
func (c *Client) UserList(opts types.ListOptions) ([]*types.User, error) {
listOpts := doOptions{
fieldSelector: opts.FieldSelector,
labelSelector: opts.LabelSelector,
namespace: opts.Namespace,
context: opts.Context,
}
if opts.LabelSelector != "" {
query := url.Values{}
query.Add("labelSelector", opts.LabelSelector)
listOpts.values = query
}
resp, err := c.do("GET", UserAPIPrefix, listOpts)
if err != nil {
return nil, err
}
defer resp.Body.Close()
users := make([]*types.User, 0)
if err := json.NewDecoder(resp.Body).Decode(&users); err != nil {
return nil, err
}
return users, nil
}
// User returns a user by its username/id.
func (c *Client) User(username string) (*types.User, error) {
path := fmt.Sprintf("%s/%s", UserAPIPrefix, username)
resp, err := c.do("GET", path, doOptions{})
if err != nil {
if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
return nil, ErrNoSuchUser
}
return nil, err
}
defer resp.Body.Close()
var user *types.User
if err := json.NewDecoder(resp.Body).Decode(&user); err != nil {
return nil, err
}
return user, nil
}
// UserCreate creates a user on the server.
func (c *Client) UserCreate(opts types.UserCreateOptions) error {
_, err := c.do("POST", UserAPIPrefix, doOptions{
data: opts,
context: opts.Context,
})
return err
}
// UserUpdate updates a user on the server.
func (c *Client) UserUpdate(user *types.User, ctx context.Context) error {
var ref string
switch {
case user.UUID != "":
ref = user.UUID
case user.Username != "":
ref = user.Username
default:
return ErrNoSuchUser
}
path := fmt.Sprintf("%s/%s", UserAPIPrefix, ref)
resp, err := c.do("POST", path, doOptions{
data: user,
context: ctx,
})
if err != nil {
if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
return ErrNoSuchUser
}
return err
}
defer resp.Body.Close()
return nil
}
// UserDelete removes a user by its reference.
func (c *Client) UserDelete(opts types.DeleteOptions) error {
resp, err := c.do("DELETE", UserAPIPrefix+"/"+opts.Name, doOptions{})
if err != nil {
if e, ok := err.(*Error); ok {
if e.Status == http.StatusNotFound {
return ErrNoSuchUser
}
}
return err
}
defer resp.Body.Close()
return nil
}