Merge pull request #52132 from portworx/kubelet_weird_output_fix

Automatic merge from submit-queue (batch tested with PRs 51064, 52132). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>..

Kubelet weird output fix

**What this PR does / why we need it**:
All kube binaries print the following message at the top when executed:
```
2017/08/28 21:37:12 proto: duplicate proto type registered: google.protobuf.Any
2017/08/28 21:37:12 proto: duplicate proto type registered: google.protobuf.Duration
2017/08/28 21:37:12 proto: duplicate proto type registered: google.protobuf.Timestamp
```
This PR addresses the above issue
It involves the following two changes:
1. Updating vendor packages
- Removes everything under the repo ``go.pedge.io``
- Updates repo libopenstorage/openstorage (which was using the above package)
2. Updates the portworx volume native driver to adhere to the newly vendor'ed code.



**Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: 

fixes #51452

**Special notes for your reviewer**:
I have divided the changes into 2 commits
1. Vendor'ed changes
2. Changes in portworx volume driver.

```release-note
Remove duplicate proto errors in kubelet.
```
This commit is contained in:
Kubernetes Submit Queue
2017-09-20 14:32:59 -07:00
committed by GitHub
40 changed files with 1973 additions and 2367 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
}

26
vendor/github.com/mohae/deepcopy/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,26 @@
# 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
*~
*.out
*.log

11
vendor/github.com/mohae/deepcopy/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,11 @@
language: go
go:
- tip
matrix:
allow_failures:
- go: tip
script:
- go test ./...

21
vendor/github.com/mohae/deepcopy/BUILD generated vendored Normal file
View File

@@ -0,0 +1,21 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["deepcopy.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"],
)

21
vendor/github.com/mohae/deepcopy/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Joel
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.

8
vendor/github.com/mohae/deepcopy/README.md generated vendored Normal file
View File

@@ -0,0 +1,8 @@
deepCopy
========
[![GoDoc](https://godoc.org/github.com/mohae/deepcopy?status.svg)](https://godoc.org/github.com/mohae/deepcopy)[![Build Status](https://travis-ci.org/mohae/deepcopy.png)](https://travis-ci.org/mohae/deepcopy)
DeepCopy makes deep copies of things: unexported field values are not copied.
## Usage
cpy := deepcopy.Copy(orig)

112
vendor/github.com/mohae/deepcopy/deepcopy.go generated vendored Normal file
View File

@@ -0,0 +1,112 @@
// deepcopy makes deep copies of things. A standard copy will copy the
// pointers: deep copy copies the values pointed to. Unexported field
// values are not copied.
//
// Copyright (c)2014-2016, Joel Scoble (github.com/mohae), all rights reserved.
// License: MIT, for more details check the included LICENSE file.
package deepcopy
import (
"reflect"
"time"
)
// Iface is an alias to Copy; this exists for backwards compatibility reasons.
func Iface(iface interface{}) interface{} {
return Copy(iface)
}
// Copy creates a deep copy of whatever is passed to it and returns the copy
// in an interface{}. The returned value will need to be asserted to the
// correct type.
func Copy(src interface{}) interface{} {
if src == nil {
return nil
}
// Make the interface a reflect.Value
original := reflect.ValueOf(src)
// Make a copy of the same type as the original.
cpy := reflect.New(original.Type()).Elem()
// Recursively copy the original.
copyRecursive(original, cpy)
// Return the copy as an interface.
return cpy.Interface()
}
// copyRecursive does the actual copying of the interface. It currently has
// limited support for what it can handle. Add as needed.
func copyRecursive(original, cpy reflect.Value) {
// handle according to original's Kind
switch original.Kind() {
case reflect.Ptr:
// Get the actual value being pointed to.
originalValue := original.Elem()
// if it isn't valid, return.
if !originalValue.IsValid() {
return
}
cpy.Set(reflect.New(originalValue.Type()))
copyRecursive(originalValue, cpy.Elem())
case reflect.Interface:
// If this is a nil, don't do anything
if original.IsNil() {
return
}
// Get the value for the interface, not the pointer.
originalValue := original.Elem()
// Get the value by calling Elem().
copyValue := reflect.New(originalValue.Type()).Elem()
copyRecursive(originalValue, copyValue)
cpy.Set(copyValue)
case reflect.Struct:
t, ok := original.Interface().(time.Time)
if ok {
cpy.Set(reflect.ValueOf(t))
return
}
// Go through each field of the struct and copy it.
for i := 0; i < original.NumField(); i++ {
// The Type's StructField for a given field is checked to see if StructField.PkgPath
// is set to determine if the field is exported or not because CanSet() returns false
// for settable fields. I'm not sure why. -mohae
if original.Type().Field(i).PkgPath != "" {
continue
}
copyRecursive(original.Field(i), cpy.Field(i))
}
case reflect.Slice:
if original.IsNil() {
return
}
// Make a new slice and copy each element.
cpy.Set(reflect.MakeSlice(original.Type(), original.Len(), original.Cap()))
for i := 0; i < original.Len(); i++ {
copyRecursive(original.Index(i), cpy.Index(i))
}
case reflect.Map:
if original.IsNil() {
return
}
cpy.Set(reflect.MakeMap(original.Type()))
for _, key := range original.MapKeys() {
originalValue := original.MapIndex(key)
copyValue := reflect.New(originalValue.Type()).Elem()
copyRecursive(originalValue, copyValue)
copyKey := Copy(key.Interface())
cpy.SetMapIndex(reflect.ValueOf(copyKey), copyValue)
}
default:
cpy.Set(original)
}
}