2013-08-27 00:57:23 -04:00
|
|
|
package openstack
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"time"
|
2014-10-27 19:40:49 -04:00
|
|
|
|
2015-06-12 00:16:43 -04:00
|
|
|
"github.com/mitchellh/multistep"
|
|
|
|
"github.com/mitchellh/packer/packer"
|
|
|
|
"github.com/rackspace/gophercloud"
|
|
|
|
"github.com/rackspace/gophercloud/openstack/compute/v2/images"
|
|
|
|
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
|
2013-08-27 00:57:23 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
type stepCreateImage struct{}
|
|
|
|
|
2013-08-31 15:37:07 -04:00
|
|
|
func (s *stepCreateImage) Run(state multistep.StateBag) multistep.StepAction {
|
2015-05-27 16:02:57 -04:00
|
|
|
config := state.Get("config").(Config)
|
2015-06-12 00:16:43 -04:00
|
|
|
server := state.Get("server").(*servers.Server)
|
2013-08-31 15:37:07 -04:00
|
|
|
ui := state.Get("ui").(packer.Ui)
|
2013-08-27 00:57:23 -04:00
|
|
|
|
2015-06-12 00:16:43 -04:00
|
|
|
// We need the v2 compute client
|
|
|
|
client, err := config.computeV2Client()
|
|
|
|
if err != nil {
|
|
|
|
err = fmt.Errorf("Error initializing compute client: %s", err)
|
|
|
|
state.Put("error", err)
|
|
|
|
return multistep.ActionHalt
|
|
|
|
}
|
|
|
|
|
2013-08-27 00:57:23 -04:00
|
|
|
// Create the image
|
|
|
|
ui.Say(fmt.Sprintf("Creating the image: %s", config.ImageName))
|
2015-06-12 00:16:43 -04:00
|
|
|
imageId, err := servers.CreateImage(client, server.ID, servers.CreateImageOpts{
|
2013-08-27 00:57:23 -04:00
|
|
|
Name: config.ImageName,
|
2015-06-12 00:16:43 -04:00
|
|
|
}).ExtractImageID()
|
2013-08-27 00:57:23 -04:00
|
|
|
if err != nil {
|
|
|
|
err := fmt.Errorf("Error creating image: %s", err)
|
2013-08-31 15:37:07 -04:00
|
|
|
state.Put("error", err)
|
2013-08-27 00:57:23 -04:00
|
|
|
ui.Error(err.Error())
|
|
|
|
return multistep.ActionHalt
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the Image ID in the state
|
2015-06-12 00:16:43 -04:00
|
|
|
ui.Message(fmt.Sprintf("Image: %s", imageId))
|
2013-08-31 15:37:07 -04:00
|
|
|
state.Put("image", imageId)
|
2013-08-27 00:57:23 -04:00
|
|
|
|
|
|
|
// Wait for the image to become ready
|
|
|
|
ui.Say("Waiting for image to become ready...")
|
2015-06-12 00:16:43 -04:00
|
|
|
if err := WaitForImage(client, imageId); err != nil {
|
2013-08-27 00:57:23 -04:00
|
|
|
err := fmt.Errorf("Error waiting for image: %s", err)
|
2013-08-31 15:37:07 -04:00
|
|
|
state.Put("error", err)
|
2013-08-27 00:57:23 -04:00
|
|
|
ui.Error(err.Error())
|
|
|
|
return multistep.ActionHalt
|
|
|
|
}
|
|
|
|
|
|
|
|
return multistep.ActionContinue
|
|
|
|
}
|
|
|
|
|
2013-08-31 15:37:07 -04:00
|
|
|
func (s *stepCreateImage) Cleanup(multistep.StateBag) {
|
2013-08-27 00:57:23 -04:00
|
|
|
// No cleanup...
|
|
|
|
}
|
|
|
|
|
|
|
|
// WaitForImage waits for the given Image ID to become ready.
|
2015-06-12 00:16:43 -04:00
|
|
|
func WaitForImage(client *gophercloud.ServiceClient, imageId string) error {
|
2013-08-27 00:57:23 -04:00
|
|
|
for {
|
2015-06-12 00:16:43 -04:00
|
|
|
image, err := images.Get(client, imageId).Extract()
|
2013-08-27 00:57:23 -04:00
|
|
|
if err != nil {
|
2015-06-12 00:16:43 -04:00
|
|
|
errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError)
|
|
|
|
if ok && errCode.Actual == 500 {
|
|
|
|
log.Printf("[ERROR] 500 error received, will ignore and retry: %s", err)
|
|
|
|
time.Sleep(2 * time.Second)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2013-08-27 00:57:23 -04:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if image.Status == "ACTIVE" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Printf("Waiting for image creation status: %s (%d%%)", image.Status, image.Progress)
|
|
|
|
time.Sleep(2 * time.Second)
|
|
|
|
}
|
|
|
|
}
|