github.com/amanya/packer@v0.12.1-0.20161117214323-902ac5ab2eb6/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 maxNumErrors := 10 66 numErrors := 0 67 68 for { 69 image, err := images.Get(client, imageId).Extract() 70 if err != nil { 71 errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError) 72 if ok && (errCode.Actual == 500 || errCode.Actual == 404) { 73 numErrors++ 74 if numErrors >= maxNumErrors { 75 log.Printf("[ERROR] Maximum number of errors (%d) reached; failing with: %s", numErrors, err) 76 return err 77 } 78 log.Printf("[ERROR] %d error received, will ignore and retry: %s", errCode.Actual, err) 79 time.Sleep(2 * time.Second) 80 continue 81 } 82 83 return err 84 } 85 86 if image.Status == "ACTIVE" { 87 return nil 88 } 89 90 log.Printf("Waiting for image creation status: %s (%d%%)", image.Status, image.Progress) 91 time.Sleep(2 * time.Second) 92 } 93 }