Files
docker-machine/drivers/openstack/openstack.go

683 lines
17 KiB
Go
Raw Normal View History

package openstack
import (
"fmt"
"io/ioutil"
"strings"
"time"
"github.com/codegangsta/cli"
Make libmachine usable by outside world - Clear out some cruft tightly coupling libmachine to filestore - Comment out drivers other than virtualbox for now - Change way too many things - Mostly, break out the code to be more modular. - Destroy all traces of "provider" in its current form. It will be brought back as something more sensible, instead of something which overlaps in function with both Host and Store. - Fix mis-managed config passthru - Remove a few instances of state stored in env vars - This should be explicitly communicated in Go-land, not through the shell. - Rename "store" module to "persist" - This is done mostly to avoid confusion about the fact that a concrete instance of a "Store" interface is oftentimes referred to as "store" in the code. - Rip out repetitive antipattern for getting store - This replaces the previous repetive idiom for getting the cert info, and consequently the store, with a much less repetitive idiom. - Also, some redundant methods in commands.go for accessing hosts have either been simplified or removed entirely. - First steps towards fixing up tests - Test progress continues - Replace unit tests with integration tests - MAKE ALL UNIT TESTS PASS YAY - Add helper test files - Don't write to disk in libmachine/host - Heh.. coverage check strikes again - Fix remove code - Move cert code around - Continued progress: simplify Driver - Fixups and make creation work with new model - Move drivers module inside of libmachine - Move ssh module inside of libmachine - Move state module to libmachine - Move utils module to libmachine - Move version module to libmachine - Move log module to libmachine - Modify some constructor methods around - Change Travis build dep structure - Boring gofmt fix - Add version module - Move NewHost to store - Update some boring cert path infos to make API easier to use - Fix up some issues around the new model - Clean up some cert path stuff - Don't use shady functions to get store path :D - Continue artifact work - Fix silly machines dir bug - Continue fixing silly path issues - Change up output of vbm a bit - Continue work to make example go - Change output a little more - Last changes needed to make create finish properly - Fix config.go to use libmachine - Cut down code duplication and make both methods work with libmachine - Add pluggable logging implementation - Return error when machine already in desired state - Update example to show log method - Fix file:// bug - Fix Swarm defaults - Remove unused TLS settings from Engine and Swarm options - Remove spurious error - Correct bug detecting if migration was performed - Fix compilation errors from tests - Fix most of remaining test issues - Fix final silly bug in tests - Remove extraneous debug code - Add -race to test command - Appease the gofmt - Appease the generate coverage - Making executive decision to remove Travis coverage check In the early days I thought this would be a good idea because it would encourage people to write tests in case they added a new module. Well, in fact it has just turned into a giant nuisance and made refactoring work like this even more difficult. - Move Get to Load - Move HostListItem code to CLI Signed-off-by: Nathan LeClaire <nathan.leclaire@gmail.com>
2015-08-18 11:26:42 +09:00
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/log"
"github.com/docker/machine/libmachine/mcnutils"
"github.com/docker/machine/libmachine/ssh"
"github.com/docker/machine/libmachine/state"
)
type Driver struct {
*drivers.BaseDriver
AuthUrl string
ActiveTimeout int
Insecure bool
DomainID string
DomainName string
Username string
Password string
TenantName string
TenantId string
Region string
AvailabilityZone string
EndpointType string
MachineId string
FlavorName string
FlavorId string
ImageName string
ImageId string
KeyPairName string
NetworkName string
NetworkId string
SecurityGroups []string
FloatingIpPool string
FloatingIpPoolId string
IpVersion int
client Client
}
Make libmachine usable by outside world - Clear out some cruft tightly coupling libmachine to filestore - Comment out drivers other than virtualbox for now - Change way too many things - Mostly, break out the code to be more modular. - Destroy all traces of "provider" in its current form. It will be brought back as something more sensible, instead of something which overlaps in function with both Host and Store. - Fix mis-managed config passthru - Remove a few instances of state stored in env vars - This should be explicitly communicated in Go-land, not through the shell. - Rename "store" module to "persist" - This is done mostly to avoid confusion about the fact that a concrete instance of a "Store" interface is oftentimes referred to as "store" in the code. - Rip out repetitive antipattern for getting store - This replaces the previous repetive idiom for getting the cert info, and consequently the store, with a much less repetitive idiom. - Also, some redundant methods in commands.go for accessing hosts have either been simplified or removed entirely. - First steps towards fixing up tests - Test progress continues - Replace unit tests with integration tests - MAKE ALL UNIT TESTS PASS YAY - Add helper test files - Don't write to disk in libmachine/host - Heh.. coverage check strikes again - Fix remove code - Move cert code around - Continued progress: simplify Driver - Fixups and make creation work with new model - Move drivers module inside of libmachine - Move ssh module inside of libmachine - Move state module to libmachine - Move utils module to libmachine - Move version module to libmachine - Move log module to libmachine - Modify some constructor methods around - Change Travis build dep structure - Boring gofmt fix - Add version module - Move NewHost to store - Update some boring cert path infos to make API easier to use - Fix up some issues around the new model - Clean up some cert path stuff - Don't use shady functions to get store path :D - Continue artifact work - Fix silly machines dir bug - Continue fixing silly path issues - Change up output of vbm a bit - Continue work to make example go - Change output a little more - Last changes needed to make create finish properly - Fix config.go to use libmachine - Cut down code duplication and make both methods work with libmachine - Add pluggable logging implementation - Return error when machine already in desired state - Update example to show log method - Fix file:// bug - Fix Swarm defaults - Remove unused TLS settings from Engine and Swarm options - Remove spurious error - Correct bug detecting if migration was performed - Fix compilation errors from tests - Fix most of remaining test issues - Fix final silly bug in tests - Remove extraneous debug code - Add -race to test command - Appease the gofmt - Appease the generate coverage - Making executive decision to remove Travis coverage check In the early days I thought this would be a good idea because it would encourage people to write tests in case they added a new module. Well, in fact it has just turned into a giant nuisance and made refactoring work like this even more difficult. - Move Get to Load - Move HostListItem code to CLI Signed-off-by: Nathan LeClaire <nathan.leclaire@gmail.com>
2015-08-18 11:26:42 +09:00
const (
defaultSSHUser = "root"
defaultSSHPort = 22
defaultActiveTimeout = 200
)
func init() {
drivers.Register("openstack", &drivers.RegisteredDriver{
GetCreateFlags: GetCreateFlags,
})
}
func GetCreateFlags() []cli.Flag {
return []cli.Flag{
cli.StringFlag{
EnvVar: "OS_AUTH_URL",
Name: "openstack-auth-url",
Usage: "OpenStack authentication URL",
Value: "",
},
cli.BoolFlag{
EnvVar: "OS_INSECURE",
Name: "openstack-insecure",
Usage: "Disable TLS credential checking.",
},
cli.StringFlag{
EnvVar: "OS_DOMAIN_ID",
Name: "openstack-domain-id",
Usage: "OpenStack domain ID (identity v3 only)",
Value: "",
},
cli.StringFlag{
EnvVar: "OS_DOMAIN_NAME",
Name: "openstack-domain-name",
Usage: "OpenStack domain name (identity v3 only)",
Value: "",
},
cli.StringFlag{
EnvVar: "OS_USERNAME",
Name: "openstack-username",
Usage: "OpenStack username",
Value: "",
},
cli.StringFlag{
EnvVar: "OS_PASSWORD",
Name: "openstack-password",
Usage: "OpenStack password",
Value: "",
},
cli.StringFlag{
EnvVar: "OS_TENANT_NAME",
Name: "openstack-tenant-name",
Usage: "OpenStack tenant name",
Value: "",
},
cli.StringFlag{
EnvVar: "OS_TENANT_ID",
Name: "openstack-tenant-id",
Usage: "OpenStack tenant id",
Value: "",
},
cli.StringFlag{
EnvVar: "OS_REGION_NAME",
Name: "openstack-region",
Usage: "OpenStack region name",
Value: "",
},
cli.StringFlag{
EnvVar: "OS_AVAILABILITY_ZONE",
Name: "openstack-availability-zone",
Usage: "OpenStack availability zone",
Value: "",
},
cli.StringFlag{
EnvVar: "OS_ENDPOINT_TYPE",
Name: "openstack-endpoint-type",
Usage: "OpenStack endpoint type (adminURL, internalURL or publicURL)",
Value: "",
},
cli.StringFlag{
EnvVar: "OS_FLAVOR_ID",
Name: "openstack-flavor-id",
Usage: "OpenStack flavor id to use for the instance",
Value: "",
},
cli.StringFlag{
EnvVar: "OS_FLAVOR_NAME",
Name: "openstack-flavor-name",
Usage: "OpenStack flavor name to use for the instance",
Value: "",
},
cli.StringFlag{
EnvVar: "OS_IMAGE_ID",
Name: "openstack-image-id",
Usage: "OpenStack image id to use for the instance",
Value: "",
},
cli.StringFlag{
EnvVar: "OS_IMAGE_NAME",
Name: "openstack-image-name",
Usage: "OpenStack image name to use for the instance",
Value: "",
},
cli.StringFlag{
EnvVar: "OS_NETWORK_ID",
Name: "openstack-net-id",
Usage: "OpenStack network id the machine will be connected on",
Value: "",
},
cli.StringFlag{
EnvVar: "OS_NETWORK_NAME",
Name: "openstack-net-name",
Usage: "OpenStack network name the machine will be connected on",
Value: "",
},
cli.StringFlag{
EnvVar: "OS_SECURITY_GROUPS",
Name: "openstack-sec-groups",
Usage: "OpenStack comma separated security groups for the machine",
Value: "",
},
cli.StringFlag{
EnvVar: "OS_FLOATINGIP_POOL",
Name: "openstack-floatingip-pool",
Usage: "OpenStack floating IP pool to get an IP from to assign to the instance",
Value: "",
},
cli.IntFlag{
EnvVar: "OS_IP_VERSION",
Name: "openstack-ip-version",
Usage: "OpenStack version of IP address assigned for the machine",
Value: 4,
},
cli.StringFlag{
EnvVar: "OS_SSH_USER",
Name: "openstack-ssh-user",
Usage: "OpenStack SSH user",
Value: defaultSSHUser,
},
cli.IntFlag{
EnvVar: "OS_SSH_PORT",
Name: "openstack-ssh-port",
Usage: "OpenStack SSH port",
Value: defaultSSHPort,
},
cli.IntFlag{
EnvVar: "OS_ACTIVE_TIMEOUT",
Name: "openstack-active-timeout",
Usage: "OpenStack active timeout",
Value: defaultActiveTimeout,
},
}
}
Make libmachine usable by outside world - Clear out some cruft tightly coupling libmachine to filestore - Comment out drivers other than virtualbox for now - Change way too many things - Mostly, break out the code to be more modular. - Destroy all traces of "provider" in its current form. It will be brought back as something more sensible, instead of something which overlaps in function with both Host and Store. - Fix mis-managed config passthru - Remove a few instances of state stored in env vars - This should be explicitly communicated in Go-land, not through the shell. - Rename "store" module to "persist" - This is done mostly to avoid confusion about the fact that a concrete instance of a "Store" interface is oftentimes referred to as "store" in the code. - Rip out repetitive antipattern for getting store - This replaces the previous repetive idiom for getting the cert info, and consequently the store, with a much less repetitive idiom. - Also, some redundant methods in commands.go for accessing hosts have either been simplified or removed entirely. - First steps towards fixing up tests - Test progress continues - Replace unit tests with integration tests - MAKE ALL UNIT TESTS PASS YAY - Add helper test files - Don't write to disk in libmachine/host - Heh.. coverage check strikes again - Fix remove code - Move cert code around - Continued progress: simplify Driver - Fixups and make creation work with new model - Move drivers module inside of libmachine - Move ssh module inside of libmachine - Move state module to libmachine - Move utils module to libmachine - Move version module to libmachine - Move log module to libmachine - Modify some constructor methods around - Change Travis build dep structure - Boring gofmt fix - Add version module - Move NewHost to store - Update some boring cert path infos to make API easier to use - Fix up some issues around the new model - Clean up some cert path stuff - Don't use shady functions to get store path :D - Continue artifact work - Fix silly machines dir bug - Continue fixing silly path issues - Change up output of vbm a bit - Continue work to make example go - Change output a little more - Last changes needed to make create finish properly - Fix config.go to use libmachine - Cut down code duplication and make both methods work with libmachine - Add pluggable logging implementation - Return error when machine already in desired state - Update example to show log method - Fix file:// bug - Fix Swarm defaults - Remove unused TLS settings from Engine and Swarm options - Remove spurious error - Correct bug detecting if migration was performed - Fix compilation errors from tests - Fix most of remaining test issues - Fix final silly bug in tests - Remove extraneous debug code - Add -race to test command - Appease the gofmt - Appease the generate coverage - Making executive decision to remove Travis coverage check In the early days I thought this would be a good idea because it would encourage people to write tests in case they added a new module. Well, in fact it has just turned into a giant nuisance and made refactoring work like this even more difficult. - Move Get to Load - Move HostListItem code to CLI Signed-off-by: Nathan LeClaire <nathan.leclaire@gmail.com>
2015-08-18 11:26:42 +09:00
func NewDriver(hostName, storePath string) drivers.Driver {
return NewDerivedDriver(hostName, storePath)
}
Make libmachine usable by outside world - Clear out some cruft tightly coupling libmachine to filestore - Comment out drivers other than virtualbox for now - Change way too many things - Mostly, break out the code to be more modular. - Destroy all traces of "provider" in its current form. It will be brought back as something more sensible, instead of something which overlaps in function with both Host and Store. - Fix mis-managed config passthru - Remove a few instances of state stored in env vars - This should be explicitly communicated in Go-land, not through the shell. - Rename "store" module to "persist" - This is done mostly to avoid confusion about the fact that a concrete instance of a "Store" interface is oftentimes referred to as "store" in the code. - Rip out repetitive antipattern for getting store - This replaces the previous repetive idiom for getting the cert info, and consequently the store, with a much less repetitive idiom. - Also, some redundant methods in commands.go for accessing hosts have either been simplified or removed entirely. - First steps towards fixing up tests - Test progress continues - Replace unit tests with integration tests - MAKE ALL UNIT TESTS PASS YAY - Add helper test files - Don't write to disk in libmachine/host - Heh.. coverage check strikes again - Fix remove code - Move cert code around - Continued progress: simplify Driver - Fixups and make creation work with new model - Move drivers module inside of libmachine - Move ssh module inside of libmachine - Move state module to libmachine - Move utils module to libmachine - Move version module to libmachine - Move log module to libmachine - Modify some constructor methods around - Change Travis build dep structure - Boring gofmt fix - Add version module - Move NewHost to store - Update some boring cert path infos to make API easier to use - Fix up some issues around the new model - Clean up some cert path stuff - Don't use shady functions to get store path :D - Continue artifact work - Fix silly machines dir bug - Continue fixing silly path issues - Change up output of vbm a bit - Continue work to make example go - Change output a little more - Last changes needed to make create finish properly - Fix config.go to use libmachine - Cut down code duplication and make both methods work with libmachine - Add pluggable logging implementation - Return error when machine already in desired state - Update example to show log method - Fix file:// bug - Fix Swarm defaults - Remove unused TLS settings from Engine and Swarm options - Remove spurious error - Correct bug detecting if migration was performed - Fix compilation errors from tests - Fix most of remaining test issues - Fix final silly bug in tests - Remove extraneous debug code - Add -race to test command - Appease the gofmt - Appease the generate coverage - Making executive decision to remove Travis coverage check In the early days I thought this would be a good idea because it would encourage people to write tests in case they added a new module. Well, in fact it has just turned into a giant nuisance and made refactoring work like this even more difficult. - Move Get to Load - Move HostListItem code to CLI Signed-off-by: Nathan LeClaire <nathan.leclaire@gmail.com>
2015-08-18 11:26:42 +09:00
func NewDerivedDriver(hostName, storePath string) *Driver {
return &Driver{
client: &GenericClient{},
ActiveTimeout: defaultActiveTimeout,
BaseDriver: &drivers.BaseDriver{
SSHUser: defaultSSHUser,
SSHPort: defaultSSHPort,
MachineName: hostName,
StorePath: storePath,
},
}
}
func (d *Driver) GetSSHHostname() (string, error) {
return d.GetIP()
}
func (d *Driver) DriverName() string {
return "openstack"
}
func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error {
d.AuthUrl = flags.String("openstack-auth-url")
d.ActiveTimeout = flags.Int("openstack-active-timeout")
d.Insecure = flags.Bool("openstack-insecure")
d.DomainID = flags.String("openstack-domain-id")
d.DomainName = flags.String("openstack-domain-name")
d.Username = flags.String("openstack-username")
d.Password = flags.String("openstack-password")
d.TenantName = flags.String("openstack-tenant-name")
d.TenantId = flags.String("openstack-tenant-id")
d.Region = flags.String("openstack-region")
d.AvailabilityZone = flags.String("openstack-availability-zone")
d.EndpointType = flags.String("openstack-endpoint-type")
d.FlavorId = flags.String("openstack-flavor-id")
d.FlavorName = flags.String("openstack-flavor-name")
d.ImageId = flags.String("openstack-image-id")
d.ImageName = flags.String("openstack-image-name")
d.NetworkId = flags.String("openstack-net-id")
d.NetworkName = flags.String("openstack-net-name")
if flags.String("openstack-sec-groups") != "" {
d.SecurityGroups = strings.Split(flags.String("openstack-sec-groups"), ",")
}
d.FloatingIpPool = flags.String("openstack-floatingip-pool")
d.IpVersion = flags.Int("openstack-ip-version")
d.SSHUser = flags.String("openstack-ssh-user")
d.SSHPort = flags.Int("openstack-ssh-port")
d.SwarmMaster = flags.Bool("swarm-master")
d.SwarmHost = flags.String("swarm-host")
d.SwarmDiscovery = flags.String("swarm-discovery")
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) {
if d.IPAddress != "" {
return d.IPAddress, nil
}
log.WithField("MachineId", d.MachineId).Debug("Looking for the IP address...")
if err := d.initCompute(); err != nil {
return "", err
}
addressType := Fixed
if d.FloatingIpPool != "" {
addressType = Floating
}
// 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
}
for _, a := range addresses {
if a.AddressType == addressType && a.Version == d.IpVersion {
return a.Address, nil
}
}
time.Sleep(2 * time.Second)
}
return "", fmt.Errorf("No IP found for the machine")
}
func (d *Driver) GetState() (state.State, error) {
log.WithField("MachineId", d.MachineId).Debug("Get status for OpenStack instance...")
if err := d.initCompute(); err != nil {
return state.None, err
}
s, err := d.client.GetInstanceState(d)
if err != nil {
return state.None, err
}
log.WithFields(log.Fields{
"MachineId": d.MachineId,
"State": s,
}).Debug("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) PreCreateCheck() error {
return nil
}
func (d *Driver) Create() error {
Make libmachine usable by outside world - Clear out some cruft tightly coupling libmachine to filestore - Comment out drivers other than virtualbox for now - Change way too many things - Mostly, break out the code to be more modular. - Destroy all traces of "provider" in its current form. It will be brought back as something more sensible, instead of something which overlaps in function with both Host and Store. - Fix mis-managed config passthru - Remove a few instances of state stored in env vars - This should be explicitly communicated in Go-land, not through the shell. - Rename "store" module to "persist" - This is done mostly to avoid confusion about the fact that a concrete instance of a "Store" interface is oftentimes referred to as "store" in the code. - Rip out repetitive antipattern for getting store - This replaces the previous repetive idiom for getting the cert info, and consequently the store, with a much less repetitive idiom. - Also, some redundant methods in commands.go for accessing hosts have either been simplified or removed entirely. - First steps towards fixing up tests - Test progress continues - Replace unit tests with integration tests - MAKE ALL UNIT TESTS PASS YAY - Add helper test files - Don't write to disk in libmachine/host - Heh.. coverage check strikes again - Fix remove code - Move cert code around - Continued progress: simplify Driver - Fixups and make creation work with new model - Move drivers module inside of libmachine - Move ssh module inside of libmachine - Move state module to libmachine - Move utils module to libmachine - Move version module to libmachine - Move log module to libmachine - Modify some constructor methods around - Change Travis build dep structure - Boring gofmt fix - Add version module - Move NewHost to store - Update some boring cert path infos to make API easier to use - Fix up some issues around the new model - Clean up some cert path stuff - Don't use shady functions to get store path :D - Continue artifact work - Fix silly machines dir bug - Continue fixing silly path issues - Change up output of vbm a bit - Continue work to make example go - Change output a little more - Last changes needed to make create finish properly - Fix config.go to use libmachine - Cut down code duplication and make both methods work with libmachine - Add pluggable logging implementation - Return error when machine already in desired state - Update example to show log method - Fix file:// bug - Fix Swarm defaults - Remove unused TLS settings from Engine and Swarm options - Remove spurious error - Correct bug detecting if migration was performed - Fix compilation errors from tests - Fix most of remaining test issues - Fix final silly bug in tests - Remove extraneous debug code - Add -race to test command - Appease the gofmt - Appease the generate coverage - Making executive decision to remove Travis coverage check In the early days I thought this would be a good idea because it would encourage people to write tests in case they added a new module. Well, in fact it has just turned into a giant nuisance and made refactoring work like this even more difficult. - Move Get to Load - Move HostListItem code to CLI Signed-off-by: Nathan LeClaire <nathan.leclaire@gmail.com>
2015-08-18 11:26:42 +09:00
d.KeyPairName = fmt.Sprintf("%s-%s", d.MachineName, mcnutils.GenerateRandomID())
if err := d.resolveIds(); err != nil {
return err
}
if err := d.createSSHKey(); err != nil {
return err
}
if err := d.createMachine(); err != nil {
return err
}
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
}
return nil
}
func (d *Driver) Start() error {
log.WithField("MachineId", d.MachineId).Info("Starting OpenStack instance...")
if err := d.initCompute(); err != nil {
return err
}
if err := d.client.StartInstance(d); err != nil {
return err
}
return nil
}
func (d *Driver) Stop() error {
log.WithField("MachineId", d.MachineId).Info("Stopping OpenStack instance...")
if err := d.initCompute(); err != nil {
return err
}
if err := d.client.StopInstance(d); err != nil {
return err
}
return nil
}
func (d *Driver) Remove() error {
log.WithField("MachineId", d.MachineId).Debug("deleting instance...")
log.Info("Deleting OpenStack instance...")
if err := d.initCompute(); err != nil {
return err
}
if err := d.client.DeleteInstance(d); err != nil {
return err
}
log.WithField("Name", d.KeyPairName).Debug("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.initCompute(); err != nil {
return err
}
if err := d.client.RestartInstance(d); err != nil {
return err
}
return nil
}
func (d *Driver) Kill() error {
return d.Stop()
}
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'"
errorUnknownFlavorName string = "Unable to find flavor named %s"
errorUnknownImageName string = "Unable to find image named %s"
errorUnknownNetworkName string = "Unable to find network named %s"
)
func (d *Driver) checkConfig() error {
if d.AuthUrl == "" {
return fmt.Errorf(errorMandatoryEnvOrOption, "Authentication 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.FlavorName == "" && d.FlavorId == "" {
return fmt.Errorf(errorMandatoryOption, "Flavor name or Flavor id", "--openstack-flavor-name or --openstack-flavor-id")
}
if d.FlavorName != "" && d.FlavorId != "" {
return fmt.Errorf(errorExclusiveOptions, "Flavor name", "Flavor id")
}
if d.ImageName == "" && d.ImageId == "" {
return fmt.Errorf(errorMandatoryOption, "Image name or Image id", "--openstack-image-name or --openstack-image-id")
}
if d.ImageName != "" && d.ImageId != "" {
return fmt.Errorf(errorExclusiveOptions, "Image name", "Image id")
}
if d.NetworkName != "" && d.NetworkId != "" {
return fmt.Errorf(errorExclusiveOptions, "Network name", "Network id")
}
if d.EndpointType != "" && (d.EndpointType != "publicURL" && d.EndpointType != "adminURL" && d.EndpointType != "internalURL") {
return fmt.Errorf(errorWrongEndpointType)
}
return nil
}
func (d *Driver) resolveIds() error {
if d.NetworkName != "" {
if err := d.initNetwork(); err != nil {
return err
}
networkId, err := d.client.GetNetworkId(d)
if err != nil {
return err
}
if networkId == "" {
return fmt.Errorf(errorUnknownNetworkName, d.NetworkName)
}
d.NetworkId = networkId
log.WithFields(log.Fields{
"Name": d.NetworkName,
"ID": d.NetworkId,
}).Debug("Found network id using its name")
}
if d.FlavorName != "" {
if err := d.initCompute(); err != nil {
return err
}
flavorId, err := d.client.GetFlavorId(d)
if err != nil {
return err
}
if flavorId == "" {
return fmt.Errorf(errorUnknownFlavorName, d.FlavorName)
}
d.FlavorId = flavorId
log.WithFields(log.Fields{
"Name": d.FlavorName,
"ID": d.FlavorId,
}).Debug("Found flavor id using its name")
}
if d.ImageName != "" {
if err := d.initCompute(); err != nil {
return err
}
imageId, err := d.client.GetImageId(d)
if err != nil {
return err
}
if imageId == "" {
return fmt.Errorf(errorUnknownImageName, d.ImageName)
}
d.ImageId = imageId
log.WithFields(log.Fields{
"Name": d.ImageName,
"ID": d.ImageId,
}).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
}
func (d *Driver) initCompute() error {
if err := d.client.Authenticate(d); err != nil {
return err
}
if err := d.client.InitComputeClient(d); err != nil {
return err
}
return nil
}
func (d *Driver) initNetwork() error {
if err := d.client.Authenticate(d); err != nil {
return err
}
if err := d.client.InitNetworkClient(d); err != nil {
return err
}
return nil
}
func (d *Driver) createSSHKey() error {
log.WithField("Name", d.KeyPairName).Debug("Creating Key Pair...")
if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil {
return err
}
publicKey, err := ioutil.ReadFile(d.publicSSHKeyPath())
if err != nil {
return err
}
if err := d.initCompute(); 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,
}).Debug("Creating OpenStack instance...")
if err := d.initCompute(); err != nil {
return err
}
instanceId, err := d.client.CreateInstance(d)
if err != nil {
return err
}
d.MachineId = instanceId
return nil
}
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.IPAddress = 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"); err != nil {
return err
}
return nil
}
func (d *Driver) lookForIpAddress() error {
ip, err := d.GetIP()
if err != nil {
return err
}
d.IPAddress = ip
log.WithFields(log.Fields{
"IP": ip,
"MachineId": d.MachineId,
}).Debug("IP address found")
return nil
}
func (d *Driver) publicSSHKeyPath() string {
return d.GetSSHKeyPath() + ".pub"
}