Skip to content

Commit

Permalink
Attachments Bitmask & Updated Docs
Browse files Browse the repository at this point in the history
This patch updates the "attachments" parameter used when retrieving
volumes from a boolean flag to a more discreet bitmask. This patch
also includes updated APIB documentation.
  • Loading branch information
akutz committed Nov 1, 2016
1 parent bbdb230 commit 853a2e1
Show file tree
Hide file tree
Showing 27 changed files with 771 additions and 363 deletions.
6 changes: 3 additions & 3 deletions api/client/client_api_funcs.go
Expand Up @@ -84,7 +84,7 @@ func (c *client) ServiceInspect(

func (c *client) Volumes(
ctx types.Context,
attachments bool) (types.ServiceVolumeMap, error) {
attachments types.VolumeAttachmentsTypes) (types.ServiceVolumeMap, error) {

reply := types.ServiceVolumeMap{}
url := fmt.Sprintf("/volumes?attachments=%v", attachments)
Expand All @@ -97,7 +97,7 @@ func (c *client) Volumes(
func (c *client) VolumesByService(
ctx types.Context,
service string,
attachments bool) (types.VolumeMap, error) {
attachments types.VolumeAttachmentsTypes) (types.VolumeMap, error) {

reply := types.VolumeMap{}
url := fmt.Sprintf("/volumes/%s?attachments=%v", service, attachments)
Expand All @@ -110,7 +110,7 @@ func (c *client) VolumesByService(
func (c *client) VolumeInspect(
ctx types.Context,
service, volumeID string,
attachments bool) (*types.Volume, error) {
attachments types.VolumeAttachmentsTypes) (*types.Volume, error) {

reply := types.Volume{}
url := fmt.Sprintf(
Expand Down
35 changes: 19 additions & 16 deletions api/server/router/volume/volume_routes.go
Expand Up @@ -34,7 +34,7 @@ func (r *router) volumes(
tasks = map[string]*types.Task{}
taskIDs []int
opts = &types.VolumesOpts{
Attachments: store.GetBool("attachments"),
Attachments: store.GetAttachments(),
Opts: store,
}
reply = types.ServiceVolumeMap{}
Expand Down Expand Up @@ -107,7 +107,7 @@ func (r *router) volumesForService(
service := context.MustService(ctx)

opts := &types.VolumesOpts{
Attachments: store.GetBool("attachments"),
Attachments: store.GetAttachments(),
Opts: store,
}

Expand Down Expand Up @@ -143,7 +143,7 @@ func getFilteredVolumes(
)

iid, iidOK := context.InstanceID(ctx)
if opts.Attachments && !iidOK {
if opts.Attachments.RequiresInstanceID() && !iidOK {
return nil, utils.NewMissingInstanceIDError(storSvc.Name())
}

Expand All @@ -152,11 +152,6 @@ func getFilteredVolumes(
return nil, err
}

lcaseIID := ""
if iid != nil {
lcaseIID = strings.ToLower(iid.ID)
}

if filter != nil {
filterOp = filter.Op
filterLeft = strings.ToLower(filter.Left)
Expand All @@ -166,22 +161,29 @@ func getFilteredVolumes(
for _, obj := range objs {

if filterOp == types.FilterEqualityMatch && filterLeft == "name" {
if strings.ToLower(obj.Name) != filterRight {
if !strings.EqualFold(obj.Name, filterRight) {
continue
}
}

if opts.Attachments {
// if only the requesting instance's attachments are requested then
// filter the volume's attachments list
if opts.Attachments.Mine() {
atts := []*types.VolumeAttachment{}
for _, a := range obj.Attachments {
if lcaseIID == strings.ToLower(a.InstanceID.ID) {
if strings.EqualFold(iid.ID, a.InstanceID.ID) {
atts = append(atts, a)
}
}
obj.Attachments = atts
if len(obj.Attachments) == 0 {
continue
}
}

if opts.Attachments.Attached() && len(obj.Attachments) == 0 {
continue
}

if opts.Attachments.Unattached() && len(obj.Attachments) > 0 {
continue
}

if OnVolume != nil {
Expand All @@ -207,10 +209,11 @@ func (r *router) volumeInspect(
req *http.Request,
store types.Store) error {

attachments := store.GetBool("attachments")
attachments := store.GetAttachments()

service := context.MustService(ctx)
if _, ok := context.InstanceID(ctx); !ok && attachments {
if _, ok := context.InstanceID(ctx); !ok &&
attachments.RequiresInstanceID() {
return utils.NewMissingInstanceIDError(service.Name())
}

Expand Down
6 changes: 3 additions & 3 deletions api/types/types_clients.go
Expand Up @@ -106,19 +106,19 @@ type APIClient interface {
// Volumes returns a list of all Volumes for all Services.
Volumes(
ctx Context,
attachments bool) (ServiceVolumeMap, error)
attachments VolumeAttachmentsTypes) (ServiceVolumeMap, error)

// VolumesByService returns a list of all Volumes for a service.
VolumesByService(
ctx Context,
service string,
attachments bool) (VolumeMap, error)
attachments VolumeAttachmentsTypes) (VolumeMap, error)

// VolumeInspect gets information about a single volume.
VolumeInspect(
ctx Context,
service, volumeID string,
attachments bool) (*Volume, error)
attachments VolumeAttachmentsTypes) (*Volume, error)

// VolumeCreate creates a single volume.
VolumeCreate(
Expand Down
4 changes: 3 additions & 1 deletion api/types/types_drivers_client.go
Expand Up @@ -32,7 +32,9 @@ type ClientDriver interface {

// VolumeInspectBefore may return an error, preventing the operation.
VolumeInspectBefore(
ctx *Context, service, volumeID string, attachments bool) error
ctx *Context,
service, volumeID string,
attachments VolumeAttachmentsTypes) error

// VolumeInspectAfter provides an opportunity to inspect/mutate the result.
VolumeInspectAfter(ctx Context, result *Volume)
Expand Down
133 changes: 131 additions & 2 deletions api/types/types_drivers_storage.go
@@ -1,20 +1,149 @@
package types

import "strconv"

// LibStorageDriverName is the name of the libStorage storage driver.
const LibStorageDriverName = "libstorage"

// NewStorageDriver is a function that constructs a new StorageDriver.
type NewStorageDriver func() StorageDriver

// VolumeAttachmentsTypes is the type of the volume attachments bitmask.
type VolumeAttachmentsTypes int

const (

// VolumeAttachmentsRequested indicates attachment information is requested.
VolumeAttachmentsRequested VolumeAttachmentsTypes = 1 << iota // 1

// VolumeAttachmentsMine indicates attachment information should
// be returned for volumes attached to the instance specified in the
// instance ID request header. If this bit is set then the instance ID
// header is required.
VolumeAttachmentsMine // 2

// VolumeAttachmentsDevices indicates an attempt should made to map devices
// provided via the local devices request header to the appropriate
// attachment information. If this bit is set then the instance ID and
// local device headers are required.
VolumeAttachmentsDevices // 4

// VolumeAttachmentsAttached indicates only volumes that are attached
// should be returned.
VolumeAttachmentsAttached // 8

// VolumeAttachmentsUnattached indicates only volumes that are unattached
// should be returned.
VolumeAttachmentsUnattached // 16
)

const (
// VolumeAttachmentsNone specifies no attachment information is requested.
// This is the default value and the same as omitting this parameter
// altogether.
VolumeAttachmentsNone VolumeAttachmentsTypes = 0

// VolumeAttachmentsFalse is an alias for VolumeAttachmentsNone.
VolumeAttachmentsFalse = VolumeAttachmentsNone

// VolumeAttachmentsTrue is a mask of
// VolumeAttachmentsRequested | VolumeAttachmentsMine |
// VolumeAttachmentsDevices | VolumeAttachmentsAttached
VolumeAttachmentsTrue = VolumeAttachmentsRequested |
VolumeAttachmentsMine | VolumeAttachmentsDevices |
VolumeAttachmentsAttached
)

// ParseVolumeAttachmentTypes parses a value into a VolumeAttachmentsTypes
// value.
func ParseVolumeAttachmentTypes(v interface{}) VolumeAttachmentsTypes {
switch tv := v.(type) {
case VolumeAttachmentsTypes:
return tv
case bool:
if tv {
return VolumeAttachmentsTrue
}
return VolumeAttachmentsRequested
case int:
return VolumeAttachmentsTypes(tv)
case uint:
return VolumeAttachmentsTypes(tv)
case int8:
return VolumeAttachmentsTypes(tv)
case uint8:
return VolumeAttachmentsTypes(tv)
case int16:
return VolumeAttachmentsTypes(tv)
case uint16:
return VolumeAttachmentsTypes(tv)
case int32:
return VolumeAttachmentsTypes(tv)
case uint32:
return VolumeAttachmentsTypes(tv)
case int64:
return VolumeAttachmentsTypes(tv)
case uint64:
return VolumeAttachmentsTypes(tv)
case string:
if i, err := strconv.ParseInt(tv, 10, 64); err == nil {
return ParseVolumeAttachmentTypes(i)
}
if b, err := strconv.ParseBool(tv); err == nil {
return ParseVolumeAttachmentTypes(b)
}
}
return VolumeAttachmentsNone
}

// RequiresInstanceID returns a flag that indicates whether the attachment
// bit requires an instance ID to perform successfully.
func (v VolumeAttachmentsTypes) RequiresInstanceID() bool {
return v.Mine() || v.Devices()
}

// Requested returns a flag that indicates attachment information is requested.
func (v VolumeAttachmentsTypes) Requested() bool {
return v&VolumeAttachmentsRequested > 0
}

// Mine returns a flag that indicates attachment information should
// be returned for volumes attached to the instance specified in the
// instance ID request header. If this bit is set then the instance ID
// header is required.
func (v VolumeAttachmentsTypes) Mine() bool {
return v&VolumeAttachmentsMine > 0
}

// Devices returns a flag that indicates an attempt should made to map devices
// provided via the local devices request header to the appropriate
// attachment information. If this bit is set then the instance ID and
// local device headers are required.
func (v VolumeAttachmentsTypes) Devices() bool {
return v&VolumeAttachmentsDevices > 0
}

// Attached returns a flag that indicates only volumes that are attached should
// be returned.
func (v VolumeAttachmentsTypes) Attached() bool {
return v&VolumeAttachmentsAttached > 0
}

// Unattached returns a flag that indicates only volumes that are unattached
// should be returned.
func (v VolumeAttachmentsTypes) Unattached() bool {
return v&VolumeAttachmentsUnattached > 0
}

// VolumesOpts are options when inspecting a volume.
type VolumesOpts struct {
Attachments bool
Attachments VolumeAttachmentsTypes
Opts Store
}

// VolumeInspectOpts are options when inspecting a volume.
type VolumeInspectOpts struct {
Attachments bool
Attachments VolumeAttachmentsTypes
Opts Store
}

Expand Down
85 changes: 85 additions & 0 deletions api/types/types_drivers_storage_test.go
@@ -0,0 +1,85 @@
package types

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestVolumeAttachmentsTypes(t *testing.T) {
var a VolumeAttachmentsTypes
assert.False(t, a.Requested())
assert.False(t, a.Mine())
assert.False(t, a.Devices())
assert.False(t, a.Attached())

a = VolumeAttachmentsTypes(5)
assert.True(t, a.Requested())
assert.False(t, a.Mine())
assert.True(t, a.Devices())
assert.False(t, a.Attached())

a = VolumeAttachmentsTypes(9)
assert.True(t, a.Requested())
assert.False(t, a.Mine())
assert.False(t, a.Devices())
assert.True(t, a.Attached())

a = VolumeAttachmentsTypes(13)
assert.True(t, a.Requested())
assert.False(t, a.Mine())
assert.True(t, a.Devices())
assert.True(t, a.Attached())
}

func TestParseVolumeAttachmentsTypes(t *testing.T) {
var a VolumeAttachmentsTypes
assert.False(t, a.Requested())
assert.False(t, a.Mine())
assert.False(t, a.Devices())
assert.False(t, a.Attached())

a = ParseVolumeAttachmentTypes("true")
assert.True(t, a.Requested())
assert.True(t, a.Mine())
assert.True(t, a.Devices())
assert.True(t, a.Attached())
a = ParseVolumeAttachmentTypes(true)
assert.True(t, a.Requested())
assert.True(t, a.Mine())
assert.True(t, a.Devices())
assert.True(t, a.Attached())

a = ParseVolumeAttachmentTypes("5")
assert.True(t, a.Requested())
assert.False(t, a.Mine())
assert.True(t, a.Devices())
assert.False(t, a.Attached())
a = ParseVolumeAttachmentTypes(5)
assert.True(t, a.Requested())
assert.False(t, a.Mine())
assert.True(t, a.Devices())
assert.False(t, a.Attached())

a = ParseVolumeAttachmentTypes("9")
assert.True(t, a.Requested())
assert.False(t, a.Mine())
assert.False(t, a.Devices())
assert.True(t, a.Attached())
a = ParseVolumeAttachmentTypes(9)
assert.True(t, a.Requested())
assert.False(t, a.Mine())
assert.False(t, a.Devices())
assert.True(t, a.Attached())

a = ParseVolumeAttachmentTypes("13")
assert.True(t, a.Requested())
assert.False(t, a.Mine())
assert.True(t, a.Devices())
assert.True(t, a.Attached())
a = ParseVolumeAttachmentTypes(13)
assert.True(t, a.Requested())
assert.False(t, a.Mine())
assert.True(t, a.Devices())
assert.True(t, a.Attached())
}

0 comments on commit 853a2e1

Please sign in to comment.