github.com/kimor79/packer@v0.8.7-0.20151221212622-d507b18eb4cf/builder/openstack/step_create_image.go (about) 1 package openstack 2 3 import ( 4 "fmt" 5 "log" 6 "time" 7 8 "github.com/mitchellh/multistep" 9 "github.com/mitchellh/packer/packer" 10 "github.com/rackspace/gophercloud" 11 "github.com/rackspace/gophercloud/openstack/compute/v2/images" 12 "github.com/rackspace/gophercloud/openstack/compute/v2/servers" 13 ) 14 15 type stepCreateImage struct{} 16 17 func (s *stepCreateImage) Run(state multistep.StateBag) multistep.StepAction { 18 config := state.Get("config").(Config) 19 server := state.Get("server").(*servers.Server) 20 ui := state.Get("ui").(packer.Ui) 21 22 // We need the v2 compute client 23 client, err := config.computeV2Client() 24 if err != nil { 25 err = fmt.Errorf("Error initializing compute client: %s", err) 26 state.Put("error", err) 27 return multistep.ActionHalt 28 } 29 30 // Create the image 31 ui.Say(fmt.Sprintf("Creating the image: %s", config.ImageName)) 32 imageId, err := servers.CreateImage(client, server.ID, servers.CreateImageOpts{ 33 Name: config.ImageName, 34 Metadata: config.ImageMetadata, 35 }).ExtractImageID() 36 if err != nil { 37 err := fmt.Errorf("Error creating image: %s", err) 38 state.Put("error", err) 39 ui.Error(err.Error()) 40 return multistep.ActionHalt 41 } 42 43 // Set the Image ID in the state 44 ui.Message(fmt.Sprintf("Image: %s", imageId)) 45 state.Put("image", imageId) 46 47 // Wait for the image to become ready 48 ui.Say(fmt.Sprintf("Waiting for image %s (image id: %s) to become ready...", config.ImageName, imageId)) 49 if err := WaitForImage(client, imageId); err != nil { 50 err := fmt.Errorf("Error waiting for image: %s", err) 51 state.Put("error", err) 52 ui.Error(err.Error()) 53 return multistep.ActionHalt 54 } 55 56 return multistep.ActionContinue 57 } 58 59 func (s *stepCreateImage) Cleanup(multistep.StateBag) { 60 // No cleanup... 61 } 62 63 // WaitForImage waits for the given Image ID to become ready. 64 func WaitForImage(client *gophercloud.ServiceClient, imageId string) error { 65 for { 66 image, err := images.Get(client, imageId).Extract() 67 if err != nil { 68 errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError) 69 if ok && errCode.Actual == 500 { 70 log.Printf("[ERROR] 500 error received, will ignore and retry: %s", err) 71 time.Sleep(2 * time.Second) 72 continue 73 } 74 75 return err 76 } 77 78 if image.Status == "ACTIVE" { 79 return nil 80 } 81 82 log.Printf("Waiting for image creation status: %s (%d%%)", image.Status, image.Progress) 83 time.Sleep(2 * time.Second) 84 } 85 }