Add StorageOS volume plugin
This commit is contained in:
24
vendor/github.com/storageos/go-api/.gitignore
generated
vendored
Normal file
24
vendor/github.com/storageos/go-api/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
47
vendor/github.com/storageos/go-api/BUILD
generated
vendored
Normal file
47
vendor/github.com/storageos/go-api/BUILD
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"client.go",
|
||||
"client_unix.go",
|
||||
"controller.go",
|
||||
"event.go",
|
||||
"namespace.go",
|
||||
"pool.go",
|
||||
"rule.go",
|
||||
"server_version.go",
|
||||
"template.go",
|
||||
"util.go",
|
||||
"validation.go",
|
||||
"volume.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//vendor/github.com/gorilla/websocket:go_default_library",
|
||||
"//vendor/github.com/storageos/go-api/types:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//vendor/github.com/storageos/go-api/types:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
45
vendor/github.com/storageos/go-api/LICENCE
generated
vendored
Normal file
45
vendor/github.com/storageos/go-api/LICENCE
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
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.
|
2
vendor/github.com/storageos/go-api/README.md
generated
vendored
Normal file
2
vendor/github.com/storageos/go-api/README.md
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# StorageOS API client library
|
||||
|
620
vendor/github.com/storageos/go-api/client.go
generated
vendored
Normal file
620
vendor/github.com/storageos/go-api/client.go
generated
vendored
Normal file
@@ -0,0 +1,620 @@
|
||||
package storageos
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
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")
|
||||
|
||||
// ErrInactivityTimeout is returned when a streamable call has been inactive for some time.
|
||||
ErrInactivityTimeout = errors.New("inactivity time exceeded timeout")
|
||||
|
||||
// ErrInvalidVersion is returned when a versioned client was requested but no version specified.
|
||||
ErrInvalidVersion = errors.New("invalid version")
|
||||
|
||||
// DefaultHost is the default API host
|
||||
DefaultHost = "tcp://localhost:5705"
|
||||
)
|
||||
|
||||
// APIVersion is an internal representation of a version of the Remote API.
|
||||
type APIVersion int
|
||||
|
||||
// NewAPIVersion returns an instance of APIVersion for the given string.
|
||||
//
|
||||
// The given string must be in the form <major>
|
||||
func NewAPIVersion(input string) (APIVersion, error) {
|
||||
if input == "" {
|
||||
return DefaultVersion, ErrInvalidVersion
|
||||
}
|
||||
version, err := strconv.Atoi(input)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("Unable to parse version %q", input)
|
||||
}
|
||||
return APIVersion(version), nil
|
||||
}
|
||||
|
||||
func (version APIVersion) String() string {
|
||||
return fmt.Sprintf("v%d", version)
|
||||
}
|
||||
|
||||
// Client is the basic type of this package. It provides methods for
|
||||
// interaction with the API.
|
||||
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
|
||||
}
|
||||
|
||||
// ClientVersion returns the API version of the client
|
||||
func (c *Client) ClientVersion() string {
|
||||
return DefaultVersionStr
|
||||
}
|
||||
|
||||
// Dialer is an interface that allows network connections to be dialed
|
||||
// (net.Dialer fulfills this interface) and named pipes (a shim using
|
||||
// winio.DialPipe)
|
||||
type Dialer interface {
|
||||
Dial(network, address string) (net.Conn, error)
|
||||
}
|
||||
|
||||
// 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, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client.SkipServerVersionCheck = true
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c := &Client{
|
||||
HTTPClient: defaultClient(),
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// SetAuth sets the API username and secret to be used for all API requests.
|
||||
// It should not be called concurrently with any other Client methods.
|
||||
func (c *Client) SetAuth(username string, secret string) {
|
||||
if username != "" {
|
||||
c.username = username
|
||||
}
|
||||
if secret != "" {
|
||||
c.secret = secret
|
||||
}
|
||||
}
|
||||
|
||||
// SetTimeout takes a timeout and applies it to both the HTTPClient and
|
||||
// nativeHTTPClient. It should not be called concurrently with any other Client
|
||||
// methods.
|
||||
func (c *Client) SetTimeout(t time.Duration) {
|
||||
if c.HTTPClient != nil {
|
||||
c.HTTPClient.Timeout = t
|
||||
}
|
||||
if c.nativeHTTPClient != nil {
|
||||
c.nativeHTTPClient.Timeout = t
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) checkAPIVersion() error {
|
||||
serverAPIVersionString, err := c.getServerAPIVersionString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.serverAPIVersion, err = NewAPIVersion(serverAPIVersionString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.requestedAPIVersion == 0 {
|
||||
c.expectedAPIVersion = c.serverAPIVersion
|
||||
} else {
|
||||
c.expectedAPIVersion = c.requestedAPIVersion
|
||||
}
|
||||
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.
|
||||
func (c *Client) Ping() error {
|
||||
urlpath := "/_ping"
|
||||
resp, err := c.do("GET", urlpath, doOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return newError(resp)
|
||||
}
|
||||
resp.Body.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) getServerAPIVersionString() (version string, err error) {
|
||||
v, err := c.ServerVersion(context.Background())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return v.APIVersion, nil
|
||||
}
|
||||
|
||||
type doOptions struct {
|
||||
data interface{}
|
||||
fieldSelector string
|
||||
labelSelector string
|
||||
namespace string
|
||||
forceJSON bool
|
||||
force bool
|
||||
values url.Values
|
||||
headers map[string]string
|
||||
unversioned bool
|
||||
context context.Context
|
||||
}
|
||||
|
||||
func (c *Client) do(method, urlpath string, doOptions doOptions) (*http.Response, error) {
|
||||
var params io.Reader
|
||||
if doOptions.data != nil || doOptions.forceJSON {
|
||||
buf, err := json.Marshal(doOptions.data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
params = bytes.NewBuffer(buf)
|
||||
}
|
||||
|
||||
// Prefix the path with the namespace if given. The caller should only set
|
||||
// the namespace if this is desired.
|
||||
if doOptions.namespace != "" {
|
||||
urlpath = "/" + NamespaceAPIPrefix + "/" + doOptions.namespace + "/" + urlpath
|
||||
}
|
||||
|
||||
if !c.SkipServerVersionCheck && !doOptions.unversioned {
|
||||
err := c.checkAPIVersion()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
query := url.Values{}
|
||||
if doOptions.values != nil {
|
||||
query = doOptions.values
|
||||
}
|
||||
if doOptions.force {
|
||||
query.Add("force", "1")
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, u, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("User-Agent", userAgent)
|
||||
if doOptions.data != nil {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
} else if method == "POST" {
|
||||
req.Header.Set("Content-Type", "plain/text")
|
||||
}
|
||||
if c.username != "" && c.secret != "" {
|
||||
req.SetBasicAuth(c.username, c.secret)
|
||||
}
|
||||
|
||||
for k, v := range doOptions.headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
|
||||
ctx := doOptions.context
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
|
||||
resp, err := httpClient.Do(req.WithContext(ctx))
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "connection refused") {
|
||||
return nil, ErrConnectionRefused
|
||||
}
|
||||
return nil, chooseError(ctx, err)
|
||||
}
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 400 {
|
||||
return nil, newError(resp)
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// if error in context, return that instead of generic http error
|
||||
func chooseError(ctx context.Context, err error) error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
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 = ""
|
||||
}
|
||||
if unversioned {
|
||||
apiPath = fmt.Sprintf("%s/%s", urlStr, path)
|
||||
} else {
|
||||
apiPath = fmt.Sprintf("%s/%s/%s", urlStr, c.requestedAPIVersion, path)
|
||||
}
|
||||
|
||||
if len(query) > 0 {
|
||||
apiPath = apiPath + "?" + query.Encode()
|
||||
}
|
||||
|
||||
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 ""
|
||||
}
|
||||
value := reflect.ValueOf(opts)
|
||||
if value.Kind() == reflect.Ptr {
|
||||
value = value.Elem()
|
||||
}
|
||||
if value.Kind() != reflect.Struct {
|
||||
return ""
|
||||
}
|
||||
items := url.Values(map[string][]string{})
|
||||
for i := 0; i < value.NumField(); i++ {
|
||||
field := value.Type().Field(i)
|
||||
if field.PkgPath != "" {
|
||||
continue
|
||||
}
|
||||
key := field.Tag.Get("qs")
|
||||
if key == "" {
|
||||
key = strings.ToLower(field.Name)
|
||||
} else if key == "-" {
|
||||
continue
|
||||
}
|
||||
addQueryStringValue(items, key, value.Field(i))
|
||||
}
|
||||
return items.Encode()
|
||||
}
|
||||
|
||||
func addQueryStringValue(items url.Values, key string, v reflect.Value) {
|
||||
switch v.Kind() {
|
||||
case reflect.Bool:
|
||||
if v.Bool() {
|
||||
items.Add(key, "1")
|
||||
}
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
if v.Int() > 0 {
|
||||
items.Add(key, strconv.FormatInt(v.Int(), 10))
|
||||
}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
if v.Float() > 0 {
|
||||
items.Add(key, strconv.FormatFloat(v.Float(), 'f', -1, 64))
|
||||
}
|
||||
case reflect.String:
|
||||
if v.String() != "" {
|
||||
items.Add(key, v.String())
|
||||
}
|
||||
case reflect.Ptr:
|
||||
if !v.IsNil() {
|
||||
if b, err := json.Marshal(v.Interface()); err == nil {
|
||||
items.Add(key, string(b))
|
||||
}
|
||||
}
|
||||
case reflect.Map:
|
||||
if len(v.MapKeys()) > 0 {
|
||||
if b, err := json.Marshal(v.Interface()); err == nil {
|
||||
items.Add(key, string(b))
|
||||
}
|
||||
}
|
||||
case reflect.Array, reflect.Slice:
|
||||
vLen := v.Len()
|
||||
if vLen > 0 {
|
||||
for i := 0; i < vLen; i++ {
|
||||
addQueryStringValue(items, key, v.Index(i))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Error represents failures in the API. It represents a failure from the API.
|
||||
type Error struct {
|
||||
Status int
|
||||
Message string
|
||||
}
|
||||
|
||||
func newError(resp *http.Response) *Error {
|
||||
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)}
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
return fmt.Sprintf("API error (%d): %s", e.Status, e.Message)
|
||||
}
|
||||
|
||||
func parseEndpoint(endpoint string, tls bool) (*url.URL, error) {
|
||||
if endpoint != "" && !strings.Contains(endpoint, "://") {
|
||||
endpoint = "tcp://" + endpoint
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// 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()
|
||||
transport.DisableKeepAlives = true
|
||||
transport.MaxIdleConnsPerHost = -1
|
||||
return transport
|
||||
}
|
||||
|
||||
// defaultPooledTransport returns a new http.Transport with similar default
|
||||
// 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 {
|
||||
transport := &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
DisableKeepAlives: false,
|
||||
MaxIdleConnsPerHost: 1,
|
||||
}
|
||||
return 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 {
|
||||
return &http.Client{
|
||||
Transport: defaultTransport(),
|
||||
}
|
||||
}
|
25
vendor/github.com/storageos/go-api/client_unix.go
generated
vendored
Normal file
25
vendor/github.com/storageos/go-api/client_unix.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// +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}
|
||||
}
|
40
vendor/github.com/storageos/go-api/client_windows.go
generated
vendored
Normal file
40
vendor/github.com/storageos/go-api/client_windows.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// +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}
|
||||
}
|
111
vendor/github.com/storageos/go-api/controller.go
generated
vendored
Normal file
111
vendor/github.com/storageos/go-api/controller.go
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
package storageos
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/storageos/go-api/types"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
// ControllerAPIPrefix is a partial path to the HTTP endpoint.
|
||||
ControllerAPIPrefix = "controllers"
|
||||
|
||||
// ErrNoSuchController is the error returned when the controller does not exist.
|
||||
ErrNoSuchController = errors.New("no such controller")
|
||||
|
||||
// ErrControllerInUse is the error returned when the controller requested to be removed is still in use.
|
||||
ErrControllerInUse = errors.New("controller in use and cannot be removed")
|
||||
)
|
||||
|
||||
// ControllerList returns the list of available controllers.
|
||||
func (c *Client) ControllerList(opts types.ListOptions) ([]*types.Controller, 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", ControllerAPIPrefix, listOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var controllers []*types.Controller
|
||||
if err := json.NewDecoder(resp.Body).Decode(&controllers); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return controllers, nil
|
||||
}
|
||||
|
||||
// Controller returns a controller by its reference.
|
||||
func (c *Client) Controller(ref string) (*types.Controller, error) {
|
||||
|
||||
resp, err := c.do("GET", ControllerAPIPrefix+"/"+ref, doOptions{})
|
||||
if err != nil {
|
||||
if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
|
||||
return nil, ErrNoSuchController
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var controller types.Controller
|
||||
if err := json.NewDecoder(resp.Body).Decode(&controller); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &controller, nil
|
||||
}
|
||||
|
||||
// ControllerUpdate updates a controller on the server.
|
||||
func (c *Client) ControllerUpdate(opts types.ControllerUpdateOptions) (*types.Controller, error) {
|
||||
ref := opts.Name
|
||||
if IsUUID(opts.ID) {
|
||||
ref = opts.ID
|
||||
}
|
||||
resp, err := c.do("PUT", ControllerAPIPrefix+"/"+ref, doOptions{
|
||||
data: opts,
|
||||
context: opts.Context,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var controller types.Controller
|
||||
if err := json.NewDecoder(resp.Body).Decode(&controller); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &controller, nil
|
||||
}
|
||||
|
||||
// ControllerDelete removes a controller by its reference.
|
||||
func (c *Client) ControllerDelete(opts types.DeleteOptions) error {
|
||||
deleteOpts := doOptions{
|
||||
namespace: opts.Namespace,
|
||||
force: opts.Force,
|
||||
context: opts.Context,
|
||||
}
|
||||
resp, err := c.do("DELETE", ControllerAPIPrefix+"/"+opts.Name, deleteOpts)
|
||||
if err != nil {
|
||||
if e, ok := err.(*Error); ok {
|
||||
if e.Status == http.StatusNotFound {
|
||||
return ErrNoSuchController
|
||||
}
|
||||
if e.Status == http.StatusConflict {
|
||||
return ErrControllerInUse
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
return nil
|
||||
}
|
189
vendor/github.com/storageos/go-api/event.go
generated
vendored
Normal file
189
vendor/github.com/storageos/go-api/event.go
generated
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
package storageos
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
|
||||
"github.com/storageos/go-api/types"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
// EventAPIPrefix is a partial path to the HTTP endpoint.
|
||||
EventAPIPrefix = "event"
|
||||
|
||||
// ErrNoSuchEvent is the error returned when the event does not exist.
|
||||
ErrNoSuchEvent = errors.New("no such event")
|
||||
)
|
||||
|
||||
// EventList returns the list of available events.
|
||||
func (c *Client) EventList(opts types.ListOptions) ([]*types.Event, error) {
|
||||
listOpts := doOptions{
|
||||
fieldSelector: opts.FieldSelector,
|
||||
labelSelector: opts.LabelSelector,
|
||||
context: opts.Context,
|
||||
}
|
||||
resp, err := c.do("GET", EventAPIPrefix, listOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var events []*types.Event
|
||||
if err := json.NewDecoder(resp.Body).Decode(&events); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return events, nil
|
||||
}
|
||||
|
||||
// Events returns a stream of events in the daemon. It's up to the caller to close the stream
|
||||
// by cancelling the context. Once the stream has been completely read an io.EOF error will
|
||||
// be sent over the error channel. If an error is sent all processing will be stopped. It's up
|
||||
// to the caller to reopen the stream in the event of an error by reinvoking this method.
|
||||
func (c *Client) Events(ctx context.Context, opts types.ListOptions) (<-chan types.Request, <-chan error) {
|
||||
|
||||
// listOpts := doOptions{
|
||||
// fieldSelector: opts.FieldSelector,
|
||||
// labelSelector: opts.LabelSelector,
|
||||
// context: ctx,
|
||||
// }
|
||||
|
||||
messages := make(chan types.Request)
|
||||
errs := make(chan error, 1)
|
||||
|
||||
// started := make(chan struct{})
|
||||
ws, _, err := websocket.DefaultDialer.Dial("ws://10.245.103.2:8000/v1/ws/event", nil)
|
||||
if err != nil {
|
||||
// close(started)
|
||||
// errs <- err
|
||||
log.Fatal(err)
|
||||
}
|
||||
// defer ws.Close()
|
||||
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer ws.Close()
|
||||
defer close(done)
|
||||
for {
|
||||
_, message, err := ws.ReadMessage()
|
||||
if err != nil {
|
||||
log.Println("read:", err)
|
||||
errs <- err
|
||||
return
|
||||
}
|
||||
// log.Printf("recv: %s", message)
|
||||
var request types.Request
|
||||
if err := json.Unmarshal(message, &request); err != nil {
|
||||
log.Printf("decode error: %s", message)
|
||||
errs <- err
|
||||
return
|
||||
}
|
||||
messages <- request
|
||||
}
|
||||
}()
|
||||
|
||||
ticker := time.NewTicker(time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case t := <-ticker.C:
|
||||
log.Printf("tick: %s\n", t.String())
|
||||
err := ws.WriteMessage(websocket.TextMessage, []byte(t.String()))
|
||||
if err != nil {
|
||||
log.Println("write:", err)
|
||||
return
|
||||
}
|
||||
case <-ctx.Done():
|
||||
log.Println("done")
|
||||
err := ws.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
|
||||
if err != nil {
|
||||
log.Println("write close:", err)
|
||||
return
|
||||
}
|
||||
errs <- ctx.Err()
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(time.Second):
|
||||
}
|
||||
ws.Close()
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// go func() {
|
||||
// defer ws.Close()
|
||||
// defer close(errs)
|
||||
//
|
||||
// // query, err := buildEventsQueryParams(cli.version, options)
|
||||
// // if err != nil {
|
||||
// // close(started)
|
||||
// // errs <- err
|
||||
// // return
|
||||
// // }
|
||||
//
|
||||
// // resp, err := cli.get(ctx, "/events", query, nil)
|
||||
//
|
||||
// // decoder := json.NewDecoder(resp.Body)
|
||||
//
|
||||
// close(started)
|
||||
// for {
|
||||
// select {
|
||||
// case <-ctx.Done():
|
||||
// log.Println("done")
|
||||
// errs <- ctx.Err()
|
||||
// return
|
||||
// default:
|
||||
// log.Println("default")
|
||||
// _, message, err := ws.ReadMessage()
|
||||
// if err != nil {
|
||||
// log.Println("read:", err)
|
||||
// return
|
||||
// }
|
||||
// log.Printf("recv: %s", message)
|
||||
// var event types.Event
|
||||
// if err := json.Unmarshal(message, &event); err != nil {
|
||||
// log.Printf("decode error: %s", message)
|
||||
// errs <- err
|
||||
// return
|
||||
// }
|
||||
// log.Printf("sent: %v", event)
|
||||
// messages <- event
|
||||
//
|
||||
// // select {
|
||||
// // case messages <- event:
|
||||
// // case <-ctx.Done():
|
||||
// // errs <- ctx.Err()
|
||||
// // return
|
||||
// // }
|
||||
// }
|
||||
// }
|
||||
// }()
|
||||
// <-started
|
||||
log.Println("returning")
|
||||
return messages, errs
|
||||
}
|
||||
|
||||
// Event returns a event by its reference.
|
||||
func (c *Client) Event(ref string) (*types.Event, error) {
|
||||
resp, err := c.do("GET", EventAPIPrefix+"/"+ref, doOptions{})
|
||||
if err != nil {
|
||||
if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
|
||||
return nil, ErrNoSuchEvent
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var event types.Event
|
||||
if err := json.NewDecoder(resp.Body).Decode(&event); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &event, nil
|
||||
}
|
125
vendor/github.com/storageos/go-api/namespace.go
generated
vendored
Normal file
125
vendor/github.com/storageos/go-api/namespace.go
generated
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
package storageos
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/storageos/go-api/types"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
// NamespaceAPIPrefix is a partial path to the HTTP endpoint.
|
||||
NamespaceAPIPrefix = "namespaces"
|
||||
|
||||
// ErrNoSuchNamespace is the error returned when the namespace does not exist.
|
||||
ErrNoSuchNamespace = errors.New("no such namespace")
|
||||
|
||||
// ErrNamespaceInUse is the error returned when the namespace requested to be removed is still in use.
|
||||
ErrNamespaceInUse = errors.New("namespace in use and cannot be removed")
|
||||
)
|
||||
|
||||
// NamespaceList returns the list of available namespaces.
|
||||
func (c *Client) NamespaceList(opts types.ListOptions) ([]*types.Namespace, 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", NamespaceAPIPrefix, listOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var namespaces []*types.Namespace
|
||||
if err := json.NewDecoder(resp.Body).Decode(&namespaces); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return namespaces, nil
|
||||
}
|
||||
|
||||
// Namespace returns a namespace by its reference.
|
||||
func (c *Client) Namespace(ref string) (*types.Namespace, error) {
|
||||
resp, err := c.do("GET", NamespaceAPIPrefix+"/"+ref, doOptions{})
|
||||
if err != nil {
|
||||
if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
|
||||
return nil, ErrNoSuchNamespace
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var namespace types.Namespace
|
||||
if err := json.NewDecoder(resp.Body).Decode(&namespace); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &namespace, nil
|
||||
}
|
||||
|
||||
// NamespaceCreate creates a namespace on the server and returns the new object.
|
||||
func (c *Client) NamespaceCreate(opts types.NamespaceCreateOptions) (*types.Namespace, error) {
|
||||
resp, err := c.do("POST", NamespaceAPIPrefix, doOptions{
|
||||
data: opts,
|
||||
context: opts.Context,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var namespace types.Namespace
|
||||
if err := json.NewDecoder(resp.Body).Decode(&namespace); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &namespace, nil
|
||||
}
|
||||
|
||||
// NamespaceUpdate updates a namespace on the server and returns the updated object.
|
||||
func (c *Client) NamespaceUpdate(opts types.NamespaceCreateOptions) (*types.Namespace, error) {
|
||||
resp, err := c.do("PUT", NamespaceAPIPrefix+"/"+opts.Name, doOptions{
|
||||
data: opts,
|
||||
context: opts.Context,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var namespace types.Namespace
|
||||
if err := json.NewDecoder(resp.Body).Decode(&namespace); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &namespace, nil
|
||||
}
|
||||
|
||||
// NamespaceDelete removes a namespace by its reference.
|
||||
func (c *Client) NamespaceDelete(opts types.DeleteOptions) error {
|
||||
deleteOpts := doOptions{
|
||||
force: opts.Force,
|
||||
context: opts.Context,
|
||||
}
|
||||
resp, err := c.do("DELETE", NamespaceAPIPrefix+"/"+opts.Name, deleteOpts)
|
||||
if err != nil {
|
||||
if e, ok := err.(*Error); ok {
|
||||
if e.Status == http.StatusNotFound {
|
||||
return ErrNoSuchNamespace
|
||||
}
|
||||
if e.Status == http.StatusConflict {
|
||||
return ErrNamespaceInUse
|
||||
}
|
||||
|
||||
// namespace can't be deleted yet, unless force is supplied
|
||||
if e.Status == http.StatusPreconditionFailed {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
return nil
|
||||
}
|
96
vendor/github.com/storageos/go-api/pool.go
generated
vendored
Normal file
96
vendor/github.com/storageos/go-api/pool.go
generated
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
package storageos
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/storageos/go-api/types"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
// PoolAPIPrefix is a partial path to the HTTP endpoint.
|
||||
PoolAPIPrefix = "pools"
|
||||
|
||||
// ErrNoSuchPool is the error returned when the pool does not exist.
|
||||
ErrNoSuchPool = errors.New("no such pool")
|
||||
|
||||
// ErrPoolInUse is the error returned when the pool requested to be removed is still in use.
|
||||
ErrPoolInUse = errors.New("pool in use and cannot be removed")
|
||||
)
|
||||
|
||||
// PoolList returns the list of available pools.
|
||||
func (c *Client) PoolList(opts types.ListOptions) ([]*types.Pool, error) {
|
||||
listOpts := doOptions{
|
||||
fieldSelector: opts.FieldSelector,
|
||||
labelSelector: opts.LabelSelector,
|
||||
namespace: opts.Namespace,
|
||||
context: opts.Context,
|
||||
}
|
||||
resp, err := c.do("GET", PoolAPIPrefix, listOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var pools []*types.Pool
|
||||
if err := json.NewDecoder(resp.Body).Decode(&pools); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pools, nil
|
||||
}
|
||||
|
||||
// PoolCreate creates a pool on the server and returns the new object.
|
||||
func (c *Client) PoolCreate(opts types.PoolCreateOptions) (*types.Pool, error) {
|
||||
resp, err := c.do("POST", PoolAPIPrefix, doOptions{
|
||||
data: opts,
|
||||
context: opts.Context,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var pool types.Pool
|
||||
if err := json.NewDecoder(resp.Body).Decode(&pool); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pool, nil
|
||||
}
|
||||
|
||||
// Pool returns a pool by its reference.
|
||||
func (c *Client) Pool(ref string) (*types.Pool, error) {
|
||||
resp, err := c.do("GET", PoolAPIPrefix+"/"+ref, doOptions{})
|
||||
if err != nil {
|
||||
if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
|
||||
return nil, ErrNoSuchPool
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var pool types.Pool
|
||||
if err := json.NewDecoder(resp.Body).Decode(&pool); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pool, nil
|
||||
}
|
||||
|
||||
// PoolDelete removes a pool by its reference.
|
||||
func (c *Client) PoolDelete(opts types.DeleteOptions) error {
|
||||
deleteOpts := doOptions{
|
||||
force: opts.Force,
|
||||
context: opts.Context,
|
||||
}
|
||||
resp, err := c.do("DELETE", PoolAPIPrefix+"/"+opts.Name, deleteOpts)
|
||||
if err != nil {
|
||||
if e, ok := err.(*Error); ok {
|
||||
if e.Status == http.StatusNotFound {
|
||||
return ErrNoSuchPool
|
||||
}
|
||||
if e.Status == http.StatusConflict {
|
||||
return ErrPoolInUse
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
return nil
|
||||
}
|
137
vendor/github.com/storageos/go-api/rule.go
generated
vendored
Normal file
137
vendor/github.com/storageos/go-api/rule.go
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
package storageos
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/storageos/go-api/types"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
// RuleAPIPrefix is a partial path to the HTTP endpoint.
|
||||
RuleAPIPrefix = "rules"
|
||||
|
||||
// ErrNoSuchRule is the error returned when the rule does not exist.
|
||||
ErrNoSuchRule = errors.New("no such rule")
|
||||
|
||||
// ErrRuleInUse is the error returned when the rule requested to be removed is still in use.
|
||||
ErrRuleInUse = errors.New("rule in use and cannot be removed")
|
||||
)
|
||||
|
||||
// RuleList returns the list of available rules.
|
||||
func (c *Client) RuleList(opts types.ListOptions) ([]*types.Rule, 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", RuleAPIPrefix, listOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var rules []*types.Rule
|
||||
if err := json.NewDecoder(resp.Body).Decode(&rules); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rules, nil
|
||||
}
|
||||
|
||||
// Rule returns a rule by its reference.
|
||||
func (c *Client) Rule(namespace string, ref string) (*types.Rule, error) {
|
||||
path, err := namespacedRefPath(namespace, RuleAPIPrefix, ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := c.do("GET", path, doOptions{})
|
||||
if err != nil {
|
||||
if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
|
||||
return nil, ErrNoSuchRule
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var rule types.Rule
|
||||
if err := json.NewDecoder(resp.Body).Decode(&rule); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &rule, nil
|
||||
}
|
||||
|
||||
// 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,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var rule types.Rule
|
||||
if err := json.NewDecoder(resp.Body).Decode(&rule); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &rule, nil
|
||||
}
|
||||
|
||||
// RuleUpdate updates a rule on the server.
|
||||
func (c *Client) RuleUpdate(opts types.RuleUpdateOptions) (*types.Rule, error) {
|
||||
ref := opts.Name
|
||||
if IsUUID(opts.ID) {
|
||||
ref = opts.ID
|
||||
}
|
||||
fmt.Printf("%#v\n", opts)
|
||||
path, err := namespacedRefPath(opts.Namespace, RuleAPIPrefix, ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := c.do("PUT", path, doOptions{
|
||||
data: opts,
|
||||
context: opts.Context,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var rule types.Rule
|
||||
if err := json.NewDecoder(resp.Body).Decode(&rule); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &rule, nil
|
||||
}
|
||||
|
||||
// RuleDelete removes a rule by its reference.
|
||||
func (c *Client) RuleDelete(opts types.DeleteOptions) error {
|
||||
deleteOpts := doOptions{
|
||||
namespace: opts.Namespace,
|
||||
force: opts.Force,
|
||||
context: opts.Context,
|
||||
}
|
||||
resp, err := c.do("DELETE", RuleAPIPrefix+"/"+opts.Name, deleteOpts)
|
||||
if err != nil {
|
||||
if e, ok := err.(*Error); ok {
|
||||
if e.Status == http.StatusNotFound {
|
||||
return ErrNoSuchRule
|
||||
}
|
||||
if e.Status == http.StatusConflict {
|
||||
return ErrRuleInUse
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
return nil
|
||||
}
|
28
vendor/github.com/storageos/go-api/server_version.go
generated
vendored
Normal file
28
vendor/github.com/storageos/go-api/server_version.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
package storageos
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/storageos/go-api/types"
|
||||
)
|
||||
|
||||
// ServerVersion returns the server's version and runtime info.
|
||||
func (c *Client) ServerVersion(ctx context.Context) (*types.VersionInfo, error) {
|
||||
|
||||
// Send as unversioned
|
||||
resp, err := c.do("GET", "version", doOptions{context: ctx, unversioned: true})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, newError(resp)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var version types.VersionInfo
|
||||
if err := json.NewDecoder(resp.Body).Decode(&version); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &version, nil
|
||||
}
|
12
vendor/github.com/storageos/go-api/swagger-gen.yaml
generated
vendored
Normal file
12
vendor/github.com/storageos/go-api/swagger-gen.yaml
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
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"
|
854
vendor/github.com/storageos/go-api/swagger.yaml
generated
vendored
Normal file
854
vendor/github.com/storageos/go-api/swagger.yaml
generated
vendored
Normal file
@@ -0,0 +1,854 @@
|
||||
|
||||
# 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"
|
90
vendor/github.com/storageos/go-api/template.go
generated
vendored
Normal file
90
vendor/github.com/storageos/go-api/template.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
package storageos
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/storageos/go-api/types"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
// TemplateAPIPrefix is a partial path to the HTTP endpoint.
|
||||
TemplateAPIPrefix = "/templates"
|
||||
|
||||
// ErrNoSuchTemplate is the error returned when the template does not exist.
|
||||
ErrNoSuchTemplate = errors.New("no such template")
|
||||
|
||||
// ErrTemplateInUse is the error returned when the template requested to be removed is still in use.
|
||||
ErrTemplateInUse = errors.New("template in use and cannot be removed")
|
||||
)
|
||||
|
||||
// TemplateList returns the list of available templates.
|
||||
func (c *Client) TemplateList(opts types.ListOptions) ([]types.Template, error) {
|
||||
path := TemplateAPIPrefix + "?" + queryString(opts)
|
||||
resp, err := c.do("GET", path, doOptions{context: opts.Context})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var templates []types.Template
|
||||
if err := json.NewDecoder(resp.Body).Decode(&templates); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return templates, nil
|
||||
}
|
||||
|
||||
// TemplateCreate creates a template on the server and returns the new object.
|
||||
func (c *Client) TemplateCreate(opts types.TemplateCreateOptions) (string, error) {
|
||||
resp, err := c.do("POST", TemplateAPIPrefix, doOptions{
|
||||
data: opts,
|
||||
context: opts.Context,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
out, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strconv.Unquote(string(out))
|
||||
}
|
||||
|
||||
// Template returns a template by its reference.
|
||||
func (c *Client) Template(ref string) (*types.Template, error) {
|
||||
resp, err := c.do("GET", TemplateAPIPrefix+"/"+ref, doOptions{})
|
||||
if err != nil {
|
||||
if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
|
||||
return nil, ErrNoSuchTemplate
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var template types.Template
|
||||
if err := json.NewDecoder(resp.Body).Decode(&template); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &template, nil
|
||||
}
|
||||
|
||||
// TemplateDelete removes a template by its reference.
|
||||
func (c *Client) TemplateDelete(ref string) error {
|
||||
resp, err := c.do("DELETE", TemplateAPIPrefix+"/"+ref, doOptions{})
|
||||
if err != nil {
|
||||
if e, ok := err.(*Error); ok {
|
||||
if e.Status == http.StatusNotFound {
|
||||
return ErrNoSuchTemplate
|
||||
}
|
||||
if e.Status == http.StatusConflict {
|
||||
return ErrTemplateInUse
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
return nil
|
||||
}
|
769
vendor/github.com/storageos/go-api/testing_notes.txt
generated
vendored
Normal file
769
vendor/github.com/storageos/go-api/testing_notes.txt
generated
vendored
Normal file
@@ -0,0 +1,769 @@
|
||||
docs.storageos.com - API webpage
|
||||
================================
|
||||
|
||||
TODO: Openind paragraph of text has multiple typos and grammar errors. Need to fix this. [DONE]
|
||||
TODO: hard to see the text for the example JSON post messages on the RHS. Possibly a Safari thing?!
|
||||
TODO: some of the JSON examples on the RHS of the webpage look wrong?! Safari issue?
|
||||
TODO: docs should use all lowercase for consistency?
|
||||
|
||||
VOLUMES
|
||||
=======
|
||||
|
||||
List volumes
|
||||
============
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - no provisioned volumes.
|
||||
- No auth username and password supplied.
|
||||
-->
|
||||
GET: 172.28.128.3:5705/v1/namespaces/default/volumes
|
||||
<--
|
||||
401 UNAUTHORIZED
|
||||
Unauthorized
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - no provisioned volumes.
|
||||
- bad namespace used.
|
||||
-->
|
||||
GET: 172.28.128.3:5705/v1/namespaces/defaultxxx/volumes
|
||||
<--
|
||||
404 NOT FOUND
|
||||
JSON: "message": "Not found"
|
||||
Unauthorized
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - no provisioned volumes.
|
||||
- Dropped the {namespace} path parameter.
|
||||
-->
|
||||
GET: 172.28.128.3:5705/v1/namespaces/volumes
|
||||
<--
|
||||
404 NOT FOUND
|
||||
Not found
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - no provisioned volumes.
|
||||
- One volume has already been created successfully.
|
||||
-->
|
||||
GET: 172.28.128.3:5705/v1/namespaces/volumes
|
||||
<--
|
||||
JSON: valid volume/inode state data (note: this time the master data is correctly set i.e. has non-zero data)
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- 3 node cluster - single provisioned volumes.
|
||||
-->
|
||||
GET: 172.28.128.3:5705/v1/namespaces/volumes
|
||||
<--
|
||||
JSON: valid volume/inode state data.
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- 3 node cluster - multiple provisioned volumes.
|
||||
-->
|
||||
GET: 172.28.128.3:5705/v1/namespaces/volumes
|
||||
<--
|
||||
JSON: an array of valid volume/inode state data for multiple volumes.
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- 3 node cluster - multiple provisioned volumes.
|
||||
- labelSelector
|
||||
-->
|
||||
GET: 172.28.128.3:5705/v1/namespaces/volumes?labelSelector=com.example.some-label
|
||||
<--
|
||||
JSON: an array of valid volume/inode state data for multiple volumes.
|
||||
-FAILED- doesn't appear to filter.
|
||||
XXX:
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- 3 node cluster - multiple provisioned volumes.
|
||||
- fieldSelector
|
||||
-->
|
||||
GET: 172.28.128.3:5705/v1/namespaces/volumes?fieldSelector=<????>
|
||||
<--
|
||||
JSON: an array of valid volume/inode state data for multiple volumes.
|
||||
-UNTESTED- don't know what to put for fieldSelector's value??
|
||||
XXX:
|
||||
|
||||
===============================================================================
|
||||
|
||||
|
||||
Create volumes
|
||||
==============
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - no provisioned volumes.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/namespaces/default/volumes
|
||||
BODY (JSON):
|
||||
{
|
||||
"name": "redis-vol01",
|
||||
"size": 1
|
||||
}
|
||||
<--
|
||||
JSON: valid volume/inode state data (note: master data is all zerod at this point)
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - with a single volume already provisioned.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/namespaces/default/volumes
|
||||
BODY (JSON):
|
||||
{
|
||||
"name": "redis-vol02",
|
||||
"size": 2
|
||||
}
|
||||
<--
|
||||
JSON: valid volume/inode state data (note: master data is all zerod at this point)
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - with two volumes already provisioned.
|
||||
- Now trying to provision a third with bad JSON body -- using CAPITAL first letters for Name and Size.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/namespaces/default/volumes
|
||||
BODY (JSON):
|
||||
{
|
||||
"Name": "redis-vol03",
|
||||
"Size": 3
|
||||
}
|
||||
<--
|
||||
JSON: valid volume/inode state data (note: master data is all zerod at this point)
|
||||
-EXPECTED- WORKS?! This implies that the JSON keys are non-case sensitive.
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - with two volumes already provisioned.
|
||||
- Now trying to provision a third with bad JSON body -- using all CAPITALS for NAME and SIZE.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/namespaces/default/volumes
|
||||
BODY (JSON):
|
||||
{
|
||||
"NAME": "redis-vol03",
|
||||
"SIZE": 3
|
||||
}
|
||||
<--
|
||||
JSON: valid volume/inode state data (note: master data is all zerod at this point)
|
||||
-EXPECTED- WORKS?! This implies that the JSON keys are non-case sensitive.
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - with two volumes already provisioned.
|
||||
- Now trying to provision a volume with bad JSON body -- missing size parameter.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/namespaces/default/volumes
|
||||
BODY (JSON):
|
||||
{
|
||||
"name": "redis-vol05",
|
||||
}
|
||||
<--
|
||||
JSON: valid volume/inode state data (note: master data is all zerod at this point)
|
||||
-EXPECTED- Size defaults to 10
|
||||
TODO: update documentation to reflect this. [DONE]
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - with two volumes already provisioned.
|
||||
- Now trying to provision a volume with bad JSON body -- with size (0) parameter.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/namespaces/default/volumes
|
||||
BODY (JSON):
|
||||
{
|
||||
"name": "redis-vol05",
|
||||
"size" 0
|
||||
}
|
||||
<--
|
||||
JSON: valid volume/inode state data (note: master data is all zerod at this point)
|
||||
-EXPECTED- Size defaults to 10
|
||||
TODO: update documentation to reflect this. [DONE]
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - with two volumes already provisioned.
|
||||
- Now trying to provision a volume with bad JSON body -- empty JSON object.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/namespaces/default/volumes
|
||||
BODY (JSON):
|
||||
{
|
||||
}
|
||||
<--
|
||||
volume name not valid
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - with two volumes already provisioned.
|
||||
- Now trying to provision a volume with no JSON body -- empty
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/namespaces/default/volumes
|
||||
BODY (JSON):
|
||||
<--
|
||||
JSON: "message": "EOF"
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- 3 node cluster.
|
||||
- Now trying to provision a volume with no JSON name field
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/namespaces/default/volumes
|
||||
BODY (JSON):
|
||||
{
|
||||
"size": 2
|
||||
}
|
||||
<--
|
||||
volume name not valid
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- 3 node cluster.
|
||||
- Now trying to provision a volume with no JSON name field
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/namespaces/default/volumes
|
||||
BODY (JSON):
|
||||
{
|
||||
"size": 2
|
||||
}
|
||||
<--
|
||||
volume name not valid
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- 3 node cluster.
|
||||
- Now trying to provision a volume with same name as one that has already been provisioned.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/namespaces/default/volumes
|
||||
BODY (JSON):
|
||||
{
|
||||
"name": "myvol1",
|
||||
"size": 5
|
||||
}
|
||||
<--
|
||||
volume with name 'myvol1' already exists
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- 3 node cluster.
|
||||
- Now trying to provision a volume with pool name.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/namespaces/default/volumes
|
||||
BODY (JSON):
|
||||
{
|
||||
"name": "myvol1",
|
||||
"size": 5,
|
||||
"pool": "mypool1"
|
||||
}
|
||||
<--
|
||||
JSON: valid volume/inode state data with correct pool field.
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- 3 node cluster.
|
||||
- Now trying to provision a volume with optional labels.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/namespaces/default/volumes
|
||||
BODY (JSON):
|
||||
{
|
||||
"Name": "vol01",
|
||||
"Size": 5,
|
||||
"Labels": {
|
||||
"com.example.some-label": "some-value",
|
||||
"com.example.some-other-label": "some-other-value"
|
||||
}
|
||||
}
|
||||
<--
|
||||
JSON: valid volume/inode state data with correct labels.
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
|
||||
Get volumes
|
||||
===========
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - N provisioned volumes.
|
||||
- Get by name.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/namespaces/default/volumes/redis-vol03
|
||||
<--
|
||||
JSON: correct volume/inode state data.
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - N provisioned volumes.
|
||||
- Get by id.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/namespaces/default/volumes/270c1fc2-c578-77f8-2d7c-1515e626b6c3
|
||||
<--
|
||||
JSON: correct volume/inode state data.
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - N provisioned volumes.
|
||||
- Passing bad name/id.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/namespaces/default/volumes/this-volume-does-not-exist
|
||||
<--
|
||||
Not Found
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
|
||||
Update volumes
|
||||
==============
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - N provisioned volumes.
|
||||
- Update a volume
|
||||
-->
|
||||
PUT: 172.28.128.3:5705/v1/namespaces/default/volumes/redis-vol03
|
||||
JSON:
|
||||
{
|
||||
"Description": "string",
|
||||
"Size": 5,
|
||||
"Labels": {
|
||||
"property1": "string",
|
||||
"property2": "string"
|
||||
}
|
||||
}
|
||||
<--
|
||||
200 OK
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - N provisioned volumes.
|
||||
- Update a volume, trying with bad JSON, missing opening curly brace!
|
||||
-->
|
||||
PUT: 172.28.128.3:5705/v1/namespaces/default/volumes/redis-vol03
|
||||
JSON:
|
||||
"Description": "string",
|
||||
"Size": 5,
|
||||
"Labels": {
|
||||
"property1": "string",
|
||||
"property2": "string"
|
||||
}
|
||||
}
|
||||
<--
|
||||
400 BAD REQUEST
|
||||
Request decode failed: json: cannot unmarshal string into Go value of type types.Volume
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - N provisioned volumes.
|
||||
- Update a volume, trying with size (0) and same property1 and new property3.
|
||||
-->
|
||||
PUT: 172.28.128.3:5705/v1/namespaces/default/volumes/redis-vol03
|
||||
JSON:
|
||||
{
|
||||
"Description": "string",
|
||||
"Size": 0,
|
||||
"Labels": {
|
||||
"property1": "string",
|
||||
"property3": "string3"
|
||||
}
|
||||
}
|
||||
<--
|
||||
200 OK
|
||||
-NOT EXPECTED-
|
||||
The old labels are completely overwritten anew (hence the previous property2 label is not present). I assume this is the desired behaviour?!
|
||||
TODO: However size is now zero?! Check this is ok! Probably not; since the Create volume API defaults to 10 when 0 is passed or omitted.
|
||||
XXX:
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - N provisioned volumes.
|
||||
- Update a volume, trying with omitting size parameter
|
||||
-->
|
||||
PUT: 172.28.128.3:5705/v1/namespaces/default/volumes/volxyz
|
||||
JSON:
|
||||
{
|
||||
"Description": "string",
|
||||
"Labels": {
|
||||
"property1": "string",
|
||||
"property3": "string3"
|
||||
}
|
||||
}
|
||||
<--
|
||||
200 OK
|
||||
-NOT EXPECTED-
|
||||
XXX: size is now zero when not passing size in JSON body of PUT request.
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - N provisioned volumes.
|
||||
- Update a volume, trying with omitting description parameter
|
||||
-->
|
||||
PUT: 172.28.128.3:5705/v1/namespaces/default/volumes/volxyz
|
||||
JSON:
|
||||
{
|
||||
"Labels": {
|
||||
"property1": "string",
|
||||
"property3": "string3"
|
||||
}
|
||||
}
|
||||
<--
|
||||
200 OK
|
||||
-NOT EXPECTED-
|
||||
XXX: description string is empty i.e. "" when not passing description in JSON body of PUT request.
|
||||
The above implies that the update volume PUT request receiving side interprets missing update parameters as their null-value counterparts. So it's is not possible to update just specific parameters.
|
||||
|
||||
===============================================================================
|
||||
|
||||
|
||||
Delete volumes
|
||||
==============
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - N provisioned volumes.
|
||||
- Delete a volume. But not specifying a name in the path.
|
||||
-->
|
||||
DELETE: 172.28.128.3:5705/v1/namespaces/default/volumes
|
||||
<--
|
||||
404 NOT FOUND
|
||||
404 page not found
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - N provisioned volumes.
|
||||
- Delete a volume by specifying the volume's name.
|
||||
-->
|
||||
DELETE: 172.28.128.3:5705/v1/namespaces/default/volumes/redis-vol05
|
||||
<--
|
||||
200 OK
|
||||
-EXPECTED-
|
||||
TODO: But when doing a GET ~volumes/redis-vol05 it is still present So DELETE volumes doesn't appear to be working.
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - N provisioned volumes.
|
||||
- Delete a volume by specifying the volume's id.
|
||||
-->
|
||||
DELETE: 172.28.128.3:5705/v1/namespaces/default/volumes/5233930b-b77f-2863-0895-b1eb5d73ec45
|
||||
<--
|
||||
200 OK
|
||||
-EXPECTED-
|
||||
TODO: But when doing a GET ~volumes/5233930b-b77f-2863-0895-b1eb5d73ec45 it is still present So DELETE volumes doesn't appear to be working.
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - N provisioned volumes.
|
||||
- Trying to delete a mounted volume
|
||||
-->
|
||||
DELETE: 172.28.128.3:5705/v1/namespaces/default/volumes/volxyz
|
||||
<--
|
||||
412 PRECONDITION FAILED
|
||||
cannot delete mounted volume
|
||||
-EXPECTED-
|
||||
TODO: seems correct, this hints that the mount is working which is in conflict with my observation below for MOUNT and UNMOUNT. Q. Is it checking the mount status via the OS, or by some other means i.e. locally cached value?
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - N provisioned volumes.
|
||||
- Trying to delete a unmounted volume
|
||||
-->
|
||||
DELETE: 172.28.128.3:5705/v1/namespaces/default/volumes/volxyz
|
||||
<--
|
||||
200 OK
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
|
||||
Mount volumes
|
||||
=============
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - N provisioned volumes.
|
||||
- Mount a volume. But not specifying a name in the path.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/namespaces/default/volumes/redis-vol02/mount
|
||||
JSON:
|
||||
{
|
||||
"client": "storageos-1-68228"
|
||||
}
|
||||
<--
|
||||
200 OK
|
||||
-EXPECTED-
|
||||
NOTE: in the JSON response, no_of_mounts does increase correctly by one each time. And mounted is set to true correctly.
|
||||
TODO: although this worked, the documentation doesn't give the proper JSON request body.
|
||||
TODO: no_of_mounts is still 0 in /var/lib/storageos/state/inode/178101 (should increase by 1 for every mount.)
|
||||
BUG^
|
||||
TODO: Also not sure if really mounted this volume, since running the storageos cli e.g.:
|
||||
$ ./storageos volume ls
|
||||
The MOUNTED BY column is always empty ?? Either cli doesn't show this info, yet. Or the volume isn't mounted.
|
||||
===============================================================================
|
||||
|
||||
|
||||
Unmount volumes
|
||||
===============
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - N provisioned volumes.
|
||||
- Mount a volume. But not specifying a name in the path.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/namespaces/default/volumes/redis-vol02/unmount
|
||||
JSON:
|
||||
{
|
||||
"can-be-anything": "storageos-1-68228"
|
||||
}
|
||||
<--
|
||||
200 OK
|
||||
-EXPECTED-
|
||||
NOTE: in the JSON response, mounted is set back to false correctly.
|
||||
TODO: although this worked, the documentation doesn't give the proper JSON request body. The
|
||||
|
||||
===============================================================================
|
||||
|
||||
|
||||
POOLS
|
||||
=====
|
||||
|
||||
List pools
|
||||
==========
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster.
|
||||
- No auth username and password supplied.
|
||||
-->
|
||||
GET: 172.28.128.3:5705/v1/pools
|
||||
<--
|
||||
401 UNAUTHORIZED
|
||||
Unauthorized
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster. No pools.
|
||||
-->
|
||||
GET: 172.28.128.3:5705/v1/pools
|
||||
<--
|
||||
200 OK
|
||||
JSON: an array of pools.
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
|
||||
Create pools
|
||||
============
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/volumes
|
||||
BODY (JSON):
|
||||
{
|
||||
"name": "mypool1"
|
||||
}
|
||||
<--
|
||||
201 CREATED
|
||||
JSON: valid pool data.
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster.
|
||||
- Trying to create a pool with the same name as another already created.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/volumes
|
||||
BODY (JSON):
|
||||
{
|
||||
"name": "mypool1"
|
||||
}
|
||||
<--
|
||||
409 CONFLICT
|
||||
Pool with name 'mypool1' already exists
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster.
|
||||
- Trying to create a pool with the same name as another already created.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/volumes
|
||||
BODY (JSON):
|
||||
{
|
||||
"name": "mypool2",
|
||||
"description": "hello world!"
|
||||
}
|
||||
<--
|
||||
201 CREATED
|
||||
JSON: valid pool data.
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster.
|
||||
- Trying to create a pool with the defaultDriver string set.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/volumes
|
||||
BODY (JSON):
|
||||
{
|
||||
"name": "mypool6",
|
||||
"description": "hello world again!",
|
||||
"default": true,
|
||||
"defautDriver": "I'm the default driver :)"
|
||||
}
|
||||
<--
|
||||
201 CREATED
|
||||
JSON: Is correct for the most part, but defaultDriver is an empty string??
|
||||
-NOT EXPECTED-
|
||||
XXX
|
||||
|
||||
===============================================================================
|
||||
|
||||
|
||||
Get Pools
|
||||
=========
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - N provisioned volumes.
|
||||
- Get by name.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/pools/mypool1
|
||||
<--
|
||||
200 OK
|
||||
JSON: correct pool data.
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - N provisioned volumes.
|
||||
- Get by id.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/pools/ea477d68-8193-1179-d889-aa6ea8797082
|
||||
<--
|
||||
200 OK
|
||||
JSON: correct pool data.
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - N provisioned volumes.
|
||||
- Get by name. Try passing invalid name.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/pools/mypool1xxx
|
||||
<--
|
||||
404 NOT FOUND
|
||||
Not Found
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
|
||||
Delete Pools
|
||||
============
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - N provisioned pools.
|
||||
- Trying to delete without specifying name etc. in the path.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/pools
|
||||
<--
|
||||
404 NOT FOUND
|
||||
404 page not found
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - N provisioned pools.
|
||||
- Delete by name.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/pools/mypool2
|
||||
<--
|
||||
200 OK
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
||||
|
||||
SCENARIO:
|
||||
- Fresh start - 3 node cluster - N provisioned pools.
|
||||
- Delete by id.
|
||||
-->
|
||||
POST: 172.28.128.3:5705/v1/pools/9a10bbfe-eaaa-af3c-2a9b-d78e0790efb4
|
||||
<--
|
||||
200 OK
|
||||
-EXPECTED-
|
||||
|
||||
===============================================================================
|
49
vendor/github.com/storageos/go-api/types/BUILD
generated
vendored
Normal file
49
vendor/github.com/storageos/go-api/types/BUILD
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"auth.go",
|
||||
"capacity_stats.go",
|
||||
"controller.go",
|
||||
"controller_update_options.go",
|
||||
"delete_options.go",
|
||||
"deployment.go",
|
||||
"driver_instance.go",
|
||||
"error_response.go",
|
||||
"events.go",
|
||||
"list_options.go",
|
||||
"namespace.go",
|
||||
"operator.go",
|
||||
"pool.go",
|
||||
"pool_create_options.go",
|
||||
"rule.go",
|
||||
"template.go",
|
||||
"template_create_options.go",
|
||||
"version.go",
|
||||
"volume.go",
|
||||
"volume_create_options.go",
|
||||
"volume_update_options.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
14
vendor/github.com/storageos/go-api/types/auth.go
generated
vendored
Normal file
14
vendor/github.com/storageos/go-api/types/auth.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
package types
|
||||
|
||||
// AuthConfig contains authorization information for connecting to a Registry
|
||||
type AuthConfig struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Auth string `json:"auth,omitempty"`
|
||||
ServerAddress string `json:"serveraddress,omitempty"`
|
||||
|
||||
// IdentityToken is used to authenticate the user and get
|
||||
// an access token for the registry.
|
||||
IdentityToken string `json:"identitytoken,omitempty"`
|
||||
}
|
25
vendor/github.com/storageos/go-api/types/capacity_stats.go
generated
vendored
Normal file
25
vendor/github.com/storageos/go-api/types/capacity_stats.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
package types
|
||||
|
||||
// ErrCapacityStatsUnchanged can be used when comparing stats
|
||||
const ErrCapacityStatsUnchanged = "no changes"
|
||||
|
||||
// CapacityStats is used to report capacity statistics on pools and controllers.
|
||||
type CapacityStats struct {
|
||||
|
||||
// TotalCapacityBytes is the object's total capacity in bytes.
|
||||
TotalCapacityBytes uint64 `json:"totalCapacityBytes"`
|
||||
|
||||
// AvailableCapacityBytes is the object's available capacity in bytes.
|
||||
AvailableCapacityBytes uint64 `json:"availableCapacityBytes"`
|
||||
|
||||
// ProvisionedCapacityBytes is the object's provisioned capacity in bytes.
|
||||
ProvisionedCapacityBytes uint64 `json:"provisionedCapacityBytes"`
|
||||
}
|
||||
|
||||
// IsEqual checks if capacity values are the same
|
||||
func (c CapacityStats) IsEqual(n CapacityStats) bool {
|
||||
if c == n {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
74
vendor/github.com/storageos/go-api/types/controller.go
generated
vendored
Normal file
74
vendor/github.com/storageos/go-api/types/controller.go
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
package types
|
||||
|
||||
// Versions and Prefixes used in API and KV URLs
|
||||
import "time"
|
||||
|
||||
const (
|
||||
ControllerAPIPrefix = "controller"
|
||||
ControllerDefaultPort = "3260"
|
||||
ControllerScanAPIPrefix = "config/scan"
|
||||
)
|
||||
|
||||
// ControllerCurrent - current controller
|
||||
var ControllerCurrent = ""
|
||||
|
||||
// Controller status phases
|
||||
const (
|
||||
ControllerStatusPending = "pending"
|
||||
ControllerStatusEvaluating = "evaluating"
|
||||
ControllerStatusDeploying = "deploying"
|
||||
ControllerStatusActive = "active"
|
||||
ControllerStatusFailed = "failed"
|
||||
ControllerStatusDeleting = "deleting"
|
||||
|
||||
ControllerHealthStarting = "starting"
|
||||
ControllerHealthOK = "healthy"
|
||||
ControllerHealthDegraded = "degraded"
|
||||
ControllerHealthOffline = "offline"
|
||||
)
|
||||
|
||||
// Errors for controller related things
|
||||
const (
|
||||
ErrControllerHostIDAllocation string = "error, could not allocate hostid"
|
||||
ErrControllerIDNotSet = "error, controller ID not set"
|
||||
ErrControllerNotFound = "controller not found"
|
||||
)
|
||||
|
||||
// Controller is used to represent a storage node in a cluster
|
||||
type Controller struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
HostID uint16 `json:"hostID"`
|
||||
Scheduler bool `json:"scheduler"`
|
||||
Name string `json:"name"`
|
||||
Address string `json:"address"`
|
||||
APIPort int `json:"apiPort"`
|
||||
NatsPort int `json:"natsPort"`
|
||||
NatsClusterPort int `json:"natsClusterPort"`
|
||||
SerfPort int `json:"serfPort"`
|
||||
DFSPort int `json:"dfsPort"`
|
||||
Description string `json:"description"`
|
||||
ControllerGroups []string `json:"controllerGroups"`
|
||||
Tags []string `json:"tags"`
|
||||
Labels map[string]string `json:"labels"`
|
||||
VolumeStats VolumeStats `json:"volumeStats"`
|
||||
PoolStats map[string]DriverStats `json:"poolStats"`
|
||||
|
||||
// health is updated by the
|
||||
Health string `json:"health"`
|
||||
HealthUpdatedAt time.Time `json:"healthUpdatedAt"`
|
||||
VersionInfo map[string]VersionInfo `json:"versionInfo"`
|
||||
Version string `json:"version"`
|
||||
|
||||
// high level stats that combine info from all driver instances
|
||||
CapacityStats CapacityStats `json:"capacityStats"`
|
||||
}
|
||||
|
||||
// DriverStats is used to report stats for all drivers in a pool.
|
||||
type DriverStats map[string]CapacityStats
|
||||
|
||||
// VolumeStats - volume stats (volume counts, looking forward to capacity)
|
||||
type VolumeStats struct {
|
||||
MasterVolumeCount int `json:"masterVolumeCount"`
|
||||
ReplicaVolumeCount int `json:"replicaVolumeCount"`
|
||||
VirtualVolumeCount int `json:"virtualVolumeCount"`
|
||||
}
|
24
vendor/github.com/storageos/go-api/types/controller_update_options.go
generated
vendored
Normal file
24
vendor/github.com/storageos/go-api/types/controller_update_options.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
package types
|
||||
|
||||
import "context"
|
||||
|
||||
// ControllerUpdateOptions are available parameters for updating existing controllers.
|
||||
type ControllerUpdateOptions struct {
|
||||
|
||||
// Controller unique ID.
|
||||
// Read Only: true
|
||||
ID string `json:"id"`
|
||||
|
||||
// Controller name.
|
||||
// Read Only: true
|
||||
Name string `json:"name"`
|
||||
|
||||
// Description of the controller.
|
||||
Description string `json:"description"`
|
||||
|
||||
// Labels are user-defined key/value metadata.
|
||||
Labels map[string]string `json:"labels"`
|
||||
|
||||
// Context can be set with a timeout or can be used to cancel a request.
|
||||
Context context.Context `json:"-"`
|
||||
}
|
24
vendor/github.com/storageos/go-api/types/delete_options.go
generated
vendored
Normal file
24
vendor/github.com/storageos/go-api/types/delete_options.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
package types
|
||||
|
||||
import "context"
|
||||
|
||||
// DeleteOptions are available parameters for deleting existing volumes.
|
||||
type DeleteOptions struct {
|
||||
|
||||
// Volume unique ID.
|
||||
// Read Only: true
|
||||
ID string `json:"id"`
|
||||
|
||||
// Volume name.
|
||||
// Read Only: true
|
||||
Name string `json:"name"`
|
||||
|
||||
// Namespace is the object scope, such as for teams and projects.
|
||||
Namespace string `json:"namespace"`
|
||||
|
||||
// Force will cause the volume to be deleted even if it's in use.
|
||||
Force bool `json:"force"`
|
||||
|
||||
// Context can be set with a timeout or can be used to cancel a request.
|
||||
Context context.Context `json:"-"`
|
||||
}
|
32
vendor/github.com/storageos/go-api/types/deployment.go
generated
vendored
Normal file
32
vendor/github.com/storageos/go-api/types/deployment.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
package types
|
||||
|
||||
import "time"
|
||||
|
||||
// Deployment Volume master or replica deployment details.
|
||||
// swagger:model Deployment
|
||||
type Deployment struct {
|
||||
|
||||
// Deployment unique ID
|
||||
// Read Only: true
|
||||
ID string `json:"id"`
|
||||
|
||||
// Inode number
|
||||
// Read Only: true
|
||||
Inode uint32 `json:"inode"`
|
||||
|
||||
// Controller ID
|
||||
// Read Only: true
|
||||
Controller string `json:"controller"`
|
||||
|
||||
// Health
|
||||
// Read Only: true
|
||||
Health string `json:"health"`
|
||||
|
||||
// Status
|
||||
// Read Only: true
|
||||
Status string `json:"status"`
|
||||
|
||||
// Created at
|
||||
// Read Only: true
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
}
|
86
vendor/github.com/storageos/go-api/types/driver_instance.go
generated
vendored
Normal file
86
vendor/github.com/storageos/go-api/types/driver_instance.go
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
package types
|
||||
|
||||
import "encoding/gob"
|
||||
|
||||
// DriverInstance is used to define an instance of a storage capacity driver.
|
||||
type DriverInstance struct {
|
||||
|
||||
// Instance unique ID.
|
||||
// Read Only: true
|
||||
ID string `json:"id"`
|
||||
|
||||
// Instance name.
|
||||
Name string `json:"name"`
|
||||
|
||||
// Instance description.
|
||||
Description string `json:"description"`
|
||||
|
||||
// Flag describing whether the template is active.
|
||||
// Default: false
|
||||
Active bool `json:"active"`
|
||||
|
||||
// Config is JSON struct that is passed directly to the driver. There is no
|
||||
// specific format, and the driver is responsible for validation.
|
||||
Config interface{} `json:"config"`
|
||||
|
||||
// Labels define a list of labels that describe the driver instance. These
|
||||
// are inherited from the pool when the driver instance is created.
|
||||
Labels []string `json:"labels"`
|
||||
|
||||
// ControllerName specifies the controller that this instance is running on.
|
||||
ControllerName string `json:"controllerName"`
|
||||
|
||||
// PoolID refers to the pool that this driver instance relates to.
|
||||
PoolID string `json:"poolID"`
|
||||
|
||||
// DriverName specifies which capacity driver this is an instance of.
|
||||
DriverName string `json:"driverName"`
|
||||
|
||||
// CapacityStats tracks that capacity usage of this driver instance on the
|
||||
// current controller.
|
||||
CapacityStats CapacityStats `json:"capacityStats"`
|
||||
}
|
||||
|
||||
// DriverInstances is a collection of Driver instance objects.
|
||||
type DriverInstances []*DriverInstance
|
||||
|
||||
func init() {
|
||||
gob.Register(DriverInstance{})
|
||||
gob.Register([]interface{}{})
|
||||
}
|
||||
|
||||
// Find an instance matching the parameters.
|
||||
func (i *DriverInstances) Find(pool string, driver string, controller string) *DriverInstance {
|
||||
|
||||
for _, inst := range *i {
|
||||
if inst.PoolID == pool && inst.DriverName == driver && inst.ControllerName == controller {
|
||||
return inst
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add a new instance to the list of instances.
|
||||
func (i *DriverInstances) Add(new *DriverInstance) {
|
||||
|
||||
for _, inst := range *i {
|
||||
// Skip if it already exists
|
||||
if inst.PoolID == new.PoolID && inst.DriverName == new.DriverName && inst.ControllerName == new.ControllerName {
|
||||
return
|
||||
}
|
||||
}
|
||||
*i = append(*i, new)
|
||||
}
|
||||
|
||||
// Remove an instance to the list of instances.
|
||||
func (i *DriverInstances) Remove(id string) {
|
||||
|
||||
// TODO: not working
|
||||
// for ndx, inst := range *i {
|
||||
// if inst.ID == id {
|
||||
// // splice out the item to remove
|
||||
// *i = append(*i[:ndx], *i[ndx+1:]...)
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
}
|
13
vendor/github.com/storageos/go-api/types/error_response.go
generated
vendored
Normal file
13
vendor/github.com/storageos/go-api/types/error_response.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
package types
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
// ErrorResponse Represents an error.
|
||||
// swagger:model ErrorResponse
|
||||
type ErrorResponse struct {
|
||||
|
||||
// The error message.
|
||||
// Required: true
|
||||
Message string `json:"message"`
|
||||
}
|
60
vendor/github.com/storageos/go-api/types/events.go
generated
vendored
Normal file
60
vendor/github.com/storageos/go-api/types/events.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
package types
|
||||
|
||||
import "time"
|
||||
|
||||
// EventType describes the type of event
|
||||
type EventType string
|
||||
|
||||
// EventTypes are added to events to assist with type assertions
|
||||
const (
|
||||
RequestType EventType = "request"
|
||||
ResponseType = "response"
|
||||
HeartbeatType = "heartbeat"
|
||||
BackupType = "backup"
|
||||
)
|
||||
|
||||
// Event describes the fields that all events should implement. Event is
|
||||
// intended to be inherherited in more specific Event types.
|
||||
type Event struct {
|
||||
ID string `json:"id"`
|
||||
// Parent is used to specify parent event
|
||||
Parent string `json:"parent"`
|
||||
EventType EventType `json:"eventType"`
|
||||
Action string `json:"action"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
Log []string `json:"log"`
|
||||
ProgressPercent int `json:"progressPercent"`
|
||||
CreatedBy string `json:"createdBy"`
|
||||
|
||||
Target string `json:"target"`
|
||||
ActionPayload interface{} `json:"actionPayload"`
|
||||
|
||||
// payload can be encoded into bytes as well
|
||||
ActionPayloadBytes []byte `json:"actionPayloadBts"`
|
||||
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
// retry related value
|
||||
Retry bool `json:"retry"`
|
||||
RetriedAt time.Time `json:"retriedAt"`
|
||||
Attempts int `json:"attempts"`
|
||||
|
||||
// optional parameter
|
||||
Deadline time.Time `json:"deadline"`
|
||||
|
||||
// optional events to dispatch
|
||||
Rollback []*Request `json:"rollback"`
|
||||
RollbackDone bool `json:"rollbackDone"`
|
||||
|
||||
Subject string `json:"subject"` // or "queue"
|
||||
|
||||
// controller ID which created this event
|
||||
OriginController string `json:"originController"`
|
||||
}
|
||||
|
||||
// Request is the message structure used for sending request events
|
||||
type Request struct {
|
||||
Event
|
||||
}
|
19
vendor/github.com/storageos/go-api/types/list_options.go
generated
vendored
Normal file
19
vendor/github.com/storageos/go-api/types/list_options.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package types
|
||||
|
||||
import "context"
|
||||
|
||||
// ListOptions are optional parameters for finding and listing most objects.
|
||||
type ListOptions struct {
|
||||
|
||||
// FieldSelector restricts the list of returned objects by their fields. Defaults to everything.
|
||||
FieldSelector string
|
||||
|
||||
// LabelSelector restricts the list of returned objects by their labels. Defaults to everything.
|
||||
LabelSelector string
|
||||
|
||||
// Namespace is the object scope, such as for teams and projects.
|
||||
Namespace string
|
||||
|
||||
// Context can be set with a timeout or can be used to cancel a request.
|
||||
Context context.Context
|
||||
}
|
59
vendor/github.com/storageos/go-api/types/namespace.go
generated
vendored
Normal file
59
vendor/github.com/storageos/go-api/types/namespace.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Namespace is used to as a container to isolate namespace and rule obects.
|
||||
type Namespace struct {
|
||||
|
||||
// Namespace unique ID.
|
||||
// Read Only: true
|
||||
ID string `json:"id"`
|
||||
|
||||
// Namespace name.
|
||||
// Required: true
|
||||
Name string `json:"name"`
|
||||
|
||||
// The optional DisplayName is how the project is displayed in the web console (defaults to name).
|
||||
DisplayName string `json:"displayName"`
|
||||
|
||||
// Namespcae description.
|
||||
Description string `json:"description"`
|
||||
|
||||
// User-defined key/value metadata.
|
||||
Labels map[string]string `json:"labels"`
|
||||
|
||||
// When the namespace was created.
|
||||
// Read Only: true
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
|
||||
// User that created the namespace.
|
||||
// Read Only: true
|
||||
CreatedBy string `json:"createdBy"`
|
||||
|
||||
// When the namespace was created.
|
||||
// Read Only: true
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// NamespaceCreateOptions are available parameters for creating new namespaces.
|
||||
type NamespaceCreateOptions struct {
|
||||
|
||||
// Name is the name of the namespace to create.
|
||||
// Required: true
|
||||
Name string `json:"name"`
|
||||
|
||||
// The optional DisplayName is how the project is displayed in the web console (defaults to name).
|
||||
DisplayName string `json:"displayName"`
|
||||
|
||||
// Description describes the namespace.
|
||||
Description string `json:"description"`
|
||||
|
||||
// Labels are user-defined key/value metadata.
|
||||
Labels map[string]string `json:"labels"`
|
||||
|
||||
// Context can be set with a timeout or can be used to cancel a request.
|
||||
Context context.Context `json:"-"`
|
||||
}
|
19
vendor/github.com/storageos/go-api/types/operator.go
generated
vendored
Normal file
19
vendor/github.com/storageos/go-api/types/operator.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package types
|
||||
|
||||
// Operator represents a key/field's relationship to value(s).
|
||||
// See labels.Requirement and fields.Requirement for more details.
|
||||
type Operator string
|
||||
|
||||
// Valid operators
|
||||
const (
|
||||
None Operator = ""
|
||||
DoesNotExist Operator = "!"
|
||||
Equals Operator = "="
|
||||
DoubleEquals Operator = "=="
|
||||
In Operator = "in"
|
||||
NotEquals Operator = "!="
|
||||
NotIn Operator = "notin"
|
||||
Exists Operator = "exists"
|
||||
GreaterThan Operator = "gt"
|
||||
LessThan Operator = "lt"
|
||||
)
|
55
vendor/github.com/storageos/go-api/types/pool.go
generated
vendored
Normal file
55
vendor/github.com/storageos/go-api/types/pool.go
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
package types
|
||||
|
||||
// Pool is used to define a capacity pool.
|
||||
type Pool struct {
|
||||
|
||||
// Pool unique ID.
|
||||
// Read Only: true
|
||||
ID string `json:"id"`
|
||||
|
||||
// Pool name.
|
||||
// Required: true
|
||||
Name string `json:"name"`
|
||||
|
||||
// Pool description.
|
||||
Description string `json:"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.
|
||||
Default bool `json:"default"`
|
||||
|
||||
// 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.
|
||||
DefaultDriver string `json:"defaultDriver"`
|
||||
|
||||
// ControllerNames is a list of controller names that are participating in the
|
||||
// storage pool.
|
||||
ControllerNames []string `json:"controllerNames"`
|
||||
|
||||
// DriverNames is a list of backend storage drivers that are available in the
|
||||
// storage pool.
|
||||
DriverNames []string `json:"driverNames"`
|
||||
|
||||
// DriverInstances is used to track instances of each driver. Drivers have a
|
||||
// default configuration, which can then be customised for each pool where
|
||||
// they are used, which is representated as a DriverInstance.
|
||||
// Read Only: true
|
||||
DriverInstances []*DriverInstance `json:"driverInstances"`
|
||||
|
||||
// Flag describing whether the template is active.
|
||||
// Default: false
|
||||
Active bool `json:"active"`
|
||||
|
||||
// CapacityStats are used to track aggregate capacity usage information across
|
||||
// all controllers and driver instances.
|
||||
// Read Only: true
|
||||
CapacityStats CapacityStats `json:"capacityStats"`
|
||||
|
||||
// Labels define a list of labels that describe the pool.
|
||||
Labels map[string]string `json:"labels"`
|
||||
}
|
||||
|
||||
// Pools is a collection of Pool objects
|
||||
type Pools []*Pool
|
42
vendor/github.com/storageos/go-api/types/pool_create_options.go
generated
vendored
Normal file
42
vendor/github.com/storageos/go-api/types/pool_create_options.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package types
|
||||
|
||||
import "context"
|
||||
|
||||
// PoolCreateOptions are available parameters for creating new pools.
|
||||
type PoolCreateOptions struct {
|
||||
|
||||
// Pool name.
|
||||
// Required: true
|
||||
Name string `json:"name"`
|
||||
|
||||
// Pool description.
|
||||
Description string `json:"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.
|
||||
Default bool `json:"default"`
|
||||
|
||||
// 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.
|
||||
DefaultDriver string `json:"defaultDriver"`
|
||||
|
||||
// ControllerNames is a list of controller names that are participating in the
|
||||
// storage pool.
|
||||
ControllerNames []string `json:"controllerNames"`
|
||||
|
||||
// DriverNames is a list of backend storage drivers that are available in the
|
||||
// storage pool.
|
||||
DriverNames []string `json:"driverNames"`
|
||||
|
||||
// Flag describing whether the template is active.
|
||||
// Default: false
|
||||
Active bool `json:"active"`
|
||||
|
||||
// Labels define a list of labels that describe the pool.
|
||||
Labels map[string]string `json:"labels"`
|
||||
|
||||
// Context can be set with a timeout or can be used to cancel a request.
|
||||
Context context.Context `json:"-"`
|
||||
}
|
125
vendor/github.com/storageos/go-api/types/rule.go
generated
vendored
Normal file
125
vendor/github.com/storageos/go-api/types/rule.go
generated
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
package types
|
||||
|
||||
import "context"
|
||||
|
||||
// Rule is used to define a rule
|
||||
type Rule struct {
|
||||
|
||||
// Rule unique ID.
|
||||
// Read Only: true
|
||||
ID string `json:"id"`
|
||||
|
||||
// Rule name.
|
||||
// Required: true
|
||||
Name string `json:"name"`
|
||||
|
||||
// Namespace is the object name and authentication scope, such as for teams and projects.
|
||||
Namespace string `json:"namespace"`
|
||||
|
||||
// Rule description.
|
||||
Description string `json:"description"`
|
||||
|
||||
// Flag describing whether the rule is active.
|
||||
// Default: false
|
||||
Active bool `json:"active"`
|
||||
|
||||
// Weight is used to determine order during rule processing. Rules with
|
||||
// heavier weights are processed later.
|
||||
// default: 0
|
||||
Weight int `json:"weight"`
|
||||
|
||||
// RuleAction controls whether the action is to add or remove a label from the
|
||||
// matching object(s).
|
||||
RuleAction string `json:"action"`
|
||||
|
||||
// Selectors defines the list of labels that should trigger a rule.
|
||||
Selector string `json:"selector"`
|
||||
|
||||
// Labels define the list of labels that will be added or removed from the
|
||||
// matching object(s).
|
||||
Labels map[string]string `json:"labels"`
|
||||
}
|
||||
|
||||
// Rules is a collection of Rules.
|
||||
type Rules []*Rule
|
||||
|
||||
// RuleCreateOptions are available parameters for creating new rules.
|
||||
type RuleCreateOptions struct {
|
||||
|
||||
// Rule name.
|
||||
// Required: true
|
||||
Name string `json:"name"`
|
||||
|
||||
// Namespace is the object name and authentication scope, such as for teams and projects.
|
||||
Namespace string `json:"namespace"`
|
||||
|
||||
// Rule description.
|
||||
Description string `json:"description"`
|
||||
|
||||
// Flag describing whether the rule is active.
|
||||
// Default: false
|
||||
Active bool `json:"active"`
|
||||
|
||||
// Weight is used to determine order during rule processing. Rules with
|
||||
// heavier weights are processed later.
|
||||
// default: 0
|
||||
Weight int `json:"weight"`
|
||||
|
||||
// RuleAction controls whether the action is to add or remove a label from the
|
||||
// matching object(s).
|
||||
RuleAction string `json:"action"`
|
||||
|
||||
// Selectors defines the list of labels that should trigger a rule.
|
||||
Selector string `json:"selector"`
|
||||
|
||||
// Labels define the list of labels that will be added or removed from the
|
||||
// matching object(s).
|
||||
Labels map[string]string `json:"labels"`
|
||||
|
||||
// Context can be set with a timeout or can be used to cancel a request.
|
||||
Context context.Context `json:"-"`
|
||||
}
|
||||
|
||||
// RuleUpdateOptions are available parameters for creating new rules.
|
||||
type RuleUpdateOptions struct {
|
||||
|
||||
// Rule unique ID.
|
||||
// Read Only: true
|
||||
ID string `json:"id"`
|
||||
|
||||
// Rule name.
|
||||
// Required: true
|
||||
Name string `json:"name"`
|
||||
|
||||
// Namespace is the object name and authentication scope, such as for teams and projects.
|
||||
Namespace string `json:"namespace"`
|
||||
|
||||
// Rule description.
|
||||
Description string `json:"description"`
|
||||
|
||||
// Flag describing whether the rule is active.
|
||||
// Default: false
|
||||
Active bool `json:"active"`
|
||||
|
||||
// Weight is used to determine order during rule processing. Rules with
|
||||
// heavier weights are processed later.
|
||||
// default: 0
|
||||
Weight int `json:"weight"`
|
||||
|
||||
// Operator is used to compare objects or labels.
|
||||
Operator string `json:"operator"`
|
||||
|
||||
// RuleAction controls whether the action is to add or remove a label from the
|
||||
// matching object(s).
|
||||
RuleAction string `json:"action"`
|
||||
|
||||
// Selectors defines the list of labels that should trigger a rule.
|
||||
Selector string `json:"selector"`
|
||||
|
||||
// Labels define the list of labels that will be added or removed from the
|
||||
// matching object(s).
|
||||
Labels map[string]string `json:"labels"`
|
||||
|
||||
// Context can be set with a timeout or can be used to cancel a request.
|
||||
Context context.Context `json:"-"`
|
||||
}
|
53
vendor/github.com/storageos/go-api/types/template.go
generated
vendored
Normal file
53
vendor/github.com/storageos/go-api/types/template.go
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
package types
|
||||
|
||||
// Template is used to define an auto-naming rule.
|
||||
type Template struct {
|
||||
|
||||
// Template unique ID.
|
||||
// Read Only: true
|
||||
ID string `json:"id"`
|
||||
|
||||
// Template name.
|
||||
// Required: true
|
||||
Name string `json:"name"`
|
||||
|
||||
// Template description.
|
||||
Description string `json:"description"`
|
||||
|
||||
// Template format. This is used for pattern matching against labels.
|
||||
Format string `json:"format"`
|
||||
|
||||
// Autoincrement defines whether there is a dynamic numeric component in the
|
||||
// template that must auto-increment when objects with the same name already
|
||||
// exists.
|
||||
AutoIncrement bool `json:"autoIncrement"`
|
||||
|
||||
// Padding determines whether a dynamic numeric component in the name should
|
||||
// be padded.
|
||||
// default: false
|
||||
Padding bool `json:"padding"`
|
||||
|
||||
// PaddingLength sets the length of the padding. A Padding length of 3 would
|
||||
// set name similar to `abc001` for the first item. Ignored if Padding set to
|
||||
// `false`.
|
||||
PaddingLength int `json:"paddingLength"`
|
||||
|
||||
// Flag describing whether the template is active.
|
||||
// Default: false
|
||||
Active bool `json:"active"`
|
||||
|
||||
// Weight is used to determine order during template processing. Templates
|
||||
// with heavier weights are processed later.
|
||||
// default: 0
|
||||
Weight int `json:"weight"`
|
||||
|
||||
// ObjectTypes defines the type names that the template can be applied to.
|
||||
ObjectTypes []string `json:"objectTypes"`
|
||||
|
||||
// Labels define a list of the labels that the object must have in order for
|
||||
// the template to be applied.
|
||||
Labels map[string]string `json:"labels"`
|
||||
}
|
||||
|
||||
// Templates is a collection of Template objects
|
||||
type Templates []*Template
|
51
vendor/github.com/storageos/go-api/types/template_create_options.go
generated
vendored
Normal file
51
vendor/github.com/storageos/go-api/types/template_create_options.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
package types
|
||||
|
||||
import "context"
|
||||
|
||||
// TemplateCreateOptions are available parameters for creating new templates.
|
||||
type TemplateCreateOptions struct {
|
||||
|
||||
// Template name.
|
||||
// Required: true
|
||||
Name string `json:"name"`
|
||||
|
||||
// Template description.
|
||||
Description string `json:"description"`
|
||||
|
||||
// Template format. This is used for pattern matching against labels.
|
||||
Format string `json:"format"`
|
||||
|
||||
// Autoincrement defines whether there is a dynamic numeric component in the
|
||||
// template that must auto-increment when objects with the same name already
|
||||
// exists.
|
||||
AutoIncrement bool `json:"autoIncrement"`
|
||||
|
||||
// Padding determines whether a dynamic numeric component in the name should
|
||||
// be padded.
|
||||
// default: false
|
||||
Padding bool `json:"padding"`
|
||||
|
||||
// PaddingLength sets the length of the padding. A Padding length of 3 would
|
||||
// set name similar to `abc001` for the first item. Ignored if Padding set to
|
||||
// `false`.
|
||||
PaddingLength int `json:"paddingLength"`
|
||||
|
||||
// Flag describing whether the template is active.
|
||||
// Default: false
|
||||
Active bool `json:"active"`
|
||||
|
||||
// Weight is used to determine order during template processing. Templates
|
||||
// with heavier weights are processed later.
|
||||
// default: 0
|
||||
Weight int `json:"weight"`
|
||||
|
||||
// ObjectTypes defines the type names that the template can be applied to.
|
||||
ObjectTypes []string `json:"objectTypes"`
|
||||
|
||||
// Labels define a list of the labels that the object must have in order for
|
||||
// the template to be applied.
|
||||
Labels map[string]string `json:"labels"`
|
||||
|
||||
// Context can be set with a timeout or can be used to cancel a request.
|
||||
Context context.Context `json:"-"`
|
||||
}
|
26
vendor/github.com/storageos/go-api/types/version.go
generated
vendored
Normal file
26
vendor/github.com/storageos/go-api/types/version.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
package types
|
||||
|
||||
// VersionInfo describes version and runtime info.
|
||||
type VersionInfo struct {
|
||||
Name string `json:"name"`
|
||||
BuildDate string `json:"buildDate"`
|
||||
Revision string `json:"revision"`
|
||||
Version string `json:"version"`
|
||||
APIVersion string `json:"apiVersion"`
|
||||
GoVersion string `json:"goVersion"`
|
||||
OS string `json:"os"`
|
||||
Arch string `json:"arch"`
|
||||
KernelVersion string `json:"kernelVersion"`
|
||||
Experimental bool `json:"experimental"`
|
||||
}
|
||||
|
||||
type VersionResponse struct {
|
||||
Client *VersionInfo
|
||||
Server *VersionInfo
|
||||
}
|
||||
|
||||
// ServerOK returns true when the client could connect to the docker server
|
||||
// and parse the information received. It returns false otherwise.
|
||||
func (v VersionResponse) ServerOK() bool {
|
||||
return v.Server != nil
|
||||
}
|
133
vendor/github.com/storageos/go-api/types/volume.go
generated
vendored
Normal file
133
vendor/github.com/storageos/go-api/types/volume.go
generated
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DefaultNamespace is used when a namespace hasn't been specified.
|
||||
const DefaultNamespace = "default"
|
||||
|
||||
// Volume represents storage volume.
|
||||
// swagger:model Volume
|
||||
type Volume struct {
|
||||
|
||||
// Volume unique ID.
|
||||
// Read Only: true
|
||||
ID string `json:"id"`
|
||||
|
||||
// Block device inode.
|
||||
// Read Only: true
|
||||
Inode uint32 `json:"inode"`
|
||||
|
||||
// Volume name.
|
||||
// Required: true
|
||||
Name string `json:"name"`
|
||||
|
||||
// Size in GB.
|
||||
// Required: true
|
||||
Size int `json:"size"`
|
||||
|
||||
// Name of capacity pool to provision the volume in, or the name of the current pool.
|
||||
Pool string `json:"pool"`
|
||||
|
||||
// Filesystem type to mount. May be set on create, or set by rules to influence client.
|
||||
FSType string `json:"fsType"`
|
||||
|
||||
// Volume description.
|
||||
Description string `json:"description"`
|
||||
|
||||
// User-defined key/value metadata.
|
||||
Labels map[string]string `json:"labels"`
|
||||
|
||||
// Namespace is the object name and authentication scope, such as for teams and projects.
|
||||
Namespace string `json:"namespace"`
|
||||
|
||||
// Volume deployment information for the master volume.
|
||||
// Read Only: true
|
||||
Master *Deployment `json:"master,omitempty"`
|
||||
|
||||
// Flag indicating if the volume is mounted and in use.
|
||||
// Read Only: true
|
||||
Mounted bool `json:"mounted"`
|
||||
|
||||
// Mountpoint, where the volume is mounted
|
||||
Mountpoint string `json:"mountpoint"`
|
||||
|
||||
// When the volume was mounted.
|
||||
// Read Only: true
|
||||
MountedAt time.Time `json:"mountedAt,omitempty"`
|
||||
|
||||
// Reference to the node that has the volume mounted.
|
||||
// Read Only: true
|
||||
MountedBy string `json:"mountedBy,omitempty"`
|
||||
|
||||
// Volume deployment information for the replica volumes.
|
||||
// Read Only: true
|
||||
Replicas []*Deployment `json:"replicas"`
|
||||
|
||||
// Volume health, one of: healthy, degraded or dead.
|
||||
// Read Only: true
|
||||
Health string `json:"health"`
|
||||
|
||||
// Short status, one of: pending, evaluating, deploying, active, unavailable, failed, updating, deleting.
|
||||
// Read Only: true
|
||||
Status string `json:"status"`
|
||||
|
||||
// Status message explaining current status.
|
||||
// Read Only: true
|
||||
StatusMessage string `json:"statusMessage"`
|
||||
|
||||
// When the volume was created.
|
||||
// Read Only: true
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
|
||||
// User that created the volume.
|
||||
// Read Only: true
|
||||
CreatedBy string `json:"createdBy"`
|
||||
}
|
||||
|
||||
// VolumeMountOptions - used by clients to inform of volume mount operations.
|
||||
type VolumeMountOptions struct {
|
||||
|
||||
// Volume unique ID.
|
||||
ID string `json:"id"`
|
||||
|
||||
// Name is the name of the volume to mount.
|
||||
Name string `json:"name"`
|
||||
|
||||
// Mountpoint, where the volume is mounted
|
||||
Mountpoint string `json:"mountpoint"`
|
||||
|
||||
// Filesystem type, optional but expected when mounting raw volume
|
||||
FsType string `json:"fsType"`
|
||||
|
||||
// Namespace is the object scope, such as for teams and projects.
|
||||
Namespace string `json:"namespace"`
|
||||
|
||||
// The hostname of the client mounting the volume.
|
||||
Client string `json:"client"`
|
||||
|
||||
// Context can be set with a timeout or can be used to cancel a request.
|
||||
Context context.Context `json:"-"`
|
||||
}
|
||||
|
||||
// VolumeUnmountOptions - used by clients to inform of volume mount operations.
|
||||
type VolumeUnmountOptions struct {
|
||||
|
||||
// Volume unique ID.
|
||||
ID string `json:"id"`
|
||||
|
||||
// Name is the name of the volume to unmount.
|
||||
Name string `json:"name"`
|
||||
|
||||
// Namespace is the object scope, such as for teams and projects.
|
||||
Namespace string `json:"namespace"`
|
||||
|
||||
// The hostname of the client unmounting the volume. Must match the hostname
|
||||
// of the client that registered the mount operation.
|
||||
Client string `json:"client"`
|
||||
|
||||
// Context can be set with a timeout or can be used to cancel a request.
|
||||
Context context.Context `json:"-"`
|
||||
}
|
33
vendor/github.com/storageos/go-api/types/volume_create_options.go
generated
vendored
Normal file
33
vendor/github.com/storageos/go-api/types/volume_create_options.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
package types
|
||||
|
||||
import "context"
|
||||
|
||||
// VolumeCreateOptions are available parameters for creating new volumes.
|
||||
type VolumeCreateOptions struct {
|
||||
|
||||
// Name is the name of the volume to create.
|
||||
// Required: true
|
||||
Name string `json:"name"`
|
||||
|
||||
// Description describes the volume.
|
||||
Description string `json:"description"`
|
||||
|
||||
// Size in GB.
|
||||
// Required: true
|
||||
Size int `json:"size"`
|
||||
|
||||
// Pool is the name or id of capacity pool to provision the volume in.
|
||||
Pool string `json:"pool"`
|
||||
|
||||
// Filesystem type to mount. May be set on create, or set by rules to influence client.
|
||||
FSType string `json:"fsType"`
|
||||
|
||||
// Namespace is the object scope, such as for teams and projects.
|
||||
Namespace string `json:"namespace"`
|
||||
|
||||
// Labels are user-defined key/value metadata.
|
||||
Labels map[string]string `json:"labels"`
|
||||
|
||||
// Context can be set with a timeout or can be used to cancel a request.
|
||||
Context context.Context `json:"-"`
|
||||
}
|
31
vendor/github.com/storageos/go-api/types/volume_update_options.go
generated
vendored
Normal file
31
vendor/github.com/storageos/go-api/types/volume_update_options.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
package types
|
||||
|
||||
import "context"
|
||||
|
||||
// VolumeUpdateOptions are available parameters for updating existing volumes.
|
||||
type VolumeUpdateOptions struct {
|
||||
|
||||
// Volume unique ID.
|
||||
// Read Only: true
|
||||
ID string `json:"id"`
|
||||
|
||||
// Volume name.
|
||||
// Read Only: true
|
||||
Name string `json:"name"`
|
||||
|
||||
// Description describes the volume.
|
||||
Description string `json:"description"`
|
||||
|
||||
// Size in GB.
|
||||
// Required: true
|
||||
Size int `json:"size"`
|
||||
|
||||
// Namespace is the object scope, such as for teams and projects.
|
||||
Namespace string `json:"namespace"`
|
||||
|
||||
// Labels are user-defined key/value metadata.
|
||||
Labels map[string]string `json:"labels"`
|
||||
|
||||
// Context can be set with a timeout or can be used to cancel a request.
|
||||
Context context.Context `json:"-"`
|
||||
}
|
16
vendor/github.com/storageos/go-api/util.go
generated
vendored
Normal file
16
vendor/github.com/storageos/go-api/util.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
package storageos
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ParseRef is a helper to split out the namespace and name from a path
|
||||
// reference.
|
||||
func ParseRef(ref string) (namespace string, name string, err error) {
|
||||
parts := strings.Split(ref, "/")
|
||||
if len(parts) != 2 {
|
||||
return "", "", fmt.Errorf("Name must be prefixed with <namespace>/")
|
||||
}
|
||||
return parts[0], parts[1], nil
|
||||
}
|
74
vendor/github.com/storageos/go-api/validation.go
generated
vendored
Normal file
74
vendor/github.com/storageos/go-api/validation.go
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
package storageos
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
const (
|
||||
// IDFormat are the characters allowed to represent an ID.
|
||||
IDFormat = `[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}`
|
||||
|
||||
// NameFormat are the characters allowed to represent a name.
|
||||
NameFormat = `[a-zA-Z0-9][a-zA-Z0-9~_.-]+`
|
||||
)
|
||||
|
||||
var (
|
||||
// IDPattern is a regular expression to validate a unique id against the
|
||||
// collection of restricted characters.
|
||||
IDPattern = regexp.MustCompile(`^` + IDFormat + `$`)
|
||||
|
||||
// NamePattern is a regular expression to validate names against the
|
||||
// collection of restricted characters.
|
||||
NamePattern = regexp.MustCompile(`^` + NameFormat + `$`)
|
||||
|
||||
ErrNoRef = errors.New("no ref provided or incorrect format")
|
||||
ErrNoNamespace = errors.New("no namespace provided or incorrect format")
|
||||
)
|
||||
|
||||
// ValidateNamespaceAndRef returns true if both the namespace and ref are valid.
|
||||
func ValidateNamespaceAndRef(namespace, ref string) error {
|
||||
if !IsUUID(ref) && !IsName(ref) {
|
||||
return ErrNoRef
|
||||
}
|
||||
if !IsName(namespace) {
|
||||
return ErrNoNamespace
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateNamespace returns true if the namespace uses a valid name.
|
||||
func ValidateNamespace(namespace string) error {
|
||||
if !IsName(namespace) {
|
||||
return ErrNoNamespace
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsUUID returns true if the string input is a valid UUID string.
|
||||
func IsUUID(s string) bool {
|
||||
return IDPattern.MatchString(s)
|
||||
}
|
||||
|
||||
// IsName returns true if the string input is a valid Name string.
|
||||
func IsName(s string) bool {
|
||||
return NamePattern.MatchString(s)
|
||||
}
|
||||
|
||||
// namespacedPath checks for valid input and returns api path for a namespaced
|
||||
// objectType. Use namespacedRefPath for objects.
|
||||
func namespacedPath(namespace, objectType string) (string, error) {
|
||||
if err := ValidateNamespace(namespace); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "/namespaces/" + namespace + "/" + objectType, nil
|
||||
}
|
||||
|
||||
// namespacedRefPath checks for valid input and returns api path for a single
|
||||
// namespaced object. Use namespacedPath for objects type path.
|
||||
func namespacedRefPath(namespace, objectType, ref string) (string, error) {
|
||||
if err := ValidateNamespaceAndRef(namespace, ref); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "/namespaces/" + namespace + "/" + objectType + "/" + ref, nil
|
||||
}
|
197
vendor/github.com/storageos/go-api/volume.go
generated
vendored
Normal file
197
vendor/github.com/storageos/go-api/volume.go
generated
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
package storageos
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/storageos/go-api/types"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
// VolumeAPIPrefix is a partial path to the HTTP endpoint.
|
||||
VolumeAPIPrefix = "volumes"
|
||||
|
||||
// ErrNoSuchVolume is the error returned when the volume does not exist.
|
||||
ErrNoSuchVolume = errors.New("no such volume")
|
||||
|
||||
// ErrVolumeInUse is the error returned when the volume requested to be removed is still in use.
|
||||
ErrVolumeInUse = errors.New("volume in use and cannot be removed")
|
||||
)
|
||||
|
||||
// VolumeList returns the list of available volumes.
|
||||
func (c *Client) VolumeList(opts types.ListOptions) ([]*types.Volume, 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", VolumeAPIPrefix, listOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var volumes []*types.Volume
|
||||
if err := json.NewDecoder(resp.Body).Decode(&volumes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return volumes, nil
|
||||
}
|
||||
|
||||
// Volume returns a volume by its reference.
|
||||
func (c *Client) Volume(namespace string, ref string) (*types.Volume, error) {
|
||||
path, err := namespacedRefPath(namespace, VolumeAPIPrefix, ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := c.do("GET", path, doOptions{})
|
||||
if err != nil {
|
||||
if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
|
||||
return nil, ErrNoSuchVolume
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var volume types.Volume
|
||||
if err := json.NewDecoder(resp.Body).Decode(&volume); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &volume, nil
|
||||
}
|
||||
|
||||
// VolumeCreate creates a volume on the server and returns the new object.
|
||||
func (c *Client) VolumeCreate(opts types.VolumeCreateOptions) (*types.Volume, error) {
|
||||
path, err := namespacedPath(opts.Namespace, VolumeAPIPrefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := c.do("POST", path, doOptions{
|
||||
data: opts,
|
||||
context: opts.Context,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var volume types.Volume
|
||||
if err := json.NewDecoder(resp.Body).Decode(&volume); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &volume, nil
|
||||
}
|
||||
|
||||
// VolumeUpdate updates a volume on the server.
|
||||
func (c *Client) VolumeUpdate(opts types.VolumeUpdateOptions) (*types.Volume, error) {
|
||||
ref := opts.Name
|
||||
if IsUUID(opts.ID) {
|
||||
ref = opts.ID
|
||||
}
|
||||
path, err := namespacedRefPath(opts.Namespace, VolumeAPIPrefix, ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := c.do("PUT", path, doOptions{
|
||||
data: opts,
|
||||
context: opts.Context,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var volume types.Volume
|
||||
if err := json.NewDecoder(resp.Body).Decode(&volume); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &volume, nil
|
||||
}
|
||||
|
||||
// VolumeDelete removes a volume by its reference.
|
||||
func (c *Client) VolumeDelete(opts types.DeleteOptions) error {
|
||||
deleteOpts := doOptions{
|
||||
namespace: opts.Namespace,
|
||||
force: opts.Force,
|
||||
context: opts.Context,
|
||||
}
|
||||
resp, err := c.do("DELETE", VolumeAPIPrefix+"/"+opts.Name, deleteOpts)
|
||||
if err != nil {
|
||||
if e, ok := err.(*Error); ok {
|
||||
if e.Status == http.StatusNotFound {
|
||||
return ErrNoSuchVolume
|
||||
}
|
||||
if e.Status == http.StatusConflict {
|
||||
return ErrVolumeInUse
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
// VolumeMount updates the volume with the client that mounted it.
|
||||
func (c *Client) VolumeMount(opts types.VolumeMountOptions) error {
|
||||
ref := opts.Name
|
||||
if IsUUID(opts.ID) {
|
||||
ref = opts.ID
|
||||
}
|
||||
path, err := namespacedRefPath(opts.Namespace, VolumeAPIPrefix, ref)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := c.do("POST", path+"/mount", doOptions{
|
||||
data: opts,
|
||||
context: opts.Context,
|
||||
})
|
||||
if err != nil {
|
||||
if e, ok := err.(*Error); ok {
|
||||
if e.Status == http.StatusNotFound {
|
||||
return ErrNoSuchVolume
|
||||
}
|
||||
if e.Status == http.StatusConflict {
|
||||
return ErrVolumeInUse
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
// VolumeUnmount removes the client from the mount reference.
|
||||
func (c *Client) VolumeUnmount(opts types.VolumeUnmountOptions) error {
|
||||
ref := opts.Name
|
||||
if IsUUID(opts.ID) {
|
||||
ref = opts.ID
|
||||
}
|
||||
path, err := namespacedRefPath(opts.Namespace, VolumeAPIPrefix, ref)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := c.do("POST", path+"/unmount", doOptions{
|
||||
data: opts,
|
||||
context: opts.Context,
|
||||
})
|
||||
if err != nil {
|
||||
if e, ok := err.(*Error); ok {
|
||||
if e.Status == http.StatusNotFound {
|
||||
return ErrNoSuchVolume
|
||||
}
|
||||
if e.Status == http.StatusConflict {
|
||||
return ErrVolumeInUse
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user