Skip to content

Commit

Permalink
Merge pull request #302 from akutz/release/0.3.0
Browse files Browse the repository at this point in the history
Release/0.3.0
  • Loading branch information
akutz authored Oct 16, 2016
2 parents 08af1c0 + 8d064f8 commit 80f4fc4
Show file tree
Hide file tree
Showing 26 changed files with 498 additions and 52 deletions.
20 changes: 20 additions & 0 deletions .docs/about/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,26 @@ Release early, release often

---

## Version 0.3.0 (2016/10/16)
This release introduces the Elastic Block Storage (EBS) driver, formerly known
as the EC2 driver in REX-Ray <=0.3.x.

### Enhancements
* Amazon Elastic Block Storage (EBS) Support ([#248](https://github.com/emccode/libstorage/issues/248), [#279](https://github.com/emccode/libstorage/issues/279))
* Build with Docker ([#274](https://github.com/emccode/libstorage/issues/274), [#281](https://github.com/emccode/libstorage/issues/281))
* Documentation updates ([#298](https://github.com/emccode/libstorage/issues/298))

### Bug Fixes
* Volume Removal Instance ID Fix ([#292](https://github.com/emccode/libstorage/issues/292))
* Avoid Client Failure when Server Driver not Supported ([#296](https://github.com/emccode/libstorage/issues/296), [#297](https://github.com/emccode/libstorage/issues/297), [#299](https://github.com/emccode/libstorage/issues/299), [#300](https://github.com/emccode/libstorage/issues/300))

### Thank You
Name | Blame
-------|------
[Proud Heng](https://github.com/proudh) | So long Proud, and thanks for all the fish. EBS is now part of a tagged release!
[Aaron Spiegel](https://github.com/spiegela) | Aaron, you may be a new contributor, but I feel like we've known each other since we were kids, running around the front-yard on a summer's dusky-eve, catching fireflies and speaking of the day we'd be patching Markdown documentation together.
[Travis Rhoden](https://github.com/codenrhoden) | While we've been colleagues a while, I'm thrilled you're finally working with the rest of the nerdiest of nerds, on libStorage and the secret holographic unicorn fight club we run on Thursday nights.

## Version 0.2.1 (2016/09/14)
This is a minor release that includes a fix for the EFS storage driver as well
as improvements to the build process. For example, Travis-CI now builds
Expand Down
6 changes: 4 additions & 2 deletions .docs/user-guide/storage-providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ The following items are configurable specific to this driver.
* `volumePath` represents the location under `/ifs/volumes` to allow volumes to
be created and removed.
* `nfsHost` is the configurable host used when mounting exports
* `dataSubnet` is the subnet the REX-Ray driver is running on
* `nfsHost` is the configurable NFS server hostname or IP (often a
SmartConnect name) used when mounting exports
* `dataSubnet` is the subnet the REX-Ray driver is running on. This is used
for the NFS export host ACLs.

### Optional Parameters
The following items are not required, but available to this driver.
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.2.1
0.3.0
30 changes: 29 additions & 1 deletion api/types/types_drivers_executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ import (
type DeviceScanType int

const (
// LSXExitCodeNotImplemented is the exit code the executor binary uses to
// indicate a function is not implemented for a given storage driver on the
// current system.
LSXExitCodeNotImplemented = 2

// LSXExitCodeTimedOut is the exit code the executor binary uses to indicate
// a function timed out.
LSXExitCodeTimedOut = 255

// LSXCmdInstanceID is the command to execute to get the instance ID.
LSXCmdInstanceID = "instanceID"

Expand All @@ -24,6 +33,10 @@ const (
// LSXCmdWaitForDevice is the command to execute to wait until a device,
// identified by volume ID, is presented to the system.
LSXCmdWaitForDevice = "wait"

// LSXCmdSupported is the command to execute to find out if an executor
// is valid for a given platform on the current host.
LSXCmdSupported = "supported"
)

const (
Expand Down Expand Up @@ -122,6 +135,21 @@ type StorageExecutorFunctions interface {
opts *LocalDevicesOpts) (*LocalDevices, error)
}

// StorageExecutorWithSupported is an interface that executor implementations
// may use by defining the function "Supported(Context, Store) (bool, error)".
// This function indicates whether a storage platform is valid when executing
// the executor binary on a given client.
type StorageExecutorWithSupported interface {
StorageExecutorFunctions

// Supported returns a flag indicating whether or not the platform
// implementing the executor is valid for the host on which the executor
// resides.
Supported(
ctx Context,
opts Store) (bool, error)
}

// ProvidesStorageExecutorCLI is a type that provides the StorageExecutorCLI.
type ProvidesStorageExecutorCLI interface {
// XCLI returns the StorageExecutorCLI.
Expand All @@ -131,7 +159,7 @@ type ProvidesStorageExecutorCLI interface {
// StorageExecutorCLI provides a way to interact with the CLI tool built with
// the driver implementations of the StorageExecutor interface.
type StorageExecutorCLI interface {
StorageExecutorFunctions
StorageExecutorWithSupported

// WaitForDevice blocks until the provided attach token appears in the
// map returned from LocalDevices or until the timeout expires, whichever
Expand Down
3 changes: 3 additions & 0 deletions api/types/types_errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import (
// a function is not implemented.
var ErrNotImplemented = goof.New("not implemented")

// ErrTimedOut is the error that is used to indicate an operation timed out.
var ErrTimedOut = goof.New("timed out")

// ErrUnsupportedForClientType is the error that occurs when an operation is
// invoked that is unsupported for the current client type.
type ErrUnsupportedForClientType struct{ goof.Goof }
Expand Down
40 changes: 30 additions & 10 deletions cli/lsx/lsx.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (

var (
cmdRx = regexp.MustCompile(
`(?i)^instanceid|nextdevice|localdevices|wait$`)
`(?i)^supported|instanceid|nextdevice|localdevices|wait$`)
)

// Run runs the executor CLI.
Expand Down Expand Up @@ -60,7 +60,6 @@ func Run() {
if cmd == "" {
printUsageAndExit()
}
cmd = strings.ToLower(cmd)
store := utils.NewStore()

var (
Expand All @@ -69,7 +68,19 @@ func Run() {
exitCode int
)

if cmd == "instanceid" {
if strings.EqualFold(cmd, apitypes.LSXCmdSupported) {
op = "supported"
if dws, ok := d.(apitypes.StorageExecutorWithSupported); ok {
opResult, opErr := dws.Supported(ctx, store)
if opErr != nil {
err = opErr
} else {
result = opResult
}
} else {
err = apitypes.ErrNotImplemented
}
} else if strings.EqualFold(cmd, apitypes.LSXCmdInstanceID) {
op = "instance ID"
opResult, opErr := d.InstanceID(ctx, store)
if opErr != nil {
Expand All @@ -78,15 +89,15 @@ func Run() {
opResult.Driver = driverName
result = opResult
}
} else if cmd == "nextdevice" {
} else if strings.EqualFold(cmd, apitypes.LSXCmdNextDevice) {
op = "next device"
opResult, opErr := d.NextDevice(ctx, store)
if opErr != nil && opErr != apitypes.ErrNotImplemented {
err = opErr
} else {
result = opResult
}
} else if cmd == "localdevices" {
} else if strings.EqualFold(cmd, apitypes.LSXCmdLocalDevices) {
if len(args) < 4 {
printUsageAndExit()
}
Expand All @@ -101,7 +112,7 @@ func Run() {
} else {
result = opResult
}
} else if cmd == "wait" {
} else if strings.EqualFold(cmd, apitypes.LSXCmdWaitForDevice) {
if len(args) < 5 {
printUsageAndExit()
}
Expand Down Expand Up @@ -141,7 +152,7 @@ func Run() {
for {
select {
case <-timeoutC:
exitCode = 255
exitCode = apitypes.LSXExitCodeTimedOut
break TimeoutLoop
case <-tick:
if found, opResult, opErr = ldl(); found || opErr != nil {
Expand All @@ -159,12 +170,21 @@ func Run() {
}

if err != nil {
// if the function is not implemented then exit with
// apitypes.LSXExitCodeNotImplemented to let callers
// know that the function is unsupported on this system
exitCode = 1
if strings.EqualFold(err.Error(), apitypes.ErrNotImplemented.Error()) {
exitCode = apitypes.LSXExitCodeNotImplemented
}
fmt.Fprintf(os.Stderr,
"error: error getting %s: %v\n", op, err)
os.Exit(1)
os.Exit(exitCode)
}

switch tr := result.(type) {
case bool:
fmt.Fprintf(os.Stdout, "%v", result)
case string:
fmt.Fprintln(os.Stdout, result)
case encoding.TextMarshaler:
Expand Down Expand Up @@ -224,9 +244,9 @@ func printUsage() {
lpad1 := buf.Len()
fmt.Fprintf(w, "%s <executor> ", os.Args[0])
lpad2 := buf.Len()
fmt.Fprintf(w, "instanceID\n")
fmt.Fprintf(w, "supported\n")
printUsageLeftPadded(w, lpad2, "instanceID\n")
printUsageLeftPadded(w, lpad2, "nextDevice\n")

printUsageLeftPadded(w, lpad2, "localDevices <scanType>\n")
printUsageLeftPadded(w, lpad2, "wait <scanType> <attachToken> <timeout>\n")
fmt.Fprintln(w)
Expand Down
10 changes: 10 additions & 0 deletions drivers/storage/ebs/executor/ebs_executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ 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 ebsUtils.IsEC2Instance(ctx)
}

// InstanceID returns the instance ID from the current instance from metadata
func (d *driver) InstanceID(
ctx types.Context,
Expand Down
24 changes: 24 additions & 0 deletions drivers/storage/ebs/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,42 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"net"
"net/http"
"time"

"github.com/emccode/libstorage/api/types"
"github.com/emccode/libstorage/drivers/storage/ebs"
)

const (
raddr = "169.254.169.254"
mdtURL = "http://" + raddr + "/latest/meta-data/"
iidURL = "http://" + raddr + "/latest/dynamic/instance-identity/document"
bdmURL = "http://" + raddr + "/latest/meta-data/block-device-mapping/"
)

// IsEC2Instance returns a flag indicating whether the executing host is an EC2
// instance based on whether or not the metadata URL can be accessed.
func IsEC2Instance(ctx types.Context) (bool, error) {
client := &http.Client{Timeout: time.Duration(1 * time.Second)}
req, err := http.NewRequest(http.MethodHead, mdtURL, nil)
if err != nil {
return false, err
}
res, err := doRequestWithClient(ctx, client, req)
if err != nil {
if terr, ok := err.(net.Error); ok && terr.Timeout() {
return false, nil
}
return false, err
}
if res.StatusCode >= 200 || res.StatusCode <= 299 {
return true, nil
}
return false, nil
}

type instanceIdentityDoc struct {
InstanceID string `json:"instanceId,omitempty"`
Region string `json:"region,omitempty"`
Expand Down
9 changes: 8 additions & 1 deletion drivers/storage/ebs/utils/utils_go17.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ import (
)

func doRequest(ctx types.Context, req *http.Request) (*http.Response, error) {
return doRequestWithClient(ctx, http.DefaultClient, req)
}

func doRequestWithClient(
ctx types.Context,
client *http.Client,
req *http.Request) (*http.Response, error) {
req = req.WithContext(ctx)
return http.DefaultClient.Do(req)
return client.Do(req)
}
9 changes: 8 additions & 1 deletion drivers/storage/ebs/utils/utils_pre_go17.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,12 @@ import (
)

func doRequest(ctx types.Context, req *http.Request) (*http.Response, error) {
return ctxhttp.Do(ctx, http.DefaultClient, req)
return doRequestWithClient(ctx, http.DefaultClient, req)
}

func doRequestWithClient(
ctx types.Context,
client *http.Client,
req *http.Request) (*http.Response, error) {
return ctxhttp.Do(ctx, client, req)
}
8 changes: 8 additions & 0 deletions drivers/storage/efs/efs.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ import (
const (
// Name is the provider's name.
Name = "efs"

// 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"
)

func init() {
Expand Down
11 changes: 11 additions & 0 deletions drivers/storage/efs/executor/efs_executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/emccode/libstorage/api/registry"
"github.com/emccode/libstorage/api/types"
"github.com/emccode/libstorage/drivers/storage/efs"
efsUtils "github.com/emccode/libstorage/drivers/storage/efs/utils"
)

// driver is the storage executor for the efs storage driver.
Expand Down Expand Up @@ -47,6 +48,16 @@ func (d *driver) Name() string {
return efs.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 efsUtils.IsEC2Instance(ctx)
}

// InstanceID returns the local instance ID for the test
func InstanceID() (*types.InstanceID, error) {
return newDriver().InstanceID(nil, nil)
Expand Down
Loading

0 comments on commit 80f4fc4

Please sign in to comment.