2016-04-14 20:29:27 -04:00
|
|
|
package triton
|
|
|
|
|
|
|
|
import (
|
2017-05-05 11:20:21 -04:00
|
|
|
"context"
|
2016-04-14 20:29:27 -04:00
|
|
|
"errors"
|
|
|
|
"time"
|
|
|
|
|
2017-04-04 16:39:01 -04:00
|
|
|
"github.com/hashicorp/packer/packer"
|
2017-04-26 15:07:45 -04:00
|
|
|
"github.com/joyent/triton-go"
|
2016-04-14 20:29:27 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
type driverTriton struct {
|
2017-04-26 15:07:45 -04:00
|
|
|
client *triton.Client
|
2016-04-14 20:29:27 -04:00
|
|
|
ui packer.Ui
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewDriverTriton(ui packer.Ui, config Config) (Driver, error) {
|
|
|
|
client, err := config.AccessConfig.CreateTritonClient()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &driverTriton{
|
|
|
|
client: client,
|
|
|
|
ui: ui,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *driverTriton) CreateImageFromMachine(machineId string, config Config) (string, error) {
|
2017-05-05 11:20:21 -04:00
|
|
|
image, err := d.client.Images().CreateImageFromMachine(context.Background(), &triton.CreateImageFromMachineInput{
|
2017-04-26 15:07:45 -04:00
|
|
|
MachineID: machineId,
|
2016-04-14 20:29:27 -04:00
|
|
|
Name: config.ImageName,
|
|
|
|
Version: config.ImageVersion,
|
|
|
|
Description: config.ImageDescription,
|
2017-04-26 15:07:45 -04:00
|
|
|
HomePage: config.ImageHomepage,
|
2016-04-14 20:29:27 -04:00
|
|
|
EULA: config.ImageEULA,
|
|
|
|
ACL: config.ImageACL,
|
|
|
|
Tags: config.ImageTags,
|
2017-04-26 15:07:45 -04:00
|
|
|
})
|
2016-04-14 20:29:27 -04:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
2017-04-26 15:07:45 -04:00
|
|
|
return image.ID, err
|
2016-04-14 20:29:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (d *driverTriton) CreateMachine(config Config) (string, error) {
|
2017-04-26 15:07:45 -04:00
|
|
|
input := &triton.CreateMachineInput{
|
2016-04-14 20:29:27 -04:00
|
|
|
Package: config.MachinePackage,
|
|
|
|
Image: config.MachineImage,
|
|
|
|
Metadata: config.MachineMetadata,
|
|
|
|
Tags: config.MachineTags,
|
|
|
|
FirewallEnabled: config.MachineFirewallEnabled,
|
|
|
|
}
|
|
|
|
|
2016-12-28 10:01:08 -05:00
|
|
|
if config.MachineName == "" {
|
|
|
|
// If not supplied generate a name for the source VM: "packer-builder-[image_name]".
|
|
|
|
// The version is not used because it can contain characters invalid for a VM name.
|
2017-04-26 15:07:45 -04:00
|
|
|
input.Name = "packer-builder-" + config.ImageName
|
2016-12-28 10:01:08 -05:00
|
|
|
} else {
|
2017-04-26 15:07:45 -04:00
|
|
|
input.Name = config.MachineName
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(config.MachineNetworks) > 0 {
|
|
|
|
input.Networks = config.MachineNetworks
|
2016-04-14 20:29:27 -04:00
|
|
|
}
|
|
|
|
|
2017-05-05 11:20:21 -04:00
|
|
|
machine, err := d.client.Machines().CreateMachine(context.Background(), input)
|
2016-04-14 20:29:27 -04:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
2017-04-26 15:07:45 -04:00
|
|
|
return machine.ID, nil
|
2016-04-14 20:29:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (d *driverTriton) DeleteImage(imageId string) error {
|
2017-05-05 11:20:21 -04:00
|
|
|
return d.client.Images().DeleteImage(context.Background(), &triton.DeleteImageInput{
|
2017-04-26 15:07:45 -04:00
|
|
|
ImageID: imageId,
|
|
|
|
})
|
2016-04-14 20:29:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (d *driverTriton) DeleteMachine(machineId string) error {
|
2017-05-05 11:20:21 -04:00
|
|
|
return d.client.Machines().DeleteMachine(context.Background(), &triton.DeleteMachineInput{
|
2017-04-26 15:07:45 -04:00
|
|
|
ID: machineId,
|
|
|
|
})
|
2016-04-14 20:29:27 -04:00
|
|
|
}
|
|
|
|
|
2017-04-26 15:07:45 -04:00
|
|
|
func (d *driverTriton) GetMachineIP(machineId string) (string, error) {
|
2017-05-05 11:20:21 -04:00
|
|
|
machine, err := d.client.Machines().GetMachine(context.Background(), &triton.GetMachineInput{
|
2017-04-26 15:07:45 -04:00
|
|
|
ID: machineId,
|
|
|
|
})
|
2016-04-14 20:29:27 -04:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return machine.PrimaryIP, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *driverTriton) StopMachine(machineId string) error {
|
2017-05-05 11:20:21 -04:00
|
|
|
return d.client.Machines().StopMachine(context.Background(), &triton.StopMachineInput{
|
2017-04-26 15:07:45 -04:00
|
|
|
MachineID: machineId,
|
|
|
|
})
|
2016-04-14 20:29:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// waitForMachineState uses the supplied client to wait for the state of
|
|
|
|
// the machine with the given ID to reach the state described in state.
|
|
|
|
// If timeout is reached before the machine reaches the required state, an
|
|
|
|
// error is returned. If the machine reaches the target state within the
|
|
|
|
// timeout, nil is returned.
|
|
|
|
func (d *driverTriton) WaitForMachineState(machineId string, state string, timeout time.Duration) error {
|
|
|
|
return waitFor(
|
|
|
|
func() (bool, error) {
|
2017-05-05 11:20:21 -04:00
|
|
|
machine, err := d.client.Machines().GetMachine(context.Background(), &triton.GetMachineInput{
|
2017-04-26 15:07:45 -04:00
|
|
|
ID: machineId,
|
|
|
|
})
|
2016-04-14 20:29:27 -04:00
|
|
|
if machine == nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
return machine.State == state, err
|
|
|
|
},
|
|
|
|
3*time.Second,
|
|
|
|
timeout,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
// waitForMachineDeletion uses the supplied client to wait for the machine
|
|
|
|
// with the given ID to be deleted. It is expected that the API call to delete
|
|
|
|
// the machine has already been issued at this point.
|
|
|
|
func (d *driverTriton) WaitForMachineDeletion(machineId string, timeout time.Duration) error {
|
|
|
|
return waitFor(
|
|
|
|
func() (bool, error) {
|
2017-05-05 11:20:21 -04:00
|
|
|
machine, err := d.client.Machines().GetMachine(context.Background(), &triton.GetMachineInput{
|
2017-04-26 15:07:45 -04:00
|
|
|
ID: machineId,
|
|
|
|
})
|
|
|
|
if err != nil && triton.IsResourceNotFound(err) {
|
|
|
|
return true, nil
|
2016-04-14 20:29:27 -04:00
|
|
|
}
|
|
|
|
|
2016-12-28 10:01:08 -05:00
|
|
|
if machine != nil {
|
2017-04-26 15:07:45 -04:00
|
|
|
return machine.State == "deleted", nil
|
2016-12-28 10:01:08 -05:00
|
|
|
}
|
|
|
|
|
2016-04-14 20:29:27 -04:00
|
|
|
return false, err
|
|
|
|
},
|
|
|
|
3*time.Second,
|
|
|
|
timeout,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *driverTriton) WaitForImageCreation(imageId string, timeout time.Duration) error {
|
|
|
|
return waitFor(
|
|
|
|
func() (bool, error) {
|
2017-05-05 11:20:21 -04:00
|
|
|
image, err := d.client.Images().GetImage(context.Background(), &triton.GetImageInput{
|
2017-04-26 15:07:45 -04:00
|
|
|
ImageID: imageId,
|
|
|
|
})
|
2016-04-14 20:29:27 -04:00
|
|
|
if image == nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
return image.OS != "", err
|
|
|
|
},
|
|
|
|
3*time.Second,
|
|
|
|
timeout,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func waitFor(f func() (bool, error), every, timeout time.Duration) error {
|
|
|
|
start := time.Now()
|
|
|
|
|
|
|
|
for time.Since(start) <= timeout {
|
|
|
|
stop, err := f()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if stop {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
time.Sleep(every)
|
|
|
|
}
|
|
|
|
|
|
|
|
return errors.New("Timed out while waiting for resource change")
|
|
|
|
}
|