Initial cut at a Rackspace driver.

* Wrap openstack.Client in an interface.
* Alternate openstack Driver creation method.
* Register the Rackspace driver in commands.go.

Signed-off-by: Ash Wilson <ash.wilson@rackspace.com>
This commit is contained in:
Ash Wilson 2014-12-11 10:14:49 -05:00 committed by Guillaume Giamarchi
parent 0f02ebe6f2
commit c12d3f8ecd
5 changed files with 196 additions and 24 deletions

View File

@ -19,6 +19,7 @@ import (
_ "github.com/docker/machine/drivers/google"
_ "github.com/docker/machine/drivers/none"
_ "github.com/docker/machine/drivers/openstack"
_ "github.com/docker/machine/drivers/rackspace"
_ "github.com/docker/machine/drivers/virtualbox"
_ "github.com/docker/machine/drivers/vmwarefusion"
_ "github.com/docker/machine/drivers/vmwarevcloudair"

View File

@ -15,13 +15,27 @@ import (
"github.com/rackspace/gophercloud/pagination"
)
type Client struct {
type Client interface {
CreateInstance(d *Driver) (string, error)
GetInstanceState(d *Driver) (string, error)
StartInstance(d *Driver) error
StopInstance(d *Driver) error
RestartInstance(d *Driver) error
DeleteInstance(d *Driver) error
WaitForInstanceStatus(d *Driver, status string, timeout int) error
GetInstanceIpAddresses(d *Driver) ([]IpAddress, error)
CreateKeyPair(d *Driver, name string, publicKey string) error
DeleteKeyPair(d *Driver, name string) error
Authenticate(d *Driver) error
}
type GenericClient struct {
Provider *gophercloud.ProviderClient
Compute *gophercloud.ServiceClient
Network *gophercloud.ServiceClient
}
func (c *Client) CreateInstance(d *Driver) (string, error) {
func (c *GenericClient) CreateInstance(d *Driver) (string, error) {
if err := c.initComputeClient(d); err != nil {
return "", err
}
@ -60,7 +74,7 @@ type IpAddress struct {
Mac string
}
func (c *Client) GetInstanceState(d *Driver) (string, error) {
func (c *GenericClient) GetInstanceState(d *Driver) (string, error) {
server, err := c.getServerDetail(d)
if err != nil {
return "", err
@ -73,7 +87,7 @@ func (c *Client) GetInstanceState(d *Driver) (string, error) {
return server.Status, nil
}
func (c *Client) StartInstance(d *Driver) error {
func (c *GenericClient) StartInstance(d *Driver) error {
if err := c.initComputeClient(d); err != nil {
return err
}
@ -83,7 +97,7 @@ func (c *Client) StartInstance(d *Driver) error {
return nil
}
func (c *Client) StopInstance(d *Driver) error {
func (c *GenericClient) StopInstance(d *Driver) error {
if err := c.initComputeClient(d); err != nil {
return err
}
@ -93,7 +107,7 @@ func (c *Client) StopInstance(d *Driver) error {
return nil
}
func (c *Client) RestartInstance(d *Driver) error {
func (c *GenericClient) RestartInstance(d *Driver) error {
if err := c.initComputeClient(d); err != nil {
return err
}
@ -103,7 +117,7 @@ func (c *Client) RestartInstance(d *Driver) error {
return nil
}
func (c *Client) DeleteInstance(d *Driver) error {
func (c *GenericClient) DeleteInstance(d *Driver) error {
if err := c.initComputeClient(d); err != nil {
return err
}
@ -113,14 +127,14 @@ func (c *Client) DeleteInstance(d *Driver) error {
return nil
}
func (c *Client) WaitForInstanceStatus(d *Driver, status string, timeout int) error {
func (c *GenericClient) WaitForInstanceStatus(d *Driver, status string, timeout int) error {
if err := servers.WaitForStatus(c.Compute, d.MachineId, status, timeout); err != nil {
return err
}
return nil
}
func (c *Client) GetInstanceIpAddresses(d *Driver) ([]IpAddress, error) {
func (c *GenericClient) GetInstanceIpAddresses(d *Driver) ([]IpAddress, error) {
server, err := c.getServerDetail(d)
if err != nil {
return nil, err
@ -140,7 +154,7 @@ func (c *Client) GetInstanceIpAddresses(d *Driver) ([]IpAddress, error) {
return addresses, nil
}
func (c *Client) GetNetworkId(d *Driver, networkName string) (string, error) {
func (c *GenericClient) GetNetworkId(d *Driver, networkName string) (string, error) {
if err := c.initNetworkClient(d); err != nil {
return "", err
}
@ -168,7 +182,7 @@ func (c *Client) GetNetworkId(d *Driver, networkName string) (string, error) {
return networkId, err
}
func (c *Client) GetFlavorId(d *Driver, flavorName string) (string, error) {
func (c *GenericClient) GetFlavorId(d *Driver, flavorName string) (string, error) {
if err := c.initComputeClient(d); err != nil {
return "", err
}
@ -195,7 +209,7 @@ func (c *Client) GetFlavorId(d *Driver, flavorName string) (string, error) {
return flavorId, err
}
func (c *Client) GetImageId(d *Driver, imageName string) (string, error) {
func (c *GenericClient) GetImageId(d *Driver, imageName string) (string, error) {
if err := c.initComputeClient(d); err != nil {
return "", err
}
@ -223,7 +237,7 @@ func (c *Client) GetImageId(d *Driver, imageName string) (string, error) {
return imageId, err
}
func (c *Client) CreateKeyPair(d *Driver, name string, publicKey string) error {
func (c *GenericClient) CreateKeyPair(d *Driver, name string, publicKey string) error {
if err := c.initComputeClient(d); err != nil {
return err
}
@ -237,7 +251,7 @@ func (c *Client) CreateKeyPair(d *Driver, name string, publicKey string) error {
return nil
}
func (c *Client) DeleteKeyPair(d *Driver, name string) error {
func (c *GenericClient) DeleteKeyPair(d *Driver, name string) error {
if err := c.initComputeClient(d); err != nil {
return err
}
@ -247,7 +261,7 @@ func (c *Client) DeleteKeyPair(d *Driver, name string) error {
return nil
}
func (c *Client) getServerDetail(d *Driver) (*servers.Server, error) {
func (c *GenericClient) getServerDetail(d *Driver) (*servers.Server, error) {
if err := c.initComputeClient(d); err != nil {
return nil, err
}
@ -258,7 +272,7 @@ func (c *Client) getServerDetail(d *Driver) (*servers.Server, error) {
return server, nil
}
func (c *Client) getFloatingIPs(d *Driver) ([]string, error) {
func (c *GenericClient) getFloatingIPs(d *Driver) ([]string, error) {
if err := c.initNetworkClient(d); err != nil {
return nil, err
@ -283,7 +297,7 @@ func (c *Client) getFloatingIPs(d *Driver) ([]string, error) {
return nil, nil
}
func (c *Client) getPorts(d *Driver) ([]string, error) {
func (c *GenericClient) getPorts(d *Driver) ([]string, error) {
if err := c.initNetworkClient(d); err != nil {
return nil, err
@ -310,7 +324,7 @@ func (c *Client) getPorts(d *Driver) ([]string, error) {
return nil, nil
}
func (c *Client) initComputeClient(d *Driver) error {
func (c *GenericClient) initComputeClient(d *Driver) error {
if c.Provider == nil {
err := c.Authenticate(d)
if err != nil {
@ -328,7 +342,7 @@ func (c *Client) initComputeClient(d *Driver) error {
return nil
}
func (c *Client) initNetworkClient(d *Driver) error {
func (c *GenericClient) initNetworkClient(d *Driver) error {
if c.Provider == nil {
err := c.Authenticate(d)
if err != nil {
@ -346,7 +360,7 @@ func (c *Client) initNetworkClient(d *Driver) error {
return nil
}
func (c *Client) getEndpointType(d *Driver) gophercloud.Availability {
func (c *GenericClient) getEndpointType(d *Driver) gophercloud.Availability {
switch d.EndpointType {
case "internalURL":
return gophercloud.AvailabilityInternal
@ -356,7 +370,7 @@ func (c *Client) getEndpointType(d *Driver) gophercloud.Availability {
return gophercloud.AvailabilityPublic
}
func (c *Client) Authenticate(d *Driver) error {
func (c *GenericClient) Authenticate(d *Driver) error {
log.WithFields(log.Fields{
"AuthUrl": d.AuthUrl,
"Username": d.Username,

View File

@ -38,7 +38,7 @@ type Driver struct {
SSHUser string
SSHPort int
storePath string
client *Client
client Client
}
type CreateFlags struct {
@ -159,12 +159,16 @@ func RegisterCreateFlags(cmd *flag.FlagSet) interface{} {
}
func NewDriver(storePath string) (drivers.Driver, error) {
return NewDerivedDriver(storePath, &GenericClient{})
}
func NewDerivedDriver(storePath string, client Client) (*Driver, error) {
log.WithFields(log.Fields{
"storePath": storePath,
}).Debug("Instanciate OpenStack driver...")
}).Debug("Instantiating OpenStack driver...")
return &Driver{
storePath: storePath,
client: &Client{},
client: client,
}, nil
}

View File

@ -0,0 +1,52 @@
package rackspace
import (
"fmt"
log "github.com/Sirupsen/logrus"
"github.com/docker/machine/drivers/openstack"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/rackspace"
)
func unsupportedOpErr(operation string) error {
return fmt.Errorf("Rackspace does not currently support the %s operation", operation)
}
// Client is a Rackspace specialization of the generic OpenStack driver.
type Client struct {
openstack.GenericClient
driver *Driver
}
// Authenticate creates a Rackspace-specific Gophercloud client.
func (c *Client) Authenticate(d *openstack.Driver) error {
log.WithFields(log.Fields{
"Username": d.Username,
}).Info("Authenticating...")
apiKey := c.driver.APIKey
opts := gophercloud.AuthOptions{
Username: d.Username,
APIKey: apiKey,
}
provider, err := rackspace.AuthenticatedClient(opts)
if err != nil {
return err
}
c.Provider = provider
return nil
}
// StartInstance is unfortunately not supported on Rackspace at this time.
func (c *Client) StartInstance(d *openstack.Driver) error {
return unsupportedOpErr("start")
}
// StopInstance is unfortunately not support on Rackspace at this time.
func (c *Client) StopInstance(d *openstack.Driver) error {
return unsupportedOpErr("stop")
}

View File

@ -0,0 +1,101 @@
package rackspace
import (
"os"
log "github.com/Sirupsen/logrus"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/machine/drivers"
"github.com/docker/machine/drivers/openstack"
)
// Driver is a machine driver for Rackspace. It's a specialization of the generic OpenStack one.
type Driver struct {
drivers.Driver
APIKey string
}
// CreateFlags stores the command-line arguments given to "machine create".
type CreateFlags struct {
Username *string
APIKey *string
Region *string
MachineName *string
EndpointType *string
ImageID *string
FlavorID *string
SSHUser *string
SSHPort *int
}
func init() {
drivers.Register("rackspace", &drivers.RegisteredDriver{
New: NewDriver,
RegisterCreateFlags: RegisterCreateFlags,
})
}
// RegisterCreateFlags registers the "machine create" flags recognized by this driver, including
// their help text and defaults.
func RegisterCreateFlags(cmd *flag.FlagSet) interface{} {
createFlags := new(CreateFlags)
createFlags.Username = cmd.String(
[]string{"-rackspace-username"},
os.Getenv("OS_USERNAME"),
"Rackspace account username",
)
createFlags.APIKey = cmd.String(
[]string{"-rackspace-api-key"},
os.Getenv("OS_API_KEY"),
"Rackspace API key",
)
createFlags.Region = cmd.String(
[]string{"-rackspace-region"},
os.Getenv("OS_REGION_NAME"),
"Rackspace region name",
)
createFlags.EndpointType = cmd.String(
[]string{"-rackspace-endpoint-type"},
os.Getenv("OS_ENDPOINT_TYPE"),
"Rackspace endpoint type (adminURL, internalURL or the default publicURL)",
)
createFlags.ImageID = cmd.String(
[]string{"-rackspace-image-id"},
"",
"Rackspace image ID. Default: Ubuntu 14.10 (Utopic Unicorn) (PVHVM)",
)
createFlags.FlavorID = cmd.String(
[]string{"-rackspace-flavor-id"},
"general1-1",
"Rackspace flavor ID. Default: General Purpose 1GB",
)
createFlags.SSHUser = cmd.String(
[]string{"-rackspace-ssh-user"},
"root",
"SSH user for the newly booted machine. Set to root by default",
)
createFlags.SSHPort = cmd.Int(
[]string{"-rackspace-ssh-port"},
22,
"SSH port for the newly booted machine. Set to 22 by default",
)
return createFlags
}
// NewDriver instantiates a Rackspace driver.
func NewDriver(storePath string) (drivers.Driver, error) {
log.WithFields(log.Fields{
"storePath": storePath,
}).Info("Instantiating Rackspace driver.")
client := &Client{}
inner, err := openstack.NewDerivedDriver(storePath, &Client{})
if err != nil {
return nil, err
}
driver := &Driver{Driver: inner}
client.driver = driver
return driver, nil
}