Fix duplicate proto error in kubectl 1.8.0-alpha.

- Remove vendor'ed package go.pedge.io/pb/go/google/protobuf.
- Update vendor'ed package github.com/libopenstorage/openstorage.
This commit is contained in:
Aditya Dani
2017-09-07 02:53:38 +01:00
parent 3168bd4b12
commit b59855d48a
37 changed files with 1947 additions and 2353 deletions

View File

@@ -10,7 +10,8 @@ go_library(
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/golang/protobuf/proto:go_default_library",
"//vendor/go.pedge.io/pb/go/google/protobuf:go_default_library",
"//vendor/github.com/golang/protobuf/ptypes/timestamp:go_default_library",
"//vendor/github.com/mohae/deepcopy:go_default_library",
],
)

View File

@@ -0,0 +1,79 @@
# OpenStorage API usage
Any storage product that uses the openstorage API can be managed via this API. Below are some examples of using this API.
### Enumerate nodes in a cluster
```go
import (
...
"github.com/libopenstorage/gossip/types"
"github.com/libopenstorage/openstorage/api"
"github.com/libopenstorage/openstorage/api/client/cluster"
)
type myapp struct {
manager cluster.Cluster
}
func (c *myapp) init() {
// Choose the default version.
// Leave the host blank to use the local UNIX socket, or pass in an IP and a port at which the server is listening on.
clnt, err := cluster.NewClusterClient("", cluster.APIVersion)
if err != nil {
fmt.Printf("Failed to initialize client library: %v\n", err)
os.Exit(1)
}
c.manager = cluster.ClusterManager(clnt)
}
func (c *myapp) listNodes() {
cluster, err := c.manager.Enumerate()
if err != nil {
cmdError(context, fn, err)
return
}
// cluster is now a hashmap of nodes... do something useful with it:
for _, n := range cluster.Nodes {
}
}
```
### Inspect a volume in a cluster
```go
import (
...
"github.com/libopenstorage/openstorage/api"
volumeclient "github.com/libopenstorage/openstorage/api/client/volume"
"github.com/libopenstorage/openstorage/volume"
)
type myapp struct {
volDriver volume.VolumeDriver
}
func (c *myapp) init() {
// Choose the default version.
// Leave the host blank to use the local UNIX socket, or pass in an IP and a port at which the server is listening on.
clnt, err := volumeclient.NewDriverClient("", v.name, volume.APIVersion)
if err != nil {
fmt.Printf("Failed to initialize client library: %v\n", err)
os.Exit(1)
}
v.volDriver = volumeclient.VolumeDriver(clnt)
}
func (c *myapp) inspect(id string) {
stats, err := v.volDriver.Stats(id, true)
if err != nil {
return
}
// stats is an object that has various volume properties and statistics.
}
```

View File

