Skip to content

Commit

Permalink
VMware vSphere Driver
Browse files Browse the repository at this point in the history
This patch introduces the new VMware vSphere VMDK Driver - "vmdk".
The driver uses VMCI Sockets
(https://www.vmware.com/support/developer/vmci-sdk/)
to communicate directly with a vSphere host, removing the need
for the sizeable VMware SDK for Go library dependency.
  • Loading branch information
akutz committed Apr 26, 2017
1 parent c676347 commit 8af504f
Show file tree
Hide file tree
Showing 13 changed files with 571 additions and 54 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*.d
*.out
got
gob
libstorage.paw
.site/
site/
Expand Down
67 changes: 67 additions & 0 deletions drivers/storage/vmdk/executor/vmdk_executor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// +build linux darwin
// +build !libstorage_storage_executor libstorage_storage_executor_vmdk

package executor

import (
gofig "github.com/akutz/gofig/types"

"github.com/codedellemc/libstorage/api/registry"
"github.com/codedellemc/libstorage/api/types"

"github.com/codedellemc/libstorage/drivers/storage/vmdk"
)

type driver struct {
config gofig.Config
}

func init() {
registry.RegisterStorageExecutor(vmdk.Name, newDriver)
}

func newDriver() types.StorageExecutor {
return &driver{}
}

func (d *driver) Name() string {
return vmdk.Name
}

func (d *driver) Supported(
ctx types.Context,
opts types.Store) (bool, error) {

return true, nil
}

func (d *driver) Init(ctx types.Context, config gofig.Config) error {
d.config = config
return nil
}

// InstanceID returns the local system's InstanceID.
func (d *driver) InstanceID(
ctx types.Context,
opts types.Store) (*types.InstanceID, error) {

iid := &types.InstanceID{Driver: vmdk.Name}
iid.ID = vmdk.Name
return iid, nil
}

// NextDevice returns the next available device.
func (d *driver) NextDevice(
ctx types.Context,
opts types.Store) (string, error) {

return "", nil
}

// LocalDevices returns a map of the system's local devices.
func (d *driver) LocalDevices(
ctx types.Context,
opts *types.LocalDevicesOpts) (*types.LocalDevices, error) {

return &types.LocalDevices{DeviceMap: map[string]string{}}, nil
}
278 changes: 278 additions & 0 deletions drivers/storage/vmdk/storage/vmdk_storage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
// +build !libstorage_storage_driver libstorage_storage_driver_vmdk

package storage

import (
"fmt"
"regexp"
"strconv"
"sync"

gofig "github.com/akutz/gofig/types"

"github.com/codedellemc/libstorage/api/registry"
"github.com/codedellemc/libstorage/api/types"

"github.com/codedellemc/libstorage/drivers/storage/vmdk"
"github.com/vmware/docker-volume-vsphere/vmdk_plugin/drivers/vmdk/vmdkops"
)

const (
minSizeGiB = 1
)

type driver struct {
ctx types.Context
config gofig.Config
ops vmdkops.VmdkOps
}

func init() {
registry.RegisterStorageDriver(vmdk.Name, newDriver)
}

func newDriver() types.StorageDriver {
return &driver{}
}

func (d *driver) Name() string {
return vmdk.Name
}

func (d *driver) Type(ctx types.Context) (types.StorageType, error) {
return types.Block, nil
}

func (d *driver) Init(ctx types.Context, config gofig.Config) error {
d.ctx = ctx
d.config = config
d.ops = vmdkops.VmdkOps{Cmd: vmdkops.EsxVmdkCmd{Mtx: &sync.Mutex{}}}
return nil
}

func (d *driver) NextDeviceInfo(
ctx types.Context) (*types.NextDeviceInfo, error) {
return &types.NextDeviceInfo{
Ignore: true,
}, nil
}

func (d *driver) InstanceInspect(
ctx types.Context,
opts types.Store) (*types.Instance, error) {

return nil, nil
}

func (d *driver) Volumes(
ctx types.Context,
opts *types.VolumesOpts) ([]*types.Volume, error) {

data, err := d.ops.List()
if err != nil {
return nil, err
}

vols := []*types.Volume{}
for _, v := range data {
vols = append(vols, &types.Volume{
Name: v.Name,
Fields: v.Attributes,
})
}

return vols, nil
}

func (d *driver) VolumeInspect(
ctx types.Context,
volumeID string,
opts *types.VolumeInspectOpts) (*types.Volume, error) {

data, err := d.ops.Get(volumeID)
if err != nil {
return nil, err
}

vol := &types.Volume{
ID: volumeID,
Name: volumeID,
Fields: map[string]string{},
}

for k, v := range data {
switch k {
case "datastore":
if v, ok := v.(string); ok {
vol.Type = v
}
case "capacity":
if v, ok := v.(map[string]interface{}); ok {
if v, ok := v["size"].(string); ok {
if v == "0" {
vol.Size = 0
} else if sz, ok := isGB(v); ok {
vol.Size = sz * 1024 * 1024 * 1024
} else if sz, ok := isMB(v); ok {
vol.Size = sz * 1024 * 1024
} else if sz, ok := isKB(v); ok {
vol.Size = sz * 1024
}
}
}
default:
vol.Fields[k] = fmt.Sprintf("%v", v)
}
}

return vol, nil
}

func isSize(rx *regexp.Regexp, s string) (int64, bool) {
m := rx.FindStringSubmatch(s)
if len(m) == 0 {
return 0, false
}
i, err := strconv.Atoi(m[1])
if err != nil {
return 0, false
}
return int64(i), true
}

var rxIsKB = regexp.MustCompile(`(?i)^([\d,\.]+)\s*KB\s*$`)

func isKB(s string) (int64, bool) {
return isSize(rxIsKB, s)
}

var rxIsMB = regexp.MustCompile(`(?i)^([\d,\.]+)\s*MB\s*$`)

func isMB(s string) (int64, bool) {
return isSize(rxIsMB, s)
}

var rxIsGB = regexp.MustCompile(`(?i)^([\d,\.]+)\s*GB\s*$`)

func isGB(s string) (int64, bool) {
return isSize(rxIsGB, s)
}

func (d *driver) VolumeCreate(
ctx types.Context,
name string,
opts *types.VolumeCreateOpts) (*types.Volume, error) {

if opts.Type != nil && *opts.Type != "" {
name = fmt.Sprintf("%s@%s", name, *opts.Type)
}

createOpts := map[string]string{}
if opts.Size != nil {
createOpts["size"] = fmt.Sprintf("%dgb", *opts.Size)
}

if err := d.ops.Create(name, createOpts); err != nil {
return nil, err
}

return d.VolumeInspect(ctx, name, nil)
}

func (d *driver) VolumeCreateFromSnapshot(
ctx types.Context,
snapshotID, volumeName string,
opts *types.VolumeCreateOpts) (*types.Volume, error) {

return nil, types.ErrNotImplemented
}

func (d *driver) VolumeCopy(
ctx types.Context,
volumeID, volumeName string,
opts types.Store) (*types.Volume, error) {

return nil, types.ErrNotImplemented
}

func (d *driver) VolumeSnapshot(
ctx types.Context,
volumeID, snapshotName string,
opts types.Store) (*types.Snapshot, error) {

return nil, types.ErrNotImplemented
}

func (d *driver) VolumeRemove(
ctx types.Context,
volumeID string,
opts *types.VolumeRemoveOpts) error {

return d.ops.Remove(volumeID, map[string]string{})
}

func (d *driver) VolumeAttach(
ctx types.Context,
volumeID string,
opts *types.VolumeAttachOpts) (*types.Volume, string, error) {

dev, err := d.ops.Attach(volumeID, nil)
if err != nil {
return nil, "", err
}

var vol *types.Volume
if vol, err = d.VolumeInspect(ctx, volumeID, nil); err != nil {
return nil, "", err
}

return vol, string(dev), nil
}

func (d *driver) VolumeDetach(
ctx types.Context,
volumeID string,
opts *types.VolumeDetachOpts) (*types.Volume, error) {

if err := d.ops.Detach(volumeID, nil); err != nil {
return nil, err
}

vol, err := d.VolumeInspect(ctx, volumeID, nil)
if err != nil {
return nil, err
}

return vol, nil
}

func (d *driver) Snapshots(
ctx types.Context,
opts types.Store) ([]*types.Snapshot, error) {

return nil, types.ErrNotImplemented
}

func (d *driver) SnapshotInspect(
ctx types.Context,
snapshotID string,
opts types.Store) (*types.Snapshot, error) {

return nil, types.ErrNotImplemented
}

func (d *driver) SnapshotCopy(
ctx types.Context,
snapshotID, snapshotName, destinationID string,
opts types.Store) (*types.Snapshot, error) {

return nil, types.ErrNotImplemented
}

func (d *driver) SnapshotRemove(
ctx types.Context,
snapshotID string,
opts types.Store) error {

return types.ErrNotImplemented
}
2 changes: 2 additions & 0 deletions drivers/storage/vmdk/tests/coverage.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
VMDK_COVERPKG := $(ROOT_IMPORT_PATH)/drivers/storage/vmdk
TEST_COVERPKG_./drivers/storage/vmdk/tests := $(VMDK_COVERPKG),$(VMDK_COVERPKG)/executor
Loading

0 comments on commit 8af504f

Please sign in to comment.