Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FittedCloud storage driver #408

Merged
merged 1 commit into from Feb 23, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions drivers/storage/fittedcloud/executor/fittedcloud_executor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// +build !libstorage_storage_executor libstorage_storage_executor_fittedcloud

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/fittedcloud"
fcUtils "github.com/codedellemc/libstorage/drivers/storage/fittedcloud/utils"
)

// driver is the storage executor for the ec2 storage driver.
type driver struct {
name string
config gofig.Config
}

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

func newDriver() types.StorageExecutor {
return &driver{name: fittedcloud.Name}
}

func (d *driver) Init(ctx types.Context, config gofig.Config) error {
// ensure backwards compatibility with ebs and ec2 in config
d.config = config
return nil
}

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

// Supported returns a flag indicating whether or not the platform
// implementing the executor is valid for the host on which the executor
// resides.
func (d *driver) Supported(
ctx types.Context,
opts types.Store) (bool, error) {
return fcUtils.IsEC2Instance(ctx)
}

// InstanceID returns the instance ID from the current instance from metadata
func (d *driver) InstanceID(
ctx types.Context,
opts types.Store) (*types.InstanceID, error) {
return fcUtils.InstanceID(ctx)
}

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

// LocalDevices retrieves device paths currently attached and/or mounted
func (d *driver) LocalDevices(
ctx types.Context,
opts *types.LocalDevicesOpts) (*types.LocalDevices, error) {
return fcUtils.LocalDevices(ctx, opts)
}
152 changes: 152 additions & 0 deletions drivers/storage/fittedcloud/fcagent/fcagent.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// +build !libstorage_storage_driver libstorage_storage_driver_fittedcloud

package fcagent

import (
"errors"
"os/exec"
"strconv"
"strings"

log "github.com/Sirupsen/logrus"
)

const (
// FcVolMaxCloudDisk is the max number of constituent disks for a FittedCloud volume
FcVolMaxCloudDisk = 6
)

// IsRunning checks if FittedCloud Agent is running
func IsRunning() (string, error) {
var (
cmdOut []byte
err error
path string
)
cmd := "fcagent"
args := []string{"echo"}

if path, err = exec.LookPath(cmd); err != nil {
log.Debug(err)
}
log.Debug(path, args[0])

if cmdOut, err = exec.Command(cmd, args...).Output(); err != nil {
log.Debug(err)
}
return string(cmdOut), err
}

// CreateVol creates a FittedCluod volume
func CreateVol(tagName string, sizeGb int, encryption bool, kmsKeyID string) (string, error) {
var (
cmdOut []byte
err error
fcVolName string
)
sizeGbStr := strconv.Itoa(sizeGb)
initGb := (sizeGb + FcVolMaxCloudDisk - 1) / FcVolMaxCloudDisk
initGbStr := strconv.Itoa(initGb)
log.Debug("sizeGbStr=" + sizeGbStr + " initGbStr=" + initGbStr)

// Find the next available fcvol name
fcVolName, err = GetFcVolName("next")
if err != nil {
return "", err
}

cmd := "fcagent"
args := make([]string, 0, 8)
args = append(args, "createvol")
args = append(args, fcVolName)
args = append(args, sizeGbStr)
args = append(args, initGbStr)
args = append(args, "--delete_on_termination=no")
if encryption {
args = append(args, "--encryption=yes")
if kmsKeyID != "" {
args = append(args, "--kms_key="+kmsKeyID)
}
} else {
args = append(args, "--encryption=no")
}
args = append(args, "--ebs_tag="+tagName)

log.Debug(cmd, args)

if cmdOut, err = exec.Command(cmd, args...).Output(); err != nil {
log.Debug(err)
return string(cmdOut), err
}
return fcVolName, nil
}

// DelVol deletes a FittedCloud volume by name
func DelVol(fcVolName string) (string, error) {
var (
cmdOut []byte
err error
)

strs := strings.SplitAfterN(fcVolName, "/dev/", 2)
if len(strs) == 2 && strs[0] == "/dev/" {
fcVolName = strs[1]
}
log.Debug("fcVolName=", fcVolName)

cmd := "fcagent"
args := []string{
"delvol",
fcVolName,
"-donotdelebs"}

log.Debug(cmd, args)

if cmdOut, err = exec.Command(cmd, args...).Output(); err != nil {
log.Debug(err)
}

return string(cmdOut), err
}

