mirror of https://github.com/docker/docs.git
Add OpenStack driver
Signed-off-by: Guillaume Giamarchi <guillaume.giamarchi@gmail.com>
This commit is contained in:
parent
1785869490
commit
f6b0c81996
47
README.md
47
README.md
|
|
@ -176,6 +176,53 @@ Options:
|
|||
- `--vmwarevsphere-pool`: Resource pool for Docker VM.
|
||||
- `--vmwarevsphere-vcenter`: IP/hostname for vCenter (or ESXi if connecting directly to a single host).
|
||||
|
||||
### OpenStack
|
||||
|
||||
Create machines on [Openstack](http://www.openstack.org/software/)
|
||||
|
||||
#### Options
|
||||
|
||||
Mandatory
|
||||
|
||||
- `--openstack-flavor-id`: The flavor ID to use when creating the machine
|
||||
- `--openstack-image-id`: The image ID to use when creating the machine. At the moment, the driver does not install
|
||||
docker on the machine. That means the image you use should already contains a ready to use docker installation
|
||||
|
||||
Optional
|
||||
|
||||
- `--openstack-auth-url`: Keystone service base URL
|
||||
- `--openstack-username`: User identifer to authenticate with.
|
||||
- `--openstack-password`: User password. It can be omitted if the standard environment variable `OS_PASSWORD` is set
|
||||
- `--openstack-tenant-name` or `--openstack-tenant-id`: Identify the tenant in which the machine will be created.
|
||||
- `--openstack-region`: The region to work on. Can be omitted if there is ony one region on the OpenStack
|
||||
- `--openstack-endpoint-type`: Endpoint type can be `internalURL`, `adminURL` on `publicURL`. If is a helper for the driver
|
||||
to choose the right URL in the OpenStack service catalog. If not provided the default id `publicURL`
|
||||
- `--openstack-net-id`: The private network id the machine will be connected on. If your OpenStack project project
|
||||
contains only one private network it will be use automatically
|
||||
- `--openstack-sec-groups`: If security groups are available on your OpenStack you can specify a comma separated list
|
||||
to use for the machine (e.g. `secgrp001,secgrp002`)
|
||||
- `--openstack-floatingip-pool`: The IP pool that will be used to get an IP an assign it to the machine. If there is an
|
||||
IP address already allocated but not assigned to any machine, this IP will be chosen and assigned to our machine. If
|
||||
there is no IP address already allocated, an new IP will be allocated and assigned to the machine
|
||||
- `--openstack-ssh-user`: The username to use for SSH into the machine. If not provided `root` will be used.
|
||||
- `--openstack-ssh-port`: Customize the SSH port if the SSH server on the machine does not listen on the default port
|
||||
|
||||
#### Environment variables
|
||||
|
||||
Some options can be omitted if the corresponding standard OpenStack environment variable is set. Here
|
||||
comes the list of the supported variables with the corresponding options. If both environment variable
|
||||
and CLI option are provided the CLI option takes the precedence.
|
||||
|
||||
| Environment variable | CLI option |
|
||||
|----------------------|-----------------------------|
|
||||
| `OS_AUTH_URL` | `--openstack-auth-url` |
|
||||
| `OS_USERNAME` | `--openstack-username` |
|
||||
| `OS_PASSWORD` | `--openstack-password` |
|
||||
| `OS_TENANT_NAME` | `--openstack-tenant-name` |
|
||||
| `OS_TENANT_ID` | `--openstack-tenant-id` |
|
||||
| `OS_REGION_NAME` | `--openstack-region` |
|
||||
| `OS_ENDPOINT_TYPE` | `--openstack-endpoint-type` |
|
||||
|
||||
## Contributing
|
||||
|
||||
[](https://godoc.org/github.com/docker/machine)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import (
|
|||
_ "github.com/docker/machine/drivers/digitalocean"
|
||||
_ "github.com/docker/machine/drivers/google"
|
||||
_ "github.com/docker/machine/drivers/none"
|
||||
_ "github.com/docker/machine/drivers/openstack"
|
||||
_ "github.com/docker/machine/drivers/virtualbox"
|
||||
_ "github.com/docker/machine/drivers/vmwarefusion"
|
||||
_ "github.com/docker/machine/drivers/vmwarevcloudair"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,297 @@
|
|||
package openstack
|
||||
|
||||
import (
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/rackspace/gophercloud"
|
||||
"github.com/rackspace/gophercloud/openstack"
|
||||
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs"
|
||||
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/startstop"
|
||||
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
|
||||
"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/floatingips"
|
||||
"github.com/rackspace/gophercloud/openstack/networking/v2/ports"
|
||||
"github.com/rackspace/gophercloud/pagination"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
Provider *gophercloud.ProviderClient
|
||||
Compute *gophercloud.ServiceClient
|
||||
Network *gophercloud.ServiceClient
|
||||
}
|
||||
|
||||
func (c *Client) CreateInstance(d *Driver) (string, error) {
|
||||
if err := c.initComputeClient(d); err != nil {
|
||||
return "", err
|
||||
}
|
||||
serverOpts := servers.CreateOpts{
|
||||
Name: d.MachineName,
|
||||
FlavorRef: d.FlavorId,
|
||||
ImageRef: d.ImageId,
|
||||
SecurityGroups: d.SecurityGroups,
|
||||
}
|
||||
if d.NetworkId != "" {
|
||||
serverOpts.Networks = []servers.Network{
|
||||
{
|
||||
UUID: d.NetworkId,
|
||||
},
|
||||
}
|
||||
}
|
||||
server, err := servers.Create(c.Compute, keypairs.CreateOptsExt{
|
||||
serverOpts,
|
||||
d.KeyPairName,
|
||||
}).Extract()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return server.ID, nil
|
||||
}
|
||||
|
||||
const (
|
||||
Floating string = "floating"
|
||||
Fixed string = "fixed"
|
||||
)
|
||||
|
||||
type IpAddress struct {
|
||||
Network string
|
||||
AddressType string
|
||||
Address string
|
||||
Mac string
|
||||
}
|
||||
|
||||
func (c *Client) GetInstanceState(d *Driver) (string, error) {
|
||||
server, err := c.getServerDetail(d)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
c.getFloatingIPs(d)
|
||||
|
||||
c.getPorts(d)
|
||||
|
||||
return server.Status, nil
|
||||
}
|
||||
|
||||
func (c *Client) StartInstance(d *Driver) error {
|
||||
if err := c.initComputeClient(d); err != nil {
|
||||
return err
|
||||
}
|
||||
if result := startstop.Start(c.Compute, d.MachineId); result.Err != nil {
|
||||
return result.Err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) StopInstance(d *Driver) error {
|
||||
if err := c.initComputeClient(d); err != nil {
|
||||
return err
|
||||
}
|
||||
if result := startstop.Stop(c.Compute, d.MachineId); result.Err != nil {
|
||||
return result.Err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) RestartInstance(d *Driver) error {
|
||||
if err := c.initComputeClient(d); err != nil {
|
||||
return err
|
||||
}
|
||||
if result := servers.Reboot(c.Compute, d.MachineId, servers.SoftReboot); result.Err != nil {
|
||||
return result.Err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) DeleteInstance(d *Driver) error {
|
||||
if err := c.initComputeClient(d); err != nil {
|
||||
return err
|
||||
}
|
||||
if result := servers.Delete(c.Compute, d.MachineId); result.Err != nil {
|
||||
return result.Err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) 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) {
|
||||
server, err := c.getServerDetail(d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addresses := []IpAddress{}
|
||||
for network, networkAddresses := range server.Addresses {
|
||||
for _, element := range networkAddresses.([]interface{}) {
|
||||
address := element.(map[string]interface{})
|
||||
addresses = append(addresses, IpAddress{
|
||||
Network: network,
|
||||
AddressType: address["OS-EXT-IPS:type"].(string),
|
||||
Address: address["addr"].(string),
|
||||
Mac: address["OS-EXT-IPS-MAC:mac_addr"].(string),
|
||||
})
|
||||
}
|
||||
}
|
||||
return addresses, nil
|
||||
}
|
||||
|
||||
func (c *Client) CreateKeyPair(d *Driver, name string, publicKey string) error {
|
||||
if err := c.initComputeClient(d); err != nil {
|
||||
return err
|
||||
}
|
||||
opts := keypairs.CreateOpts{
|
||||
Name: name,
|
||||
PublicKey: publicKey,
|
||||
}
|
||||
if result := keypairs.Create(c.Compute, opts); result.Err != nil {
|
||||
return result.Err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) DeleteKeyPair(d *Driver, name string) error {
|
||||
if err := c.initComputeClient(d); err != nil {
|
||||
return err
|
||||
}
|
||||
if result := keypairs.Delete(c.Compute, name); result.Err != nil {
|
||||
return result.Err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) getServerDetail(d *Driver) (*servers.Server, error) {
|
||||
if err := c.initComputeClient(d); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
server, err := servers.Get(c.Compute, d.MachineId).Extract()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return server, nil
|
||||
}
|
||||
|
||||
func (c *Client) getFloatingIPs(d *Driver) ([]string, error) {
|
||||
|
||||
if err := c.initNetworkClient(d); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pager := floatingips.List(c.Network, floatingips.ListOpts{})
|
||||
|
||||
err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
||||
floatingipList, err := floatingips.ExtractFloatingIPs(page)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, f := range floatingipList {
|
||||
log.Info("### FloatingIP => %s", f)
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *Client) getPorts(d *Driver) ([]string, error) {
|
||||
|
||||
if err := c.initNetworkClient(d); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pager := ports.List(c.Network, ports.ListOpts{
|
||||
DeviceID: d.MachineId,
|
||||
})
|
||||
|
||||
err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
||||
portList, err := ports.ExtractPorts(page)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, port := range portList {
|
||||
log.Info("### Port => %s", port)
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *Client) initComputeClient(d *Driver) error {
|
||||
if c.Provider == nil {
|
||||
err := c.Authenticate(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
compute, err := openstack.NewComputeV2(c.Provider, gophercloud.EndpointOpts{
|
||||
Region: d.Region,
|
||||
Availability: c.getEndpointType(d),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Compute = compute
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) initNetworkClient(d *Driver) error {
|
||||
if c.Provider == nil {
|
||||
err := c.Authenticate(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
network, err := openstack.NewNetworkV2(c.Provider, gophercloud.EndpointOpts{
|
||||
Region: d.Region,
|
||||
Availability: c.getEndpointType(d),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Network = network
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) getEndpointType(d *Driver) gophercloud.Availability {
|
||||
switch d.EndpointType {
|
||||
case "internalURL":
|
||||
return gophercloud.AvailabilityInternal
|
||||
case "adminURL":
|
||||
return gophercloud.AvailabilityAdmin
|
||||
}
|
||||
return gophercloud.AvailabilityPublic
|
||||
}
|
||||
|
||||
func (c *Client) Authenticate(d *Driver) error {
|
||||
log.WithFields(log.Fields{
|
||||
"AuthUrl": d.AuthUrl,
|
||||
"Username": d.Username,
|
||||
"TenantName": d.TenantName,
|
||||
"TenantID": d.TenantId,
|
||||
}).Info("Authenticating...")
|
||||
|
||||
opts := gophercloud.AuthOptions{
|
||||
IdentityEndpoint: d.AuthUrl,
|
||||
Username: d.Username,
|
||||
Password: d.Password,
|
||||
TenantName: d.TenantName,
|
||||
TenantID: d.TenantId,
|
||||
AllowReauth: true,
|
||||
}
|
||||
|
||||
provider, err := openstack.AuthenticatedClient(opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Provider = provider
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,450 @@
|
|||
package openstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/utils"
|
||||
"github.com/docker/machine/drivers"
|
||||
"github.com/docker/machine/ssh"
|
||||
"github.com/docker/machine/state"
|
||||
)
|
||||
|
||||
type Driver struct {
|
||||
AuthUrl string
|
||||
Username string
|
||||
Password string
|
||||
TenantName string
|
||||
TenantId string
|
||||
Region string
|
||||
EndpointType string
|
||||
MachineName string
|
||||
MachineId string
|
||||
FlavorId string
|
||||
ImageId string
|
||||
KeyPairName string
|
||||
NetworkId string
|
||||
SecurityGroups []string
|
||||
FloatingIpPool string
|
||||
SSHUser string
|
||||
SSHPort int
|
||||
storePath string
|
||||
client *Client
|
||||
}
|
||||
|
||||
type CreateFlags struct {
|
||||
AuthUrl *string
|
||||
Username *string
|
||||
Password *string
|
||||
TenantName *string
|
||||
TenantId *string
|
||||
Region *string
|
||||
EndpointType *string
|
||||
FlavorId *string
|
||||
ImageId *string
|
||||
NetworkId *string
|
||||
SecurityGroups *string
|
||||
FloatingIpPool *string
|
||||
SSHUser *string
|
||||
SSHPort *int
|
||||
}
|
||||
|
||||
func init() {
|
||||
drivers.Register("openstack", &drivers.RegisteredDriver{
|
||||
New: NewDriver,
|
||||
RegisterCreateFlags: RegisterCreateFlags,
|
||||
})
|
||||
}
|
||||
|
||||
func RegisterCreateFlags(cmd *flag.FlagSet) interface{} {
|
||||
createFlags := new(CreateFlags)
|
||||
createFlags.AuthUrl = cmd.String(
|
||||
[]string{"-openstack-auth-url"},
|
||||
os.Getenv("OS_AUTH_URL"),
|
||||
"OpenStack authentication URL",
|
||||
)
|
||||
createFlags.Username = cmd.String(
|
||||
[]string{"-openstack-username"},
|
||||
os.Getenv("OS_USERNAME"),
|
||||
"OpenStack username",
|
||||
)
|
||||
createFlags.Password = cmd.String(
|
||||
[]string{"-openstack-password"},
|
||||
os.Getenv("OS_PASSWORD"),
|
||||
"OpenStack password",
|
||||
)
|
||||
createFlags.TenantName = cmd.String(
|
||||
[]string{"-openstack-tenant-name"},
|
||||
os.Getenv("OS_TENANT_NAME"),
|
||||
"OpenStack tenant name",
|
||||
)
|
||||
createFlags.TenantId = cmd.String(
|
||||
[]string{"-openstack-tenant-id"},
|
||||
os.Getenv("OS_TENANT_ID"),
|
||||
"OpenStack tenant id",
|
||||
)
|
||||
createFlags.Region = cmd.String(
|
||||
[]string{"-openstack-region"},
|
||||
os.Getenv("OS_REGION_NAME"),
|
||||
"OpenStack region name",
|
||||
)
|
||||
createFlags.EndpointType = cmd.String(
|
||||
[]string{"-openstack-endpoint-type"},
|
||||
os.Getenv("OS_ENDPOINT_TYPE"),
|
||||
"OpenStack endpoint type (adminURL, internalURL or the default publicURL)",
|
||||
)
|
||||
createFlags.FlavorId = cmd.String(
|
||||
[]string{"-openstack-flavor-id"},
|
||||
"",
|
||||
"OpenStack flavor id to use for the instance",
|
||||
)
|
||||
createFlags.ImageId = cmd.String(
|
||||
[]string{"-openstack-image-id"},
|
||||
"",
|
||||
"OpenStack image id to use for the instance",
|
||||
)
|
||||
createFlags.NetworkId = cmd.String(
|
||||
[]string{"-openstack-net-id"},
|
||||
"",
|
||||
"OpenStack network id the machine will be connected on",
|
||||
)
|
||||
createFlags.SecurityGroups = cmd.String(
|
||||
[]string{"-openstack-sec-groups"},
|
||||
"",
|
||||
"OpenStack comma separated security groups for the machine",
|
||||
)
|
||||
createFlags.FloatingIpPool = cmd.String(
|
||||
[]string{"-openstack-floatingip-pool"},
|
||||
"",
|
||||
"OpenStack floating IP pool to get an IP from to assign to the instance",
|
||||
)
|
||||
createFlags.SSHUser = cmd.String(
|
||||
[]string{"-openstack-ssh-user"},
|
||||
"root",
|
||||
"OpenStack SSH user. Set to root by default",
|
||||
)
|
||||
createFlags.SSHPort = cmd.Int(
|
||||
[]string{"-openstack-ssh-port"},
|
||||
22,
|
||||
"OpenStack SSH port. Set to 22 by default",
|
||||
)
|
||||
return createFlags
|
||||
}
|
||||
|
||||
func NewDriver(storePath string) (drivers.Driver, error) {
|
||||
log.WithFields(log.Fields{
|
||||
"storePath": storePath,
|
||||
}).Info("Instanciate OpenStack driver...")
|
||||
return &Driver{
|
||||
storePath: storePath,
|
||||
client: &Client{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Driver) DriverName() string {
|
||||
return "openstack"
|
||||
}
|
||||
|
||||
func (d *Driver) SetConfigFromFlags(flagsInterface interface{}) error {
|
||||
flags := flagsInterface.(*CreateFlags)
|
||||
d.AuthUrl = *flags.AuthUrl
|
||||
d.Username = *flags.Username
|
||||
d.Password = *flags.Password
|
||||
d.TenantName = *flags.TenantName
|
||||
d.TenantId = *flags.TenantId
|
||||
d.Region = *flags.Region
|
||||
d.EndpointType = *flags.EndpointType
|
||||
d.FlavorId = *flags.FlavorId
|
||||
d.ImageId = *flags.ImageId
|
||||
d.NetworkId = *flags.NetworkId
|
||||
if *flags.SecurityGroups != "" {
|
||||
d.SecurityGroups = strings.Split(*flags.SecurityGroups, ",")
|
||||
}
|
||||
d.FloatingIpPool = *flags.FloatingIpPool
|
||||
d.SSHUser = *flags.SSHUser
|
||||
d.SSHPort = *flags.SSHPort
|
||||
return d.checkConfig()
|
||||
}
|
||||
|
||||
func (d *Driver) GetURL() (string, error) {
|
||||
ip, err := d.GetIP()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if ip == "" {
|
||||
return "", nil
|
||||
}
|
||||
return fmt.Sprintf("tcp://%s:2376", ip), nil
|
||||
}
|
||||
|
||||
func (d *Driver) GetIP() (string, error) {
|
||||
addresses, err := d.client.GetInstanceIpAddresses(d)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
floating := []string{}
|
||||
fixed := []string{}
|
||||
|
||||
for _, address := range addresses {
|
||||
if address.AddressType == Floating {
|
||||
floating = append(floating, address.Address)
|
||||
continue
|
||||
}
|
||||
if address.AddressType == Fixed {
|
||||
fixed = append(fixed, address.Address)
|
||||
continue
|
||||
}
|
||||
log.Warnf("Unknown IP address type : %s", address)
|
||||
}
|
||||
|
||||
if len(floating) == 1 {
|
||||
return d.foundIP(floating[0]), nil
|
||||
} else if len(floating) > 1 {
|
||||
log.Warnf("Multiple floating IP found. Take the first one of %s", floating)
|
||||
return d.foundIP(floating[0]), nil
|
||||
}
|
||||
|
||||
if len(fixed) == 1 {
|
||||
return d.foundIP(fixed[0]), nil
|
||||
} else if len(fixed) > 1 {
|
||||
log.Warnf("Multiple fixed IP found. Take the first one of %s", floating)
|
||||
return d.foundIP(fixed[0]), nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("No IP found for the machine")
|
||||
}
|
||||
|
||||
func (d *Driver) GetState() (state.State, error) {
|
||||
|
||||
log.WithField("MachineId", d.MachineId).Info("Get status for OpenStack instance...")
|
||||
|
||||
s, err := d.client.GetInstanceState(d)
|
||||
if err != nil {
|
||||
return state.None, err
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"MachineId": d.MachineId,
|
||||
"State": s,
|
||||
}).Info("State for OpenStack instance")
|
||||
|
||||
switch s {
|
||||
case "ACTIVE":
|
||||
return state.Running, nil
|
||||
case "PAUSED":
|
||||
return state.Paused, nil
|
||||
case "SUSPENDED":
|
||||
return state.Saved, nil
|
||||
case "SHUTOFF":
|
||||
return state.Stopped, nil
|
||||
case "BUILDING":
|
||||
return state.Starting, nil
|
||||
case "ERROR":
|
||||
return state.Error, nil
|
||||
}
|
||||
return state.None, nil
|
||||
}
|
||||
|
||||
func (d *Driver) Create() error {
|
||||
|
||||
d.setMachineNameIfNotSet()
|
||||
d.KeyPairName = d.MachineName
|
||||
|
||||
if err := d.createSSHKey(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.createMachine(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.waitForInstanceToStart(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.installDocker(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Driver) Start() error {
|
||||
log.WithField("MachineId", d.MachineId).Info("Starting OpenStack instance...")
|
||||
if err := d.client.StartInstance(d); err != nil {
|
||||
return err
|
||||
}
|
||||
return d.waitForInstanceToStart()
|
||||
}
|
||||
|
||||
func (d *Driver) Stop() error {
|
||||
|
||||
log.WithField("MachineId", d.MachineId).Info("Stopping OpenStack instance...")
|
||||
if err := d.client.StopInstance(d); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.WithField("MachineId", d.MachineId).Info("Waiting for the OpenStack instance to stop...")
|
||||
if err := d.client.WaitForInstanceStatus(d, "SHUTOFF", 200); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Driver) Remove() error {
|
||||
log.WithField("MachineId", d.MachineId).Info("Deleting OpenStack instance...")
|
||||
if err := d.client.DeleteInstance(d); err != nil {
|
||||
return err
|
||||
}
|
||||
log.WithField("Name", d.KeyPairName).Info("Deleting Key Pair...")
|
||||
if err := d.client.DeleteKeyPair(d, d.KeyPairName); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Driver) Restart() error {
|
||||
log.WithField("MachineId", d.MachineId).Info("Restarting OpenStack instance...")
|
||||
if err := d.client.RestartInstance(d); err != nil {
|
||||
return err
|
||||
}
|
||||
return d.waitForInstanceToStart()
|
||||
}
|
||||
|
||||
func (d *Driver) Kill() error {
|
||||
return d.Stop()
|
||||
}
|
||||
|
||||
func (d *Driver) Upgrade() error {
|
||||
return fmt.Errorf("Upgrate is currently not available for the OpenStack driver")
|
||||
}
|
||||
|
||||
func (d *Driver) GetSSHCommand(args ...string) (*exec.Cmd, error) {
|
||||
ip, err := d.GetIP()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ssh.GetSSHCommand(ip, d.SSHPort, d.SSHUser, d.sshKeyPath(), args...), nil
|
||||
}
|
||||
|
||||
const (
|
||||
errorMandatoryEnvOrOption string = "%s must be specified either using the environment variable %s or the CLI option %s"
|
||||
errorMandatoryOption string = "%s must be specified using the CLI option %s"
|
||||
errorExclusiveOptions string = "Either %s or %s must be specified, not both"
|
||||
errorMandatoryTenantNameOrId string = "Tenant id or name must be provided either using one of the environment variables OS_TENANT_ID and OS_TENANT_NAME or one of the CLI options --openstack-tenant-id and --openstack-tenant-name"
|
||||
errorWrongEndpointType string = "Endpoint type must be 'publicURL', 'adminURL' or 'internalURL'"
|
||||
)
|
||||
|
||||
func (d *Driver) checkConfig() error {
|
||||
if d.AuthUrl == "" {
|
||||
return fmt.Errorf(errorMandatoryEnvOrOption, "Autentication URL", "OS_AUTH_URL", "--openstack-auth-url")
|
||||
}
|
||||
if d.Username == "" {
|
||||
return fmt.Errorf(errorMandatoryEnvOrOption, "Username", "OS_USERNAME", "--openstack-username")
|
||||
}
|
||||
if d.Password == "" {
|
||||
return fmt.Errorf(errorMandatoryEnvOrOption, "Password", "OS_PASSWORD", "--openstack-password")
|
||||
}
|
||||
if d.TenantName == "" && d.TenantId == "" {
|
||||
return fmt.Errorf(errorMandatoryTenantNameOrId)
|
||||
}
|
||||
if d.TenantName != "" && d.TenantId != "" {
|
||||
return fmt.Errorf(errorExclusiveOptions, "tenant id", "tenant name")
|
||||
}
|
||||
if d.FlavorId == "" {
|
||||
return fmt.Errorf(errorMandatoryOption, "Flavor id", "--openstack-flavor-id")
|
||||
}
|
||||
if d.ImageId == "" {
|
||||
return fmt.Errorf(errorMandatoryOption, "Image id", "--openstack-image-id")
|
||||
}
|
||||
if d.EndpointType != "" && (d.EndpointType != "publicURL" || d.EndpointType != "adminURL" || d.EndpointType != "internalURL") {
|
||||
return fmt.Errorf(errorWrongEndpointType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Driver) foundIP(ip string) string {
|
||||
log.WithFields(log.Fields{
|
||||
"IP": ip,
|
||||
"MachineId": d.MachineId,
|
||||
}).Info("IP address found")
|
||||
return ip
|
||||
}
|
||||
|
||||
func (d *Driver) createSSHKey() error {
|
||||
log.WithField("Name", d.KeyPairName).Info("Creating Key Pair...")
|
||||
if err := ssh.GenerateSSHKey(d.sshKeyPath()); err != nil {
|
||||
return err
|
||||
}
|
||||
publicKey, err := ioutil.ReadFile(d.publicSSHKeyPath())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.client.CreateKeyPair(d, d.KeyPairName, string(publicKey)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Driver) createMachine() error {
|
||||
log.WithFields(log.Fields{
|
||||
"FlavorId": d.FlavorId,
|
||||
"ImageId": d.ImageId,
|
||||
}).Info("Creating OpenStack instance...")
|
||||
instanceId, err := d.client.CreateInstance(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.MachineId = instanceId
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Driver) waitForInstanceToStart() error {
|
||||
log.WithField("MachineId", d.MachineId).Info("Waiting for the OpenStack instance to start...")
|
||||
if err := d.client.WaitForInstanceStatus(d, "ACTIVE", 200); err != nil {
|
||||
return err
|
||||
}
|
||||
ip, err := d.GetIP()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ssh.WaitForTCP(fmt.Sprintf("%s:%d", ip, d.SSHPort))
|
||||
}
|
||||
|
||||
func (d *Driver) installDocker() error {
|
||||
log.WithField("MachineId", d.MachineId).Info("Installing dock on the machine")
|
||||
cmdTemplate := "%scurl -sSL https://gist.githubusercontent.com/smashwilson/1a286139720a28ac6ead/raw/41d93c57ea2e86815cdfbfec42aaa696034afcc8/setup-docker.sh | /bin/bash"
|
||||
var cmd string
|
||||
if d.SSHUser == "root" {
|
||||
cmd = fmt.Sprintf(cmdTemplate, "")
|
||||
} else {
|
||||
cmd = fmt.Sprintf(cmdTemplate, "sudo ")
|
||||
}
|
||||
log.Infof(cmd)
|
||||
sshCmd, err := d.GetSSHCommand(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := sshCmd.Run(); err != nil {
|
||||
log.Warnf("Docker installation failed: %v", err)
|
||||
log.Warnf("The machine is not ready to run docker containers")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Driver) sshKeyPath() string {
|
||||
return path.Join(d.storePath, "id_rsa")
|
||||
}
|
||||
|
||||
func (d *Driver) publicSSHKeyPath() string {
|
||||
return d.sshKeyPath() + ".pub"
|
||||
}
|
||||
|
||||
func (d *Driver) setMachineNameIfNotSet() {
|
||||
if d.MachineName == "" {
|
||||
d.MachineName = fmt.Sprintf("docker-host-%s", utils.GenerateRandomID())
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue