Skip to content

Commit

Permalink
Add DigitalOcean driver
Browse files Browse the repository at this point in the history
  • Loading branch information
Dan Norris committed Jan 18, 2017
1 parent 1abc39c commit 5a3c43a
Show file tree
Hide file tree
Showing 21 changed files with 1,144 additions and 27 deletions.
Empty file.
35 changes: 35 additions & 0 deletions drivers/storage/digitalocean/digitalocean.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// +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_"
)

func init() {
registerConfig()
}

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

package executor

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

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

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

type driver struct {
config gofig.Config
}

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

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

func (d *driver) Name() string {
return digitalocean.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[digitalocean.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 {
var token string
envToken := os.Getenv("DIGITALOCEAN_ACCESS_TOKEN")
if envToken != "" {
token = envToken
} else {
token = d.config.GetString("digitalocean.token")
}

return token
}
Loading

0 comments on commit 5a3c43a

Please sign in to comment.