Skip to content

Commit

Permalink
Add DigitalOcean driver
Browse files Browse the repository at this point in the history
  • Loading branch information
protochron authored and Dan Norris committed Jan 21, 2017
1 parent 1abc39c commit 530b225
Show file tree
Hide file tree
Showing 21 changed files with 1,214 additions and 27 deletions.
47 changes: 47 additions & 0 deletions drivers/storage/digitalocean/digitalocean.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// +build !libstorage_storage_driver libstorage_storage_driver_digitalocean

package digitalocean

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

const (
// Name is the name of the driver
Name = "digitalocean"

// InstanceIDFieldRegion is the key used to retrive the region from the
// instance id map
InstanceIDFieldRegion = "region"

// InstanceIDFieldName is the key used to retrive the name from the instance
// id map
InstanceIDFieldName = "name"

// VolumePrefix is the value that every DO volume appears with DigitalOcean
// volumes are are found using disk/by-id, ex:
// /dev/disk/by-id/scsi-0DO_Volume_volume-nyc1-01 See
// https://www.digitalocean.com/community/tutorials/how-to-use-block-storage-on-digitalocean#preparing-volumes-for-use-in-linux
VolumePrefix = "scsi-0DO_Volume_"

// ConfigDOToken is the key for the token in the config file
ConfigDOToken = Name + ".token"

// ConfigDORegion is the key for the region in the config file
ConfigDORegion = Name + ".region"
)

func init() {
registerConfig()
}

func registerConfig() {
r := gofigCore.NewRegistration("DigitalOcean")
r.Key(gofig.String, "", "", "",
ConfigDOToken,
"digitaloceanAccessToken",
"DIGITALOCEAN_ACCESS_TOKEN")
r.Key(gofig.String, "", "", "DigitalOcean region", ConfigDORegion)
gofigCore.Register(r)
}
120 changes: 120 additions & 0 deletions drivers/storage/digitalocean/executor/digitalocean_executor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// +build !libstorage_storage_executor libstorage_storage_executor_digitalocean

package executor

import (
"fmt"
"io/ioutil"
"path/filepath"
"regexp"

gofig "github.com/akutz/gofig/types"
"github.com/codedellemc/libstorage/api/registry"
"github.com/codedellemc/libstorage/api/types"
do "github.com/codedellemc/libstorage/drivers/storage/digitalocean"
doUtils "github.com/codedellemc/libstorage/drivers/storage/digitalocean/utils"
)

var (
diskPrefix = regexp.MustCompile(
fmt.Sprintf("^%s(.*)", do.VolumePrefix))
diskSuffix = regexp.MustCompile("part-.*$")
)

type driver struct {
config gofig.Config
}

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

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

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

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

func (d *driver) InstanceID(
ctx types.Context, opts types.Store) (*types.InstanceID, error) {
return doUtils.InstanceID(ctx)
}

func (d *driver) NextDevice(
ctx types.Context, opts types.Store) (string, error) {
return "", types.ErrNotImplemented
}

func (d *driver) LocalDevices(
ctx types.Context,
opts *types.LocalDevicesOpts) (*types.LocalDevices, error) {
deviceMap := map[string]string{}
diskIDPath := "/dev/disk/by-id"

dir, _ := ioutil.ReadDir(diskIDPath)
for _, device := range dir {
switch {
case !diskPrefix.MatchString(device.Name()):
continue
case diskSuffix.MatchString(device.Name()):
continue
case diskPrefix.MatchString(device.Name()):
volumeName := diskPrefix.FindStringSubmatch(device.Name())[1]
devPath, err := filepath.EvalSymlinks(
fmt.Sprintf("%s/%s", diskIDPath, device.Name()))
if err != nil {
return nil, err
}
deviceMap[volumeName] = devPath
}
}

ld := &types.LocalDevices{Driver: d.Name()}
if len(deviceMap) > 0 {
ld.DeviceMap = deviceMap
}

return ld, nil
}

func (d *driver) Supported(ctx types.Context, opts types.Store) (bool, error) {
iid, err := d.InstanceID(ctx, opts)
if err != nil {
return false, err
}

token := d.token()
region := iid.Fields[do.InstanceIDFieldRegion]
client, err := doUtils.Client(token)
if err != nil {
return false, err
}

regions, _, err := client.Regions.List(nil)
if err != nil {
return false, err
}

for _, reg := range regions {
if reg.Slug == region {
for _, feature := range reg.Features {
if feature == "storage" {
return true, nil
}
}
}
}

return false, nil
}

func (d *driver) token() string {
return d.config.GetString(do.ConfigDOToken)
}
Loading

0 comments on commit 530b225

Please sign in to comment.