func getFcVolName(devName string) (string, error) {
var (
cmdOut []byte
err error
)

cmd := "fcagent"
args := []string{
"getfcvolname",
devName}

log.Debug(cmd, args)

if cmdOut, err = exec.Command(cmd, args...).Output(); err != nil {
log.Debug(err)
}

return string(cmdOut), err
}

// GetFcVolName returns the FittedCloud volume name
func GetFcVolName(devName string) (string, error) {
var (
cmdOut string
err error
)
if cmdOut, err = getFcVolName(devName); err != nil {
return "", err
}
cmdOut = strings.TrimRight(cmdOut, "\n")

strs := strings.SplitAfterN(cmdOut, "fcvol=", 2)
if len(strs) == 2 {
if strs[1] == "NOTFOUND" {
return cmdOut, errors.New("fcvol not found")
}
cmdOut = strs[1]
}

return cmdOut, err
}
96 changes: 96 additions & 0 deletions drivers/storage/fittedcloud/fittedcloud.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// +build !libstorage_storage_driver libstorage_storage_driver_fittedcloud

package fittedcloud

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

const (
// Name is the provider's name.
Name = "fittedcloud"

// TagDelimiter separates tags from volume or snapshot names
TagDelimiter = "/"

// DefaultMaxRetries is the max number of times to retry failed operations
DefaultMaxRetries = 10

// InstanceIDFieldRegion is the key to retrieve the region value from the
// InstanceID Field map.
InstanceIDFieldRegion = "region"

// InstanceIDFieldAvailabilityZone is the key to retrieve the availability
// zone value from the InstanceID Field map.
InstanceIDFieldAvailabilityZone = "availabilityZone"

// AccessKey is a key constant.
AccessKey = "accessKey"

// SecretKey is a key constant.
SecretKey = "secretKey"

// Region is a key constant.
Region = "region"

// Endpoint is a key constant.
Endpoint = "endpoint"

// MaxRetries is a key constant.
MaxRetries = "maxRetries"

// Tag is a key constant.
Tag = "tag"

// KmsKeyID is the full ARN of the AWS Key Management Service (AWS KMS)
// customer master key (CMK) to use when creating the encrypted volume.
//
// This parameter is only required if you want to use a non-default CMK;
// if this parameter is not specified, the default CMK for EBS is used.
// The ARN contains the arn:aws:kms namespace, followed by the region of
// the CMK, the AWS account ID of the CMK owner, the key namespace, and
// then the CMK ID. For example,
// arn:aws:kms:us-east-1:012345678910:key/abcd1234-a123-456a-a12b-a123b4cd56ef.
//
// If a KmsKeyID is specified, all volumes will be created with their
// Encrypted flag set to true.
KmsKeyID = "kmsKeyID"

// ConfigEBS is a config key.
ConfigEBS = "ebs"

// ConfigEBSAccessKey is a config key.
ConfigEBSAccessKey = ConfigEBS + "." + AccessKey

// ConfigEBSSecretKey is a config key.
ConfigEBSSecretKey = ConfigEBS + "." + SecretKey

// ConfigEBSRegion is a config key.
ConfigEBSRegion = ConfigEBS + "." + Region

// ConfigEBSEndpoint is a config key.
ConfigEBSEndpoint = ConfigEBS + "." + Endpoint

// ConfigEBSMaxRetries is a config key.
ConfigEBSMaxRetries = ConfigEBS + "." + MaxRetries

// ConfigEBSTag is a config key.
ConfigEBSTag = ConfigEBS + "." + Tag

// ConfigEBSKmsKeyID is a config key.
ConfigEBSKmsKeyID = ConfigEBS + "." + KmsKeyID
)

func init() {
r := gofigCore.NewRegistration("FittedCloud")
r.Key(gofig.String, "", "", "", ConfigEBSAccessKey)
r.Key(gofig.String, "", "", "", ConfigEBSSecretKey)
r.Key(gofig.String, "", "", "", ConfigEBSRegion)
r.Key(gofig.String, "", "", "", ConfigEBSEndpoint)
r.Key(gofig.Int, "", DefaultMaxRetries, "", ConfigEBSMaxRetries)
r.Key(gofig.String, "", "", "Tag prefix for EBS naming", ConfigEBSTag)
r.Key(gofig.String, "", "", "", ConfigEBSKmsKeyID)

gofigCore.Register(r)
}
Loading