@@ -2,26 +2,44 @@ package api
import (
"fmt"
"math"
"strconv"
"strings"
"time"
"github.com/mohae/deepcopy"
)
// Strings for VolumeSpec
const (
Name = "name"
SpecEphemeral = "ephemeral"
SpecShared = "shared"
SpecSize = "size"
SpecScale = "scale"
SpecFilesystem = "fs"
SpecBlockSize = "block_size"
SpecHaLevel = "repl"
SpecPriority = "io_priority"
SpecSnapshotInterval = "snap_interval"
SpecAggregationLevel = "aggregation_level"
SpecDedupe = "dedupe"
SpecPassphrase = "passphrase"
Name = "name"
SpecNodes = "nodes"
SpecParent = "parent"
SpecEphemeral = "ephemeral"
SpecShared = "shared"
SpecSticky = "sticky"
SpecSecure = "secure"
SpecCompressed = "compressed"
SpecSize = "size"
SpecScale = "scale"
SpecFilesystem = "fs"
SpecBlockSize = "block_size"
SpecHaLevel = "repl"
SpecPriority = "io_priority"
SpecSnapshotInterval = "snap_interval"
SpecSnapshotSchedule = "snap_schedule"
SpecAggregationLevel = "aggregation_level"
SpecDedupe = "dedupe"
SpecPassphrase = "secret_key"
SpecAutoAggregationValue = "auto"
SpecGroup = "group"
SpecGroupEnforce = "fg"
SpecZones = "zones"
SpecRacks = "racks"
SpecRegions = "regions"
SpecLabels = "labels"
SpecPriorityAlias = "priority_io"
SpecIoProfile = "io_profile"
)
// OptionKey specifies a set of recognized query params.
@@ -30,6 +48,8 @@ const (
OptName = "Name"
// OptVolumeID query parameter used to lookup volume by ID.
OptVolumeID = "VolumeID"
// OptSnapID query parameter used to lookup snapshot by ID.
OptSnapID = "SnapID"
// OptLabel query parameter used to lookup volume by set of labels.
OptLabel = "Label"
// OptConfigLabel query parameter used to lookup volume by set of labels.
@@ -40,9 +60,16 @@ const (
// Api client-server Constants
const (
OsdVolumePath = "osd-volumes"
OsdVolumePath = "osd-volumes"
OsdSnapshotPath = "osd-snapshot"
TimeLayout = "Jan 2 15:04:05 UTC 2006"
)
const (
// AutoAggregation value indicates driver to select aggregation level.
AutoAggregation = math.MaxUint32
)
// Node describes the state of a node.
// It includes the current physical state (CPU, memory, storage, network usage) as
// well as the containers running on the system.
@@ -56,6 +83,7 @@ type Node struct {
Status Status
GenNumber uint64
Disks map[string]StorageResource
Pools []StoragePool
MgmtIp string
DataIp string
Timestamp time.Time
@@ -66,6 +94,17 @@ type Node struct {
NodeLabels map[string]string
}
type FluentDConfig struct {
IP string `json:"ip"`
Port string `json:"port"`
}
type TunnelConfig struct {
Key string `json:"key"`
Cert string `json:"cert"`
Endpoint string `json:"tunnel_endpoint"`
}
// Cluster represents the state of the cluster.
type Cluster struct {
Status Status
@@ -79,6 +118,18 @@ type Cluster struct {
// Nodes is an array of all the nodes in the cluster.
Nodes []Node
// Logging url for the cluster.
LoggingURL string
// Management url for the cluster
ManagementURL string
// FluentD Host for the cluster
FluentDConfig FluentDConfig
// TunnelConfig for the cluster [key, cert, endpoint]
TunnelConfig TunnelConfig
}
// StatPoint represents the basic structure of a single Stat reported
@@ -95,69 +146,97 @@ type StatPoint struct {
Timestamp int64
}
// DriverTypeSimpleValueOf returns the string format of DriverType
func DriverTypeSimpleValueOf(s string) (DriverType, error) {
obj, err := simpleValueOf("driver_type", DriverType_value, s)
return DriverType(obj), err
}
// SimpleString returns the string format of DriverType
func (x DriverType) SimpleString() string {
return simpleString("driver_type", DriverType_name, int32(x))
}
// FSTypeSimpleValueOf returns the string format of FSType
func FSTypeSimpleValueOf(s string) (FSType, error) {
obj, err := simpleValueOf("fs_type", FSType_value, s)
return FSType(obj), err
}
// SimpleString returns the string format of DriverType
func (x FSType) SimpleString() string {
return simpleString("fs_type", FSType_name, int32(x))
}
// CosTypeSimpleValueOf returns the string format of CosType
func CosTypeSimpleValueOf(s string) (CosType, error) {
obj, err := simpleValueOf("cos_type", CosType_value, s)
return CosType(obj), err
obj, exists := CosType_value[strings.ToUpper(s)]
if !exists {
return -1, fmt.Errorf("Invalid cos value: %s", s)
}
return CosType(obj), nil
}
// SimpleString returns the string format of CosType
func (x CosType) SimpleString() string {
return simpleString("cos_type", CosType_name, int32(x))
}
// GraphDriverChangeTypeSimpleValueOf returns the string format of GraphDriverChangeType
func GraphDriverChangeTypeSimpleValueOf(s string) (GraphDriverChangeType, error) {
obj, err := simpleValueOf("graph_driver_change_type", GraphDriverChangeType_value, s)
return GraphDriverChangeType(obj), err
}
// SimpleString returns the string format of GraphDriverChangeType
func (x GraphDriverChangeType) SimpleString() string {
return simpleString("graph_driver_change_type", GraphDriverChangeType_name, int32(x))
}
// VolumeActionParamSimpleValueOf returns the string format of VolumeAction
func VolumeActionParamSimpleValueOf(s string) (VolumeActionParam, error) {
obj, err := simpleValueOf("volume_action_param", VolumeActionParam_value, s)
return VolumeActionParam(obj), err
}
// SimpleString returns the string format of VolumeAction
func (x VolumeActionParam) SimpleString() string {
return simpleString("volume_action_param", VolumeActionParam_name, int32(x))
}
// VolumeStateSimpleValueOf returns the string format of VolumeState
func VolumeStateSimpleValueOf(s string) (VolumeState, error) {
obj, err := simpleValueOf("volume_state", VolumeState_value, s)
return VolumeState(obj), err
}
// SimpleString returns the string format of VolumeState
func (x VolumeState) SimpleString() string {
return simpleString("volume_state", VolumeState_name, int32(x))
}
// VolumeStatusSimpleValueOf returns the string format of VolumeStatus
func VolumeStatusSimpleValueOf(s string) (VolumeStatus, error) {
obj, err := simpleValueOf("volume_status", VolumeStatus_value, s)
return VolumeStatus(obj), err
}
// SimpleString returns the string format of VolumeStatus
func (x VolumeStatus) SimpleString() string {
return simpleString("volume_status", VolumeStatus_name, int32(x))
}
// IoProfileSimpleValueOf returns the string format of IoProfile
func IoProfileSimpleValueOf(s string) (IoProfile, error) {
obj, err := simpleValueOf("io_profile", IoProfile_value, s)
return IoProfile(obj), err
}
// SimpleString returns the string format of IoProfile
func (x IoProfile) SimpleString() string {
return simpleString("io_profile", IoProfile_name, int32(x))
}
func simpleValueOf(typeString string, valueMap map[string]int32, s string) (int32, error) {
obj, ok := valueMap[strings.ToUpper(fmt.Sprintf("%s_%s", typeString, s))]
if !ok {
@@ -178,6 +257,7 @@ func toSec(ms uint64) uint64 {
return ms / 1000
}
// WriteThroughput returns the write throughput
func (v *Stats) WriteThroughput() uint64 {
if v.IntervalMs == 0 {
return 0
@@ -185,6 +265,7 @@ func (v *Stats) WriteThroughput() uint64 {
return (v.WriteBytes) / toSec(v.IntervalMs)
}
// ReadThroughput returns the read throughput
func (v *Stats) ReadThroughput() uint64 {
if v.IntervalMs == 0 {
return 0
@@ -192,17 +273,93 @@ func (v *Stats) ReadThroughput() uint64 {
return (v.ReadBytes) / toSec(v.IntervalMs)
}
// Latency returns latency
func (v *Stats) Latency() uint64 {
ops := v.Writes + v.Reads
if ops == 0 {
return 0
}
return (uint64)((v.IoMs * 1000) / (v.Writes + v.Reads))
return (uint64)((v.IoMs * 1000) / ops)
}
// Read latency returns avg. time required for read operation to complete
func (v *Stats) ReadLatency() uint64 {
if v.Reads == 0 {
return 0
}
return (uint64)((v.ReadMs * 1000) / v.Reads)
}
// Write latency returns avg. time required for write operation to complete
func (v *Stats) WriteLatency() uint64 {
if v.Writes == 0 {
return 0
}
return (uint64)((v.WriteMs * 1000) / v.Writes)
}
// Iops returns iops
func (v *Stats) Iops() uint64 {
if v.IntervalMs == 0 {
return 0
}
return (v.Writes + v.Reads) / toSec(v.IntervalMs)
}
// Scaled returns true if the volume is scaled.
func (v *Volume) Scaled() bool {
return v.Spec.Scale > 1
}
// Contains returns true if mid is a member of volume's replication set.
func (m *Volume) Contains(mid string) bool {
rsets := m.GetReplicaSets()
for _, rset := range rsets {
for _, node := range rset.Nodes {
if node == mid {
return true
}
}
}
return false
}
// Copy makes a deep copy of VolumeSpec
func (s *VolumeSpec) Copy() *VolumeSpec {
spec := *s
if s.VolumeLabels != nil {
spec.VolumeLabels = make(map[string]string)
for k, v := range s.VolumeLabels {
spec.VolumeLabels[k] = v
}
}
if s.ReplicaSet != nil {
spec.ReplicaSet = &ReplicaSet{Nodes: make([]string, len(s.ReplicaSet.Nodes))}
copy(spec.ReplicaSet.Nodes, s.ReplicaSet.Nodes)
}
return &spec
}
// Copy makes a deep copy of Node
func (s *Node) Copy() *Node {
localCopy := deepcopy.Copy(*s)
nodeCopy := localCopy.(Node)
return &nodeCopy
}
func (v Volume) IsClone() bool {
return v.Source != nil && len(v.Source.Parent) != 0 && !v.Readonly
}
func (v Volume) IsSnapshot() bool {
return v.Source != nil && len(v.Source.Parent) != 0 && v.Readonly
}
func (v Volume) DisplayId() string {
if v.Locator != nil {
return fmt.Sprintf("%s (%s)", v.Locator.Name, v.Id)
} else {
return v.Id
}
return ""
}

File diff suppressed because it is too large Load Diff

View File

@@ -90,6 +90,13 @@ enum CosType {
HIGH = 3;
}
enum IoProfile {
IO_PROFILE_SEQUENTIAL = 0;
IO_PROFILE_RANDOM= 1;
IO_PROFILE_DB = 2;
IO_PROFILE_DB_REMOTE = 3;
}
// VolumeState represents the state of a volume.
enum VolumeState {
VOLUME_STATE_NONE = 0;
@@ -108,6 +115,10 @@ enum VolumeState {
// Volume is deleted, it will remain in this state
// while resources are asynchronously reclaimed
VOLUME_STATE_DELETED = 7;
// Volume is trying to be detached
VOLUME_STATE_TRY_DETACHING = 8;
// Volume is undergoing restore
VOLUME_STATE_RESTORE = 9;
}
// VolumeStatus represents a health status for a volume.
@@ -138,6 +149,15 @@ enum ClusterNotify {
CLUSTER_NOTIFY_DOWN = 0;
}
enum AttachState {
// Attached and available externally
ATTACH_STATE_EXTERNAL = 0;
// Attached but only available internally
ATTACH_STATE_INTERNAL = 1;
// Switching from External to Internal
ATTACH_STATE_INTERNAL_SWITCH = 2;
}
// StorageResource groups properties of a storage device.
message StorageResource {
// Id is the LUN identifier.
@@ -166,6 +186,24 @@ message StorageResource {
google.protobuf.Timestamp last_scan = 12;
}
// StoragePool groups different storage devices based on their CosType
message StoragePool {
// ID pool ID
int32 ID = 1;
// Cos reflects the capabilities of this drive pool
CosType Cos = 2;
// Medium underlying storage type
StorageMedium Medium = 3;
// RaidLevel storage raid level
string RaidLevel = 4;
// TotalSize of the pool
uint64 TotalSize = 7;
// Used size of the pool
uint64 Used = 8;
// Labels is a list of user defined name-value pairs
map<string, string> labels = 9;
}
// VolumeLocator is a structure that is attached to a volume
// and is used to carry opaque metadata.
message VolumeLocator {
@@ -183,89 +221,115 @@ message Source {
string seed = 2;
}
message Group {
// Id common identifier across volumes that have the same group.
string id = 1;
}
// VolumeSpec has the properties needed to create a volume.
message VolumeSpec {
// Ephemeral storage
bool ephemeral = 1;
// Thin provisioned volume size in bytes
// Size specifies the thin provisioned volume size.
uint64 size = 2;
// Format disk with this FSType
// Format specifies the filesystem for this volume.
FSType format = 3;
// Block size for filesystem
// BlockSize for the filesystem.
int64 block_size = 4;
// Specifies the number of nodes that are
// allowed to fail, and yet data is available
// A value of 0 implies that data is not erasure coded,
// a failure of a node will lead to data loss
// HaLevel specifies the number of copies of data.
int64 ha_level = 5;
// The COS, 1 to 9
// Cos specifies the relative class of service.
CosType cos = 6;
// Perform dedupe on this disk
bool dedupe = 7;
// IoProfile provides a hint about application using this volume.
IoProfile io_profile = 7;
// Dedupe specifies if the volume data is to be de-duplicated.
bool dedupe = 8;
// SnapshotInterval in minutes, set to 0 to disable snapshots
uint32 snapshot_interval = 8;
// Volume configuration labels
map<string, string> volume_labels = 9;
uint32 snapshot_interval = 9;
// VolumeLabels configuration labels
map<string, string> volume_labels = 10;
// Shared is true if this volume can be remotely accessed.
bool shared = 10;
// ReplicaSet is the desired replicaSet the volume want to be placed.
ReplicaSet replica_set = 11;
// Specifies the number of parts the volume can be aggregated from.
uint32 aggregation_level = 12;
bool shared = 11;
// ReplicaSet is the desired set of nodes for the volume data.
ReplicaSet replica_set = 12;
// Aggregatiokn level Specifies the number of parts the volume can be aggregated from.
uint32 aggregation_level = 13;
// Encrypted is true if this volume will be cryptographically secured.
bool encrypted = 13;
// User passphrase if this is an encrypted volume
string passphrase = 14;
// SnapshotSchedule
string snapshot_schedule = 15;
bool encrypted = 14;
// Passphrase for an encrypted volume
string passphrase = 15;
// SnapshotSchedule a well known string that specifies when snapshots should be taken.
string snapshot_schedule = 16;
// Scale allows autocreation of volumes.
uint32 scale = 16;
uint32 scale = 17;
// Sticky volumes cannot be deleted until the flag is removed.
bool sticky = 18;
// Group identifies a consistency group
Group group = 21;
// GroupEnforced is true if consistency group creation is enforced.
bool group_enforced = 22;
// Compressed is true if this volume is to be compressed.
bool compressed = 23;
}
// Set of machine IDs (nodes) to which part of this volume is erasure coded - for clustered storage arrays
// ReplicaSet set of machine IDs (nodes) to which part of this volume is erasure
// coded - for clustered storage arrays
message ReplicaSet {
repeated string nodes = 1;
}
// List of name value mapping of driver specific runtime information.
// RuntimeStateMap is a list of name value mapping of driver specific runtime
// information.
message RuntimeStateMap {
map<string, string> runtime_state = 1;
}
// Volume represents a live, created volume.
// Volume represents an abstract storage volume.
// Volume represents an abstract storage volume.
message Volume {
// Self referential volume ID
// Self referential volume ID.
string id = 1;
// Source specified seed data for the volume.
Source source = 2;
bool readonly = 3;
// Group volumes in the same group have the same group id.
Group group = 3;
// Readonly is true if this volume is to be mounted with readonly access.
bool readonly = 4;
// User specified locator
VolumeLocator locator = 4;
VolumeLocator locator = 5;
// Volume creation time
google.protobuf.Timestamp ctime = 5;
google.protobuf.Timestamp ctime = 6;
// User specified VolumeSpec
VolumeSpec spec = 6;
// Volume usage
uint64 usage = 7;
// Time when an integrity check for run
google.protobuf.Timestamp last_scan = 8;
// Format FSType type if any
FSType format = 9;
VolumeStatus status = 10;
VolumeState state = 11;
// Machine ID (node) on which this volume is attached
// Machine ID is a node instance identifier for clustered systems.
string attached_on = 12;
string device_path = 14;
repeated string attach_path = 15;
// List of ReplicaSets which provide storage for this volume, for clustered storage arrays
repeated ReplicaSet replica_sets = 16;
// Last recorded error
string error = 17;
// List of name value mapping of driver specific runtime information.
repeated RuntimeStateMap runtime_state = 18;
string secure_device_path = 19;
// BackgroundProcessing is true if volume is attached but not by the user
bool background_processing = 20;
VolumeSpec spec = 7;
// Usage is bytes consumed by vtheis volume.
uint64 usage = 8;
// LastScan is the time when an integrity check was run.
google.protobuf.Timestamp last_scan = 9;
// Format specifies the filesytem for this volume.
FSType format = 10;
// Status is the availability status of this volume.
VolumeStatus status = 11;
// State is the current runtime state of this volume.
VolumeState state = 12;
// AttachedOn is the node instance identifier for clustered systems.
string attached_on = 13;
// AttachedState shows whether the device is attached for internal or external use.
AttachState attached_state = 14;
// DevicePath is the device exported by block device implementations.
string device_path = 15;
// SecureDevicePath is the device path for an encrypted volume.
string secure_device_path = 16;
// AttachPath is the mounted path in the host namespace.
repeated string attach_path = 17;
// AttachInfo is a list of name value mappings that provides attach information.
map<string, string> attach_info = 18;
// ReplicatSets storage for this volumefor clustered storage arrays.
repeated ReplicaSet replica_sets = 19;
// RuntimeState is a lst of name value mapping of driver specific runtime
// information.
repeated RuntimeStateMap runtime_state = 20;
// Error is the Last recorded error.
string error = 21;
}
message Stats {
@@ -308,6 +372,8 @@ message Alert {
bool cleared = 8;
// TTL in seconds for this Alert
uint64 ttl = 9;
// UniqueTag helps identify a unique alert for a given resouce
string unique_tag = 10;
}
message Alerts {
@@ -339,9 +405,13 @@ message VolumeStateAction {
VolumeActionParam attach = 1;
// Mount or unmount volume
VolumeActionParam mount = 2;
// MountPath Path where the device is mounted
string mount_path = 3;
// Device path returned in attach
// DevicePath Path returned in attach
string device_path = 4;
// UnmountBeforeDetach is used to check whether unmount should be done before
// a detach
bool unmount_before_detach = 5;
}
message VolumeSetRequest {
@@ -351,6 +421,9 @@ message VolumeSetRequest {
VolumeSpec spec = 2;
// State modification on this volume.
VolumeStateAction action = 3;
// additional options
// required for the Set operation.
map<string, string> options = 4;
}
message VolumeSetResponse {

View File

@@ -16,7 +16,7 @@ var (
)
// NewClient returns a new REST client for specified server.
func NewClient(host string, version string) (*Client, error) {
func NewClient(host, version, userAgent string) (*Client, error) {
baseURL, err := url.Parse(host)
if err != nil {
return nil, err
@@ -25,14 +25,48 @@ func NewClient(host string, version string) (*Client, error) {
baseURL.Path = "/"
}
unix2HTTP(baseURL)
hClient := getHTTPClient(host)
if hClient == nil {
return nil, fmt.Errorf("Unable to parse provided url: %v", host)
}
c := &Client{
base: baseURL,
version: version,
httpClient: getHttpClient(host),
base: baseURL,
version: version,
httpClient: hClient,
authstring: "",
accesstoken: "",
userAgent: fmt.Sprintf("%v/%v", userAgent, version),
}
return c, nil
}
// NewAuthClient returns a new REST client for specified server.
func NewAuthClient(host, version, authstring, accesstoken, userAgent string) (*Client, error) {
baseURL, err := url.Parse(host)
if err != nil {
return nil, err
}
if baseURL.Path == "" {
baseURL.Path = "/"
}
unix2HTTP(baseURL)
hClient := getHTTPClient(host)
if hClient == nil {
return nil, fmt.Errorf("Unable to parse provided url: %v", host)
}
c := &Client{
base: baseURL,
version: version,
httpClient: hClient,
authstring: authstring,
accesstoken: accesstoken,
userAgent: fmt.Sprintf("%v/%v", userAgent, version),
}
return c, nil
}
// GetUnixServerPath returns a unix domain socket prepended with the
// provided path.
func GetUnixServerPath(socketName string, paths ...string) string {
serverPath := "unix://"
for _, path := range paths {
@@ -42,13 +76,15 @@ func GetUnixServerPath(socketName string, paths ...string) string {
return serverPath
}
// Client is an HTTP REST wrapper. Use one of Get/Post/Put/Delete to get a request
// object.
type Client struct {
base *url.URL
version string
httpClient *http.Client
base *url.URL
version string
httpClient *http.Client
authstring string
accesstoken string
userAgent string
}
// Status sends a Status request at the /status REST endpoint.
@@ -58,7 +94,7 @@ func (c *Client) Status() (*Status, error) {
return status, err
}
// Version send a request at the /versions REST endpoint.
// Versions send a request at the /versions REST endpoint.
func (c *Client) Versions(endpoint string) ([]string, error) {
versions := []string{}
err := c.Get().Resource(endpoint + "/versions").Do().Unmarshal(&versions)
@@ -67,22 +103,22 @@ func (c *Client) Versions(endpoint string) ([]string, error) {
// Get returns a Request object setup for GET call.
func (c *Client) Get() *Request {
return NewRequest(c.httpClient, c.base, "GET", c.version)
return NewRequest(c.httpClient, c.base, "GET", c.version, c.authstring, c.userAgent)
}
// Post returns a Request object setup for POST call.
func (c *Client) Post() *Request {
return NewRequest(c.httpClient, c.base, "POST", c.version)
return NewRequest(c.httpClient, c.base, "POST", c.version, c.authstring, c.userAgent)
}
// Put returns a Request object setup for PUT call.
func (c *Client) Put() *Request {
return NewRequest(c.httpClient, c.base, "PUT", c.version)
return NewRequest(c.httpClient, c.base, "PUT", c.version, c.authstring, c.userAgent)
}
// Put returns a Request object setup for DELETE call.
// Delete returns a Request object setup for DELETE call.
func (c *Client) Delete() *Request {
return NewRequest(c.httpClient, c.base, "DELETE", c.version)
return NewRequest(c.httpClient, c.base, "DELETE", c.version, c.authstring, c.userAgent)
}
func unix2HTTP(u *url.URL) {
@@ -94,7 +130,12 @@ func unix2HTTP(u *url.URL) {
}
}
func newHTTPClient(u *url.URL, tlsConfig *tls.Config, timeout time.Duration) *http.Client {
func newHTTPClient(
u *url.URL,
tlsConfig *tls.Config,
timeout time.Duration,
responseTimeout time.Duration,
) *http.Client {
httpTransport := &http.Transport{
TLSClientConfig: tlsConfig,
}
@@ -114,28 +155,24 @@ func newHTTPClient(u *url.URL, tlsConfig *tls.Config, timeout time.Duration) *ht
}
}
return &http.Client{Transport: httpTransport}
return &http.Client{Transport: httpTransport, Timeout: responseTimeout}
}
func getHttpClient(host string) *http.Client {
func getHTTPClient(host string) *http.Client {
cacheLock.Lock()
defer cacheLock.Unlock()
c, ok := httpCache[host]
if !ok {
cacheLock.Lock()
defer cacheLock.Unlock()
c, ok = httpCache[host]
if !ok {
u, err := url.Parse(host)
if err != nil {
// TODO(pedge): clean up
fmt.Println("Failed to parse into url", host)
return nil
}
if u.Path == "" {
u.Path = "/"
}
c = newHTTPClient(u, nil, 10*time.Second)
httpCache[host] = c
u, err := url.Parse(host)
if err != nil {
return nil
}
if u.Path == "" {
u.Path = "/"
}
c = newHTTPClient(u, nil, 10*time.Second, 5*time.Minute)
httpCache[host] = c
}
return c
}

View File

@@ -11,6 +11,7 @@ import (
"strconv"
"strings"
"time"
"math/rand"
)
// Request is contructed iteratively by the client and finally dispatched.
@@ -31,6 +32,8 @@ type Request struct {
req *http.Request
resp *http.Response
timeout time.Duration
authstring string
accesstoken string
}
// Response is a representation of HTTP response received from the server.
@@ -48,14 +51,17 @@ type Status struct {
}
// NewRequest instance
func NewRequest(client *http.Client, base *url.URL, verb string, version string) *Request {
return &Request{
func NewRequest(client *http.Client, base *url.URL, verb string, version string, authstring, userAgent string) *Request {
r := &Request{
client: client,
verb: verb,
base: base,
path: base.Path,
version: version,
authstring: authstring,
}
r.SetHeader("User-Agent", userAgent)
return r
}
func checkExists(mustExist string, before string) error {
@@ -251,8 +257,19 @@ func (r *Request) Do() *Response {
if r.headers == nil {
r.headers = http.Header{}
}
req.Header = r.headers
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Date", time.Now().String())
if len(r.authstring) > 0 {
req.Header.Set("Authorization", "Basic "+ r.authstring)
}
if len(r.accesstoken) > 0 {
req.Header.Set("Access-Token", r.accesstoken)
}
resp, err = r.client.Do(req)
if err != nil {
return &Response{err: err}
@@ -295,10 +312,21 @@ func (r Response) Error() error {
return r.err
}
// FormatError formats the error
func (r Response) FormatError() error {
if len(r.body) == 0 {
return fmt.Errorf("Error: %v", r.err)
} else {
return fmt.Errorf("HTTP-%d: %s", r.statusCode, string(r.body))
}
return fmt.Errorf("HTTP-%d: %s", r.statusCode, string(r.body))
}
func digest(method string, path string) string {
now := time.Now().String()
s1 := rand.NewSource(time.Now().UnixNano())
r1 := rand.New(s1)
nonce := r1.Intn(10)
return method + "+" + path + "+" + now + "+" + strconv.Itoa(nonce)
}

View File

@@ -195,6 +195,21 @@ func (v *volumeClient) Snapshot(volumeID string, readonly bool,
return "", nil
}
// Restore specified volume to given snapshot state
func (v *volumeClient) Restore(volumeID string, snapID string) error {
response := &api.VolumeResponse{}
req := v.c.Post().Resource(snapPath + "/restore").Instance(volumeID)
req.QueryOption(api.OptSnapID, snapID)
if err := req.Do().Unmarshal(response); err != nil {
return err
}
if response.Error != "" {
return errors.New(response.Error)
}
return nil
}
// Stats for specified volume.
// Errors ErrEnoEnt may be returned
func (v *volumeClient) Stats(
@@ -205,21 +220,20 @@ func (v *volumeClient) Stats(
req := v.c.Get().Resource(volumePath + "/stats").Instance(volumeID)
req.QueryOption(api.OptCumulative, strconv.FormatBool(cumulative))
if err := req.Do().Unmarshal(stats); err != nil {
return nil, err
}
err := req.Do().Unmarshal(stats)
return stats, err
return stats, nil
}
// Alerts on this volume.
// UsedSize returns allocated volume size.
// Errors ErrEnoEnt may be returned
func (v *volumeClient) Alerts(volumeID string) (*api.Alerts, error) {
alerts := &api.Alerts{}
if err := v.c.Get().Resource(volumePath + "/alerts").Instance(volumeID).Do().Unmarshal(alerts); err != nil {
return nil, err
}
return alerts, nil
func (v *volumeClient) UsedSize(
volumeID string,
) (uint64, error) {
var usedSize uint64
req := v.c.Get().Resource(volumePath + "/usedsize").Instance(volumeID)
err := req.Do().Unmarshal(&usedSize)
return usedSize, err
}
// Active Requests on all volume.
@@ -289,13 +303,14 @@ func (v *volumeClient) SnapEnumerate(ids []string,
// Attach map device to the host.
// On success the devicePath specifies location where the device is exported
// Errors ErrEnoEnt, ErrVolAttached may be returned.
func (v *volumeClient) Attach(volumeID string) (string, error) {
func (v *volumeClient) Attach(volumeID string, attachOptions map[string]string) (string, error) {
response, err := v.doVolumeSetGetResponse(
volumeID,
&api.VolumeSetRequest{
Action: &api.VolumeStateAction{
Attach: api.VolumeActionParam_VOLUME_ACTION_PARAM_ON,
},
Options: attachOptions,
},
)
if err != nil {
@@ -313,12 +328,13 @@ func (v *volumeClient) Attach(volumeID string) (string, error) {
// Detach device from the host.
// Errors ErrEnoEnt, ErrVolDetached may be returned.
func (v *volumeClient) Detach(volumeID string) error {
func (v *volumeClient) Detach(volumeID string, unmountBeforeDetach bool) error {
return v.doVolumeSet(
volumeID,
&api.VolumeSetRequest{
Action: &api.VolumeStateAction{
Attach: api.VolumeActionParam_VOLUME_ACTION_PARAM_OFF,
Attach: api.VolumeActionParam_VOLUME_ACTION_PARAM_OFF,
UnmountBeforeDetach: unmountBeforeDetach,
},
},
)

View File

@@ -2,9 +2,9 @@ package volume
import (
"fmt"
"github.com/libopenstorage/openstorage/api"
"github.com/libopenstorage/openstorage/api/client"
"github.com/libopenstorage/openstorage/volume"
"github.com/libopenstorage/openstorage/api"
)
// VolumeDriver returns a REST wrapper for the VolumeDriver interface.
@@ -12,10 +12,10 @@ func VolumeDriver(c *client.Client) volume.VolumeDriver {
return newVolumeClient(c)
}
// NewDriver returns a new REST client of the supplied version for specified driver.
// NewAuthDriverClient returns a new REST client of the supplied version for specified driver.
// host: REST endpoint [http://<ip>:<port> OR unix://<path-to-unix-socket>]. default: [unix:///var/lib/osd/<driverName>.sock]
// version: Volume API version
func NewDriverClient(host, driverName, version string) (*client.Client, error) {
func NewAuthDriverClient(host, driverName, version, authstring, accesstoken, userAgent string) (*client.Client, error) {
if driverName == "" {
return nil, fmt.Errorf("Driver Name cannot be empty")
}
@@ -26,7 +26,24 @@ func NewDriverClient(host, driverName, version string) (*client.Client, error) {
// Set the default version
version = volume.APIVersion
}
return client.NewClient(host, version)
return client.NewAuthClient(host, version, authstring, accesstoken, userAgent)
}
// NewDriverClient returns a new REST client of the supplied version for specified driver.
// host: REST endpoint [http://<ip>:<port> OR unix://<path-to-unix-socket>]. default: [unix:///var/lib/osd/<driverName>.sock]
// version: Volume API version
func NewDriverClient(host, driverName, version, userAgent string) (*client.Client, error) {
if driverName == "" {
return nil, fmt.Errorf("Driver Name cannot be empty")
}
if host == "" {
host = client.GetUnixServerPath(driverName, volume.DriverAPIBase)
}
if version == "" {
// Set the default version
version = volume.APIVersion
}
return client.NewClient(host, version, userAgent)
}
// GetSupportedDriverVersions returns a list of supported versions
@@ -38,7 +55,7 @@ func GetSupportedDriverVersions(driverName, host string) ([]string, error) {
host = client.GetUnixServerPath(driverName, volume.DriverAPIBase)
}
client, err := client.NewClient(host, "")
client, err := client.NewClient(host, "", "")
if err != nil {
return []string{}, err
}

View File

@@ -6,6 +6,7 @@ go_library(
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/libopenstorage/openstorage/api:go_default_library",
"//vendor/github.com/libopenstorage/openstorage/pkg/parser:go_default_library",
"//vendor/github.com/libopenstorage/openstorage/pkg/units:go_default_library",
],
)

View File

@@ -4,8 +4,10 @@ import (
"fmt"
"regexp"
"strconv"
"strings"
"github.com/libopenstorage/openstorage/api"
"github.com/libopenstorage/openstorage/pkg/parser"
"github.com/libopenstorage/openstorage/pkg/units"
)
@@ -16,54 +18,92 @@ type SpecHandler interface {
// If the scheduler was unable to pass in the volume spec via the API,
// the spec can be passed in via the name in the format:
// "key=value;key=value;name=volname"
// source is populated if key parent=<volume_id> is specified.
// If the spec was parsed, it returns:
// (true, parsed_spec, parsed_name)
// (true, parsed_spec, locator, source, parsed_name)
// If the input string didn't contain the string, it returns:
// (false, DefaultSpec(), inputString)
SpecFromString(inputString string) (bool, *api.VolumeSpec, string)
// (false, DefaultSpec(), nil, nil, inputString)
SpecFromString(inputString string) (
bool,
*api.VolumeSpec,
*api.VolumeLocator,
*api.Source,
string,
)
// SpecFromOpts parses in docker options passed in the the docker run
// command of the form --opt name=value
// source is populated if --opt parent=<volume_id> is specified.
// If the options are validated then it returns:
// (resultant_VolumeSpec, nil)
// (resultant_VolumeSpec, source, locator, nil)
// If the options have invalid values then it returns:
// (nil, error)
// (nil, nil, nil, error)
SpecFromOpts(opts map[string]string) (
*api.VolumeSpec,
*api.VolumeLocator,
*api.Source,
error,
)
// UpdateSpecFromOpts parses in volume options passed through the opts map and updates given spec, locator & source
// If the options are validated then it returns:
// (resultant_VolumeSpec, source, locator, nil)
// If the options have invalid values then it returns:
// (nil, nil, nil, error)
UpdateSpecFromOpts(opts map[string]string, spec *api.VolumeSpec, locator *api.VolumeLocator, source *api.Source) (
*api.VolumeSpec,
*api.VolumeLocator,
*api.Source,
error,
)
SpecFromOpts(opts map[string]string) (*api.VolumeSpec, error)
// Returns a default VolumeSpec if no docker options or string encoding
// was provided.
DefaultSpec() *api.VolumeSpec
}
var (
nameRegex = regexp.MustCompile(api.Name + "=([0-9A-Za-z]+),?")
nameRegex = regexp.MustCompile(api.Name + "=([0-9A-Za-z_-]+),?")
nodesRegex = regexp.MustCompile(api.SpecNodes + "=([0-9A-Za-z_-]+),?")
sizeRegex = regexp.MustCompile(api.SpecSize + "=([0-9A-Za-z]+),?")
scaleRegex = regexp.MustCompile(api.SpecScale + "=([0-9A-Za-z]+),?")
scaleRegex = regexp.MustCompile(api.SpecScale + "=([0-9]+),?")
fsRegex = regexp.MustCompile(api.SpecFilesystem + "=([0-9A-Za-z]+),?")
bsRegex = regexp.MustCompile(api.SpecBlockSize + "=([0-9]+),?")
haRegex = regexp.MustCompile(api.SpecHaLevel + "=([0-9]+),?")
cosRegex = regexp.MustCompile(api.SpecPriority + "=([A-Za-z]+),?")
sharedRegex = regexp.MustCompile(api.SpecShared + "=([A-Za-z]+),?")
passphraseRegex = regexp.MustCompile(api.SpecPassphrase + "=([0-9A-Za-z_@./#&+-]+),?")
stickyRegex = regexp.MustCompile(api.SpecSticky + "=([A-Za-z]+),?")
secureRegex = regexp.MustCompile(api.SpecSecure + "=([A-Za-z]+),?")
zonesRegex = regexp.MustCompile(api.SpecZones + "=([A-Za-z]+),?")
racksRegex = regexp.MustCompile(api.SpecRacks + "=([A-Za-z]+),?")
aggrRegex = regexp.MustCompile(api.SpecAggregationLevel + "=([0-9]+|" +
api.SpecAutoAggregationValue + "),?")
compressedRegex = regexp.MustCompile(api.SpecCompressed + "=([A-Za-z]+),?")
snapScheduleRegex = regexp.MustCompile(api.SpecSnapshotSchedule +
`=([A-Za-z0-9:;@=#]+),?`)
)
type specHandler struct {
}
// NewSpecHandler returns a new SpecHandler interface
func NewSpecHandler() SpecHandler {
return &specHandler{}
}
func (d *specHandler) cosLevel(cos string) (uint32, error) {
func (d *specHandler) cosLevel(cos string) (api.CosType, error) {
cos = strings.ToLower(cos)
switch cos {
case "high", "3":
return uint32(api.CosType_HIGH), nil
return api.CosType_HIGH, nil
case "medium", "2":
return uint32(api.CosType_MEDIUM), nil
return api.CosType_MEDIUM, nil
case "low", "1", "":
return uint32(api.CosType_LOW), nil
return api.CosType_LOW, nil
}
return uint32(api.CosType_LOW),
return api.CosType_NONE,
fmt.Errorf("Cos must be one of %q | %q | %q", "high", "medium", "low")
}
@@ -91,30 +131,58 @@ func (d *specHandler) DefaultSpec() *api.VolumeSpec {
}
}
func (d *specHandler) SpecFromOpts(
opts map[string]string,
) (*api.VolumeSpec, error) {
spec := d.DefaultSpec()
func (d *specHandler) UpdateSpecFromOpts(opts map[string]string, spec *api.VolumeSpec, locator *api.VolumeLocator,
source *api.Source) (*api.VolumeSpec, *api.VolumeLocator, *api.Source, error) {
nodeList := make([]string, 0)
if spec == nil {
spec = d.DefaultSpec()
}
if source == nil {
source = &api.Source{}
}
if locator == nil {
locator = &api.VolumeLocator{
VolumeLabels: make(map[string]string),
}
}
for k, v := range opts {
switch k {
case api.SpecNodes:
inputNodes := strings.Split(v, ",")
for _, node := range inputNodes {
if len(node) != 0 {
nodeList = append(nodeList, node)
}
}
spec.ReplicaSet = &api.ReplicaSet{Nodes: nodeList}
case api.SpecParent:
source.Parent = v
case api.SpecEphemeral:
spec.Ephemeral, _ = strconv.ParseBool(v)
case api.SpecSize:
if size, err := units.Parse(v); err != nil {
return nil, err
return nil, nil, nil, err
} else {
spec.Size = uint64(size)
}
case api.SpecScale:
if scale, err := strconv.ParseUint(v, 10, 64); err == nil {
spec.Scale = uint32(scale)
}
case api.SpecFilesystem:
if value, err := api.FSTypeSimpleValueOf(v); err != nil {
return nil, err
return nil, nil, nil, err
} else {
spec.Format = value
}
case api.SpecBlockSize:
if blockSize, err := units.Parse(v); err != nil {
return nil, err
return nil, nil, nil, err
} else {
spec.BlockSize = blockSize
}
@@ -122,39 +190,108 @@ func (d *specHandler) SpecFromOpts(
haLevel, _ := strconv.ParseInt(v, 10, 64)
spec.HaLevel = haLevel
case api.SpecPriority:
cos, _ := api.CosTypeSimpleValueOf(v)
cos, err := d.cosLevel(v)
if err != nil {
return nil, nil, nil, err
}
spec.Cos = cos
case api.SpecPriorityAlias:
cos, err := d.cosLevel(v)
if err != nil {
return nil, nil, nil, err
}
spec.Cos = cos
case api.SpecDedupe:
spec.Dedupe, _ = strconv.ParseBool(v)
case api.SpecSnapshotInterval:
snapshotInterval, _ := strconv.ParseUint(v, 10, 32)
spec.SnapshotInterval = uint32(snapshotInterval)
case api.SpecSnapshotSchedule:
spec.SnapshotSchedule = v
case api.SpecAggregationLevel:
aggregationLevel, _ := strconv.ParseUint(v, 10, 32)
spec.AggregationLevel = uint32(aggregationLevel)
if v == api.SpecAutoAggregationValue {
spec.AggregationLevel = api.AutoAggregation
} else {
aggregationLevel, _ := strconv.ParseUint(v, 10, 32)
spec.AggregationLevel = uint32(aggregationLevel)
}
case api.SpecShared:
if shared, err := strconv.ParseBool(v); err != nil {
return nil, err
return nil, nil, nil, err
} else {
spec.Shared = shared
}
case api.SpecSticky:
if sticky, err := strconv.ParseBool(v); err != nil {
return nil, nil, nil, err
} else {
spec.Sticky = sticky
}
case api.SpecSecure:
if secure, err := strconv.ParseBool(v); err != nil {
return nil, nil, nil, err
} else {
spec.Encrypted = secure
}
case api.SpecPassphrase:
spec.Encrypted = true
spec.Passphrase = v
case api.SpecGroup:
spec.Group = &api.Group{Id: v}
case api.SpecGroupEnforce:
if groupEnforced, err := strconv.ParseBool(v); err != nil {
return nil, nil, nil, err
} else {
spec.GroupEnforced = groupEnforced
}
case api.SpecZones, api.SpecRacks:
locator.VolumeLabels[k] = v
case api.SpecCompressed:
if compressed, err := strconv.ParseBool(v); err != nil {
return nil, nil, nil, err
} else {
spec.Compressed = compressed
}
case api.SpecLabels:
if labels, err := parser.LabelsFromString(v); err != nil {
return nil, nil, nil, err
} else {
for k, v := range labels {
locator.VolumeLabels[k] = v
}
}
case api.SpecIoProfile:
if ioProfile, err := api.IoProfileSimpleValueOf(v); err != nil {
return nil, nil, nil, err
} else {
spec.IoProfile = ioProfile
}
default:
spec.VolumeLabels[k] = v
}
}
return spec, nil
return spec, locator, source, nil
}
func (d *specHandler) SpecFromOpts(
opts map[string]string,
) (*api.VolumeSpec, *api.VolumeLocator, *api.Source, error) {
source := &api.Source{}
locator := &api.VolumeLocator{
VolumeLabels: make(map[string]string),
}
spec := d.DefaultSpec()
return d.UpdateSpecFromOpts(opts, spec, locator, source)
}
func (d *specHandler) SpecFromString(
str string,
) (bool, *api.VolumeSpec, string) {
) (bool, *api.VolumeSpec, *api.VolumeLocator, *api.Source, string) {
// If we can't parse the name, the rest of the spec is invalid.
ok, name := d.getVal(nameRegex, str)
if !ok {
return false, d.DefaultSpec(), str
return false, d.DefaultSpec(), nil, nil, str
}
opts := make(map[string]string)
@@ -162,6 +299,9 @@ func (d *specHandler) SpecFromString(
if ok, sz := d.getVal(sizeRegex, str); ok {
opts[api.SpecSize] = sz
}
if ok, nodes := d.getVal(nodesRegex, str); ok {
opts[api.SpecNodes] = nodes
}
if ok, scale := d.getVal(scaleRegex, str); ok {
opts[api.SpecScale] = scale
}
@@ -180,13 +320,34 @@ func (d *specHandler) SpecFromString(
if ok, shared := d.getVal(sharedRegex, str); ok {
opts[api.SpecShared] = shared
}
if ok, sticky := d.getVal(stickyRegex, str); ok {
opts[api.SpecSticky] = sticky
}
if ok, secure := d.getVal(secureRegex, str); ok {
opts[api.SpecSecure] = secure
}
if ok, passphrase := d.getVal(passphraseRegex, str); ok {
opts[api.SpecPassphrase] = passphrase
}
spec, err := d.SpecFromOpts(opts)
if err != nil {
return false, d.DefaultSpec(), name
if ok, zones := d.getVal(zonesRegex, str); ok {
opts[api.SpecZones] = zones
}
return true, spec, name
if ok, racks := d.getVal(racksRegex, str); ok {
opts[api.SpecRacks] = racks
}
if ok, aggregationLvl := d.getVal(aggrRegex, str); ok {
opts[api.SpecAggregationLevel] = aggregationLvl
}
if ok, compressed := d.getVal(compressedRegex, str); ok {
opts[api.SpecCompressed] = compressed
}
if ok, sched := d.getVal(snapScheduleRegex, str); ok {
opts[api.SpecSnapshotSchedule] = strings.Replace(sched, "#", ",", -1)
}
spec, locator, source, err := d.SpecFromOpts(opts)
if err != nil {
return false, d.DefaultSpec(), nil, nil, name
}
return true, spec, locator, source, name
}

View File

@@ -1,5 +1,6 @@
package api
// StatusKind indicates the severity of a status
type StatusKind int32
const (
@@ -12,32 +13,35 @@ const (
)
var statusToStatusKind = map[Status]StatusKind{
Status_STATUS_NONE: StatusSeverityHigh,
Status_STATUS_INIT: StatusSeverityMedium,
Status_STATUS_OK: StatusSeverityLow,
Status_STATUS_OFFLINE: StatusSeverityHigh,
Status_STATUS_ERROR: StatusSeverityHigh,
Status_STATUS_NOT_IN_QUORUM: StatusSeverityHigh,
Status_STATUS_DECOMMISSION: StatusSeverityHigh,
Status_STATUS_MAINTENANCE: StatusSeverityHigh,
Status_STATUS_STORAGE_DOWN: StatusSeverityHigh,
Status_STATUS_STORAGE_DEGRADED: StatusSeverityHigh,
Status_STATUS_NEEDS_REBOOT: StatusSeverityHigh,
Status_STATUS_STORAGE_REBALANCE: StatusSeverityMedium,
Status_STATUS_STORAGE_DRIVE_REPLACE: StatusSeverityMedium,
Status_STATUS_NONE: StatusSeverityHigh,
Status_STATUS_INIT: StatusSeverityMedium,
Status_STATUS_OK: StatusSeverityLow,
Status_STATUS_OFFLINE: StatusSeverityHigh,
Status_STATUS_ERROR: StatusSeverityHigh,
Status_STATUS_NOT_IN_QUORUM: StatusSeverityHigh,
Status_STATUS_DECOMMISSION: StatusSeverityHigh,
Status_STATUS_MAINTENANCE: StatusSeverityHigh,
Status_STATUS_STORAGE_DOWN: StatusSeverityHigh,
Status_STATUS_STORAGE_DEGRADED: StatusSeverityHigh,
Status_STATUS_NEEDS_REBOOT: StatusSeverityHigh,
Status_STATUS_STORAGE_REBALANCE: StatusSeverityMedium,
Status_STATUS_STORAGE_DRIVE_REPLACE: StatusSeverityMedium,
// Add statuses before MAX
Status_STATUS_MAX: StatusSeverityHigh,
}
// StatusSimpleValueOf returns the string format of Status
func StatusSimpleValueOf(s string) (Status, error) {
obj, err := simpleValueOf("status", Status_value, s)
return Status(obj), err
}
// SimpleString returns the string format of Status
func (x Status) SimpleString() string {
return simpleString("status", Status_name, int32(x))
}
// StatusKind returns the king of status
func (x Status) StatusKind() StatusKind {
statusType, _ := statusToStatusKind[x]
return statusType

View File

@@ -0,0 +1,21 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["labels.go"],
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,74 @@
package parser
import (
"fmt"
"strings"
)
const (
NoLabel = "NoLabel"
)
func LabelsFromString(str string) (map[string]string, error) {
if len(str) == 0 {
return nil, nil
}
labels := strings.Split(str, ",")
m := make(map[string]string, len(labels))
for _, v := range labels {
if strings.Contains(v, "=") {
label := strings.SplitN(v, "=", 2)
if len(label) != 2 {
return m, fmt.Errorf("Malformed label: %s", v)
}
if _, ok := m[label[0]]; ok {
return m, fmt.Errorf("Duplicate label: %s", v)
}
m[label[0]] = label[1]
} else if len(v) != 0 {
m[v] = ""
}
}
return m, nil
}
func LabelsToString(labels map[string]string) string {
l := ""
for k, v := range labels {
if len(l) != 0 {
l += ","
}
if len(v) != 0 {
l += k + "=" + v
} else if len(k) != 0 {
l += k
}
}
return l
}
func MergeLabels(old map[string]string, new map[string]string) map[string]string {
if old == nil {
return new
}
if new == nil {
return old
}
m := make(map[string]string, len(old)+len(new))
for k, v := range old {
m[k] = v
}
for k, v := range new {
m[k] = v
}
return m
}
func HasLabels(set map[string]string, subset map[string]string) bool {
for k, v1 := range subset {
if v2, ok := set[k]; !ok || v1 != v2 {
return false
}
}
return true
}

View File

@@ -40,16 +40,16 @@ var (
"B": 1,
"b": 1,
"KB": KB,
"kb": KB,
"MB": MB,
"mb": MB,
"GB": GB,
"gb": GB,
"TB": TB,
"tb": TB,
"PB": PB,
"pb": PB,
"KB": KiB,
"kb": KiB,
"MB": MiB,
"mb": MiB,
"GB": GiB,
"gb": GiB,
"TB": TiB,
"tb": TiB,
"PB": PiB,
"pb": PiB,
"K": KiB,
"k": KiB,

View File

@@ -7,30 +7,67 @@ import (
)
var (
ErrAlreadyShutdown = errors.New("VolumeDriverProvider already shutdown")
ErrExist = errors.New("Driver already exists")
ErrDriverNotFound = errors.New("Driver implementation not found")
ErrDriverInitializing = errors.New("Driver is initializing")
ErrEnoEnt = errors.New("Volume does not exist.")
ErrEnomem = errors.New("Out of memory.")
ErrEinval = errors.New("Invalid argument")
ErrVolDetached = errors.New("Volume is detached")
ErrVolAttached = errors.New("Volume is attached")
// ErrAlreadyShutdown returned when driver is shutdown
ErrAlreadyShutdown = errors.New("VolumeDriverProvider already shutdown")
// ErrExit returned when driver already registered
ErrExist = errors.New("Already exists")
// ErrDriverNotFound returned when a driver is not registered
ErrDriverNotFound = errors.New("Driver implementation not found")
// ErrDriverInitializing returned when a driver is initializing
ErrDriverInitializing = errors.New("Driver is initializing")
// ErrEnoEnt returned when volume does not exist
ErrEnoEnt = errors.New("Volume does not exist.")
// ErrEnomem returned when we are out of memory
ErrEnomem = errors.New("Out of memory.")
// ErrEinval returned when an invalid input is provided
ErrEinval = errors.New("Invalid argument")
// ErrVolDetached returned when volume is in detached state
ErrVolDetached = errors.New("Volume is detached")
// ErrVolAttached returned when volume is in attached state
ErrVolAttached = errors.New("Volume is attached")
// ErrVolAttachedOnRemoteNode returned when volume is in attached on different node
ErrVolAttachedOnRemoteNode = errors.New("Volume is attached on another node")
ErrVolAttachedScale = errors.New("Volume is attached but can be scaled")
ErrVolHasSnaps = errors.New("Volume has snapshots associated")
ErrNotSupported = errors.New("Operation not supported")
// ErrVolAttachedScale returned when volume is attached and can be scaled
ErrVolAttachedScale = errors.New("Volume is attached on another node." +
" Increase scale factor to create more instances")
// ErrVolHasSnaps returned when volume has previous snapshots
ErrVolHasSnaps = errors.New("Volume has snapshots associated")
// ErrNotSupported returned when the operation is not supported
ErrNotSupported = errors.New("Operation not supported")
// ErrVolBusy returned when volume is in busy state
ErrVolBusy = errors.New("Volume is busy")
)
// Constants used by the VolumeDriver
const (
APIVersion = "v1"
// APIVersion for the volume management apis
APIVersion = "v1"
// PluginAPIBase where the docker unix socket resides
PluginAPIBase = "/run/docker/plugins/"
// DriverAPIBase where the osd unix socket resides
DriverAPIBase = "/var/lib/osd/driver/"
MountBase = "/var/lib/osd/mounts/"
VolumeBase = "/var/lib/osd/"
// MountBase for osd mountpoints
MountBase = "/var/lib/osd/mounts/"
// VolumeBase for osd volumes
VolumeBase = "/var/lib/osd/"
)
const (
// LocationConstaint is a label that specifies data location constraint.
LocationConstraint = "LocationConstraint"
// LocalNode is an alias for this node - similar to localhost.
LocalNode = "LocalNode"
)
// AttachOptionsKey specifies a key type from a key-value pair
// that will be passed in to the Attach api
type AttachOptionsKey string
const (
AttachOptionsSecret = AttachOptionsKey("SECRET_KEY")
)
// Store defines the interface for basic volume store operations
type Store interface {
// Lock volume specified by volumeID.
Lock(volumeID string) (interface{}, error)
@@ -68,16 +105,34 @@ type IODriver interface {
Flush(volumeID string) error
}
// SnapshotDriver interfaces provides snapshot capability
type SnapshotDriver interface {
// Snapshot create volume snapshot.
// Errors ErrEnoEnt may be returned
Snapshot(volumeID string, readonly bool, locator *api.VolumeLocator) (string, error)
// Restore restores volume to specified snapshot.
Restore(volumeID string, snapshotID string) error
}
// StatsDriver interface provides stats features
type StatsDriver interface {
// Stats for specified volume.
// cumulative stats are /proc/diskstats style stats.
// nonCumulative stats are stats for specific duration.
// Errors ErrEnoEnt may be returned
Stats(volumeID string, cumulative bool) (*api.Stats, error)
// UsedSize returns currently used volume size.
// Errors ErrEnoEnt may be returned.
UsedSize(volumeID string) (uint64, error)
// GetActiveRequests get active requests
GetActiveRequests() (*api.ActiveRequests, error)
}
// ProtoDriver must be implemented by all volume drivers. It specifies the
// most basic functionality, such as creating and deleting volumes.
type ProtoDriver interface {
SnapshotDriver
StatsDriver
// Name returns the name of the driver.
Name() string
// Type of this driver
@@ -99,16 +154,6 @@ type ProtoDriver interface {
// Update not all fields of the spec are supported, ErrNotSupported will be thrown for unsupported
// updates.
Set(volumeID string, locator *api.VolumeLocator, spec *api.VolumeSpec) error
// Stats for specified volume.
// cumulative stats are /proc/diskstats style stats.
// nonCumulative stats are stats for specific duration.
// Errors ErrEnoEnt may be returned
Stats(volumeID string, cumulative bool) (*api.Stats, error)
// Alerts on this volume.
// Errors ErrEnoEnt may be returned
Alerts(volumeID string) (*api.Alerts, error)
// GetActiveRequests get active requests
GetActiveRequests() (*api.ActiveRequests, error)
// Status returns a set of key-value pairs which give low
// level diagnostic status about this driver.
Status() [][2]string
@@ -128,6 +173,7 @@ type Enumerator interface {
SnapEnumerate(volID []string, snapLabels map[string]string) ([]*api.Volume, error)
}
// StoreEnumerator combines Store and Enumerator capabilities
type StoreEnumerator interface {
Store
Enumerator
@@ -139,10 +185,10 @@ type BlockDriver interface {
// Attach map device to the host.
// On success the devicePath specifies location where the device is exported
// Errors ErrEnoEnt, ErrVolAttached may be returned.
Attach(volumeID string) (string, error)
Attach(volumeID string, attachOptions map[string]string) (string, error)
// Detach device from the host.
// Errors ErrEnoEnt, ErrVolDetached may be returned.
Detach(volumeID string) error
Detach(volumeID string, unmountBeforeDetach bool) error
}
// VolumeDriverProvider provides VolumeDrivers.
@@ -165,7 +211,7 @@ type VolumeDriverRegistry interface {
Add(name string, init func(map[string]string) (VolumeDriver, error)) error
}
// VolumeDriverRegistry constructs a new VolumeDriverRegistry.
// NewVolumeDriverRegistry constructs a new VolumeDriverRegistry.
func NewVolumeDriverRegistry(nameToInitFunc map[string]func(map[string]string) (VolumeDriver, error)) VolumeDriverRegistry {
return newVolumeDriverRegistry(nameToInitFunc)
}

View File

@@ -8,19 +8,24 @@ var (
// BlockNotSupported is a default (null) block driver implementation. This can be
// used by drivers that do not want to (or care about) implementing the attach,
// format and detach interfaces.
BlockNotSupported = &blockNotSupported{}
BlockNotSupported = &blockNotSupported{}
// SnapshotNotSupported is a null snapshot driver implementation. This can be used
// by drivers that do not want to implement the snapshot interface
SnapshotNotSupported = &snapshotNotSupported{}
IONotSupported = &ioNotSupported{}
// IONotSupported is a null IODriver interface
IONotSupported = &ioNotSupported{}
// StatsNotSupported is a null stats driver implementation. This can be used
// by drivers that do not want to implement the stats interface.
StatsNotSupported = &statsNotSupported{}
)
type blockNotSupported struct{}
func (b *blockNotSupported) Attach(volumeID string) (string, error) {
func (b *blockNotSupported) Attach(volumeID string, attachOptions map[string]string) (string, error) {
return "", ErrNotSupported
}
func (b *blockNotSupported) Detach(volumeID string) error {
func (b *blockNotSupported) Detach(volumeID string, unmountBeforeDetach bool) error {
return ErrNotSupported
}
@@ -30,6 +35,10 @@ func (s *snapshotNotSupported) Snapshot(volumeID string, readonly bool, locator
return "", ErrNotSupported
}
func (s *snapshotNotSupported) Restore(volumeID, snapshotID string) error {
return ErrNotSupported
}
type ioNotSupported struct{}
func (i *ioNotSupported) Read(volumeID string, buffer []byte, size uint64, offset int64) (int64, error) {
@@ -43,3 +52,23 @@ func (i *ioNotSupported) Write(volumeID string, buffer []byte, size uint64, offs
func (i *ioNotSupported) Flush(volumeID string) error {
return ErrNotSupported
}
type statsNotSupported struct{}
// Stats returns stats
func (s *statsNotSupported) Stats(
volumeID string,
cumulative bool,
) (*api.Stats, error) {
return nil, ErrNotSupported
}
// UsedSize returns allocated size
func (s *statsNotSupported) UsedSize(volumeID string) (uint64, error) {
return 0, ErrNotSupported
}
// GetActiveRequests gets active requests
func (s *statsNotSupported) GetActiveRequests() (*api.ActiveRequests, error) {
return nil, nil
}