mirror of https://github.com/docker/docs.git
Support floating IP allocation and assignation
Signed-off-by: Guillaume Giamarchi <guillaume.giamarchi@gmail.com>
This commit is contained in:
parent
edec8cd024
commit
a2d64fe5c0
|
@ -30,9 +30,13 @@ type Client interface {
|
|||
GetInstanceIpAddresses(d *Driver) ([]IpAddress, error)
|
||||
CreateKeyPair(d *Driver, name string, publicKey string) error
|
||||
DeleteKeyPair(d *Driver, name string) error
|
||||
GetNetworkId(d *Driver, name string) (string, error)
|
||||
GetFlavorId(d *Driver, name string) (string, error)
|
||||
GetImageId(d *Driver, name string) (string, error)
|
||||
GetNetworkId(d *Driver) (string, error)
|
||||
GetFlavorId(d *Driver) (string, error)
|
||||
GetImageId(d *Driver) (string, error)
|
||||
AssignFloatingIP(d *Driver, floatingIp *FloatingIp, portId string) error
|
||||
GetFloatingIPs(d *Driver) ([]FloatingIp, error)
|
||||
GetFloatingIpPoolId(d *Driver) (string, error)
|
||||
GetInstancePortId(d *Driver) (string, error)
|
||||
}
|
||||
|
||||
type GenericClient struct {
|
||||
|
@ -77,16 +81,18 @@ type IpAddress struct {
|
|||
Mac string
|
||||
}
|
||||
|
||||
type FloatingIp struct {
|
||||
Id string
|
||||
Ip string
|
||||
NetworkId string
|
||||
PortId string
|
||||
}
|
||||
|
||||
func (c *GenericClient) 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
|
||||
}
|
||||
|
||||
|
@ -153,8 +159,16 @@ func (c *GenericClient) GetInstanceIpAddresses(d *Driver) ([]IpAddress, error) {
|
|||
return addresses, nil
|
||||
}
|
||||
|
||||
func (c *GenericClient) GetNetworkId(d *Driver, networkName string) (string, error) {
|
||||
opts := networks.ListOpts{Name: d.NetworkName}
|
||||
func (c *GenericClient) GetNetworkId(d *Driver) (string, error) {
|
||||
return c.getNetworkId(d, d.NetworkName)
|
||||
}
|
||||
|
||||
func (c *GenericClient) GetFloatingIpPoolId(d *Driver) (string, error) {
|
||||
return c.getNetworkId(d, d.FloatingIpPool)
|
||||
}
|
||||
|
||||
func (c *GenericClient) getNetworkId(d *Driver, networkName string) (string, error) {
|
||||
opts := networks.ListOpts{Name: networkName}
|
||||
pager := networks.List(c.Network, opts)
|
||||
networkId := ""
|
||||
|
||||
|
@ -165,7 +179,7 @@ func (c *GenericClient) GetNetworkId(d *Driver, networkName string) (string, err
|
|||
}
|
||||
|
||||
for _, n := range networkList {
|
||||
if n.Name == d.NetworkName {
|
||||
if n.Name == networkName {
|
||||
networkId = n.ID
|
||||
return false, nil
|
||||
}
|
||||
|
@ -177,7 +191,7 @@ func (c *GenericClient) GetNetworkId(d *Driver, networkName string) (string, err
|
|||
return networkId, err
|
||||
}
|
||||
|
||||
func (c *GenericClient) GetFlavorId(d *Driver, flavorName string) (string, error) {
|
||||
func (c *GenericClient) GetFlavorId(d *Driver) (string, error) {
|
||||
pager := flavors.ListDetail(c.Compute, nil)
|
||||
flavorId := ""
|
||||
|
||||
|
@ -200,8 +214,8 @@ func (c *GenericClient) GetFlavorId(d *Driver, flavorName string) (string, error
|
|||
return flavorId, err
|
||||
}
|
||||
|
||||
func (c *GenericClient) GetImageId(d *Driver, imageName string) (string, error) {
|
||||
opts := images.ListOpts{Name: imageName}
|
||||
func (c *GenericClient) GetImageId(d *Driver) (string, error) {
|
||||
opts := images.ListOpts{Name: d.ImageName}
|
||||
pager := images.ListDetail(c.Compute, opts)
|
||||
imageId := ""
|
||||
|
||||
|
@ -250,16 +264,48 @@ func (c *GenericClient) GetServerDetail(d *Driver) (*servers.Server, error) {
|
|||
return server, nil
|
||||
}
|
||||
|
||||
func (c *GenericClient) getFloatingIPs(d *Driver) ([]string, error) {
|
||||
pager := floatingips.List(c.Network, floatingips.ListOpts{})
|
||||
func (c *GenericClient) AssignFloatingIP(d *Driver, floatingIp *FloatingIp, portId string) error {
|
||||
if floatingIp.Id == "" {
|
||||
f, err := floatingips.Create(c.Network, floatingips.CreateOpts{
|
||||
FloatingNetworkID: d.FloatingIpPoolId,
|
||||
PortID: portId,
|
||||
}).Extract()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
floatingIp.Id = f.ID
|
||||
floatingIp.Ip = f.FloatingIP
|
||||
floatingIp.NetworkId = f.FloatingNetworkID
|
||||
floatingIp.PortId = f.PortID
|
||||
return nil
|
||||
}
|
||||
_, err := floatingips.Update(c.Network, floatingIp.Id, floatingips.UpdateOpts{
|
||||
PortID: portId,
|
||||
}).Extract()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *GenericClient) GetFloatingIPs(d *Driver) ([]FloatingIp, error) {
|
||||
pager := floatingips.List(c.Network, floatingips.ListOpts{
|
||||
FloatingNetworkID: d.FloatingIpPoolId,
|
||||
})
|
||||
|
||||
ips := []FloatingIp{}
|
||||
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.Debug("### FloatingIP => %s", f)
|
||||
ips = append(ips, FloatingIp{
|
||||
Id: f.ID,
|
||||
Ip: f.FloatingIP,
|
||||
NetworkId: f.FloatingNetworkID,
|
||||
PortId: f.PortID,
|
||||
})
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
|
@ -267,29 +313,32 @@ func (c *GenericClient) getFloatingIPs(d *Driver) ([]string, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, nil
|
||||
return ips, nil
|
||||
}
|
||||
|
||||
func (c *GenericClient) getPorts(d *Driver) ([]string, error) {
|
||||
func (c *GenericClient) GetInstancePortId(d *Driver) (string, error) {
|
||||
pager := ports.List(c.Network, ports.ListOpts{
|
||||
DeviceID: d.MachineId,
|
||||
DeviceID: d.MachineId,
|
||||
NetworkID: d.NetworkId,
|
||||
})
|
||||
|
||||
var portId string
|
||||
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.Debug("### Port => %s", port)
|
||||
portId = port.ID
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
return nil, nil
|
||||
return portId, nil
|
||||
}
|
||||
|
||||
func (c *GenericClient) InitComputeClient(d *Driver) error {
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"os/exec"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/codegangsta/cli"
|
||||
|
@ -16,28 +17,30 @@ import (
|
|||
)
|
||||
|
||||
type Driver struct {
|
||||
AuthUrl string
|
||||
Username string
|
||||
Password string
|
||||
TenantName string
|
||||
TenantId string
|
||||
Region string
|
||||
EndpointType string
|
||||
MachineName string
|
||||
MachineId string
|
||||
FlavorName string
|
||||
FlavorId string
|
||||
ImageName string
|
||||
ImageId string
|
||||
KeyPairName string
|
||||
NetworkName string
|
||||
NetworkId string
|
||||
SecurityGroups []string
|
||||
FloatingIpPool string
|
||||
SSHUser string
|
||||
SSHPort int
|
||||
storePath string
|
||||
client Client
|
||||
AuthUrl string
|
||||
Username string
|
||||
Password string
|
||||
TenantName string
|
||||
TenantId string
|
||||
Region string
|
||||
EndpointType string
|
||||
MachineName string
|
||||
MachineId string
|
||||
FlavorName string
|
||||
FlavorId string
|
||||
ImageName string
|
||||
ImageId string
|
||||
KeyPairName string
|
||||
NetworkName string
|
||||
NetworkId string
|
||||
SecurityGroups []string
|
||||
FloatingIpPool string
|
||||
FloatingIpPoolId string
|
||||
SSHUser string
|
||||
SSHPort int
|
||||
Ip string
|
||||
storePath string
|
||||
client Client
|
||||
}
|
||||
|
||||
type CreateFlags struct {
|
||||
|
@ -218,44 +221,34 @@ func (d *Driver) GetURL() (string, error) {
|
|||
}
|
||||
|
||||
func (d *Driver) GetIP() (string, error) {
|
||||
if d.Ip != "" {
|
||||
return d.Ip, nil
|
||||
}
|
||||
|
||||
log.WithField("MachineId", d.MachineId).Debug("Looking for the IP address...")
|
||||
|
||||
if err := d.initCompute(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
addresses, err := d.client.GetInstanceIpAddresses(d)
|
||||
if err != nil {
|
||||
return "", err
|
||||
addressType := Fixed
|
||||
if d.FloatingIpPool != "" {
|
||||
addressType = Floating
|
||||
}
|
||||
|
||||
floating := []string{}
|
||||
fixed := []string{}
|
||||
|
||||
for _, address := range addresses {
|
||||
if address.AddressType == Floating {
|
||||
floating = append(floating, address.Address)
|
||||
continue
|
||||
// Looking for the IP address in a retry loop to deal with OpenStack latency
|
||||
for retryCount := 0; retryCount < 200; retryCount++ {
|
||||
addresses, err := d.client.GetInstanceIpAddresses(d)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if address.AddressType == Fixed {
|
||||
fixed = append(fixed, address.Address)
|
||||
continue
|
||||
for _, a := range addresses {
|
||||
if a.AddressType == addressType {
|
||||
return a.Address, nil
|
||||
}
|
||||
}
|
||||
log.Warnf("Unknown IP address type : %s", address)
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
|
@ -308,7 +301,18 @@ func (d *Driver) Create() error {
|
|||
if err := d.createMachine(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.waitForInstanceToStart(); err != nil {
|
||||
if err := d.waitForInstanceActive(); err != nil {
|
||||
return err
|
||||
}
|
||||
if d.FloatingIpPool != "" {
|
||||
if err := d.assignFloatingIp(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := d.lookForIpAddress(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.waitForSSHServer(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.installDocker(); err != nil {
|
||||
|
@ -389,7 +393,7 @@ func (d *Driver) GetSSHCommand(args ...string) (*exec.Cmd, error) {
|
|||
args = []string{"sudo", "sh", "-c", fmt.Sprintf("'%s'", cmd)}
|
||||
}
|
||||
|
||||
log.Debug("Command: %s", args)
|
||||
log.WithField("MachineId", d.MachineId).Debug("Command: %s", args)
|
||||
return ssh.GetSSHCommand(ip, d.SSHPort, d.SSHUser, d.sshKeyPath(), args...), nil
|
||||
}
|
||||
|
||||
|
@ -441,21 +445,13 @@ func (d *Driver) checkConfig() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *Driver) foundIP(ip string) string {
|
||||
log.WithFields(log.Fields{
|
||||
"IP": ip,
|
||||
"MachineId": d.MachineId,
|
||||
}).Debug("IP address found")
|
||||
return ip
|
||||
}
|
||||
|
||||
func (d *Driver) resolveIds() error {
|
||||
if d.NetworkName != "" {
|
||||
if err := d.initNetwork(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
networkId, err := d.client.GetNetworkId(d, d.NetworkName)
|
||||
networkId, err := d.client.GetNetworkId(d)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -476,7 +472,7 @@ func (d *Driver) resolveIds() error {
|
|||
if err := d.initCompute(); err != nil {
|
||||
return err
|
||||
}
|
||||
flavorId, err := d.client.GetFlavorId(d, d.FlavorName)
|
||||
flavorId, err := d.client.GetFlavorId(d)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -497,7 +493,7 @@ func (d *Driver) resolveIds() error {
|
|||
if err := d.initCompute(); err != nil {
|
||||
return err
|
||||
}
|
||||
imageId, err := d.client.GetImageId(d, d.ImageName)
|
||||
imageId, err := d.client.GetImageId(d)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -514,6 +510,27 @@ func (d *Driver) resolveIds() error {
|
|||
}).Debug("Found image id using its name")
|
||||
}
|
||||
|
||||
if d.FloatingIpPool != "" {
|
||||
if err := d.initNetwork(); err != nil {
|
||||
return err
|
||||
}
|
||||
f, err := d.client.GetFloatingIpPoolId(d)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if f == "" {
|
||||
return fmt.Errorf(errorUnknownNetworkName, d.FloatingIpPool)
|
||||
}
|
||||
|
||||
d.FloatingIpPoolId = f
|
||||
log.WithFields(log.Fields{
|
||||
"Name": d.FloatingIpPool,
|
||||
"ID": d.FloatingIpPoolId,
|
||||
}).Debug("Found floating IP pool id using its name")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -573,18 +590,94 @@ func (d *Driver) createMachine() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *Driver) waitForInstanceToStart() error {
|
||||
log.WithField("MachineId", d.MachineId).Debug("Waiting for the OpenStack instance to start...")
|
||||
func (d *Driver) assignFloatingIp() error {
|
||||
|
||||
if err := d.initNetwork(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
portId, err := d.client.GetInstancePortId(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ips, err := d.client.GetFloatingIPs(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var floatingIp *FloatingIp
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"MachineId": d.MachineId,
|
||||
"Pool": d.FloatingIpPool,
|
||||
}).Debugf("Looking for an available floating IP")
|
||||
|
||||
for _, ip := range ips {
|
||||
if ip.PortId == "" {
|
||||
log.WithFields(log.Fields{
|
||||
"MachineId": d.MachineId,
|
||||
"IP": ip.Ip,
|
||||
}).Debugf("Available floating IP found")
|
||||
floatingIp = &ip
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if floatingIp == nil {
|
||||
floatingIp = &FloatingIp{}
|
||||
log.WithField("MachineId", d.MachineId).Debugf("No available floating IP found. Allocating a new one...")
|
||||
} else {
|
||||
log.WithField("MachineId", d.MachineId).Debugf("Assigning floating IP to the instance")
|
||||
}
|
||||
|
||||
if err := d.client.AssignFloatingIP(d, floatingIp, portId); err != nil {
|
||||
return err
|
||||
}
|
||||
d.Ip = floatingIp.Ip
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Driver) waitForInstanceActive() error {
|
||||
log.WithField("MachineId", d.MachineId).Debug("Waiting for the OpenStack instance to be ACTIVE...")
|
||||
if err := d.client.WaitForInstanceStatus(d, "ACTIVE", 200); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Driver) lookForIpAddress() error {
|
||||
ip, err := d.GetIP()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Ip = ip
|
||||
log.WithFields(log.Fields{
|
||||
"IP": ip,
|
||||
"MachineId": d.MachineId,
|
||||
}).Debug("IP address found")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Driver) waitForSSHServer() error {
|
||||
ip, err := d.GetIP()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.WithFields(log.Fields{
|
||||
"MachineId": d.MachineId,
|
||||
"IP": ip,
|
||||
}).Debug("Waiting for the SSH server to be started...")
|
||||
return ssh.WaitForTCP(fmt.Sprintf("%s:%d", ip, d.SSHPort))
|
||||
}
|
||||
|
||||
func (d *Driver) waitForInstanceToStart() error {
|
||||
if err := d.waitForInstanceActive(); err != nil {
|
||||
return err
|
||||
}
|
||||
return d.waitForSSHServer()
|
||||
}
|
||||
|
||||
func (d *Driver) installDocker() error {
|
||||
log.WithField("MachineId", d.MachineId).Debug("Adding key to authorized-keys.d...")
|
||||
|
||||
|
|
Loading…
Reference in New Issue