github.com/amanya/packer@v0.12.1-0.20161117214323-902ac5ab2eb6/builder/cloudstack/step_create_template.go (about) 1 package cloudstack 2 3 import ( 4 "fmt" 5 "time" 6 7 "github.com/mitchellh/multistep" 8 "github.com/mitchellh/packer/packer" 9 "github.com/xanzy/go-cloudstack/cloudstack" 10 ) 11 12 type stepCreateTemplate struct{} 13 14 func (s *stepCreateTemplate) Run(state multistep.StateBag) multistep.StepAction { 15 client := state.Get("client").(*cloudstack.CloudStackClient) 16 config := state.Get("config").(*Config) 17 ui := state.Get("ui").(packer.Ui) 18 19 ui.Say(fmt.Sprintf("Creating template: %s", config.TemplateName)) 20 21 // Retrieve the instance ID from the previously saved state. 22 instanceID, ok := state.Get("instance_id").(string) 23 if !ok || instanceID == "" { 24 ui.Error("Could not retrieve instance_id from state!") 25 return multistep.ActionHalt 26 } 27 28 // Create a new parameter struct. 29 p := client.Template.NewCreateTemplateParams( 30 config.TemplateDisplayText, 31 config.TemplateName, 32 config.TemplateOS, 33 ) 34 35 // Configure the template according to the supplied config. 36 p.SetIsfeatured(config.TemplateFeatured) 37 p.SetIspublic(config.TemplatePublic) 38 p.SetIsdynamicallyscalable(config.TemplateScalable) 39 p.SetPasswordenabled(config.TemplatePasswordEnabled) 40 p.SetRequireshvm(config.TemplateRequiresHVM) 41 42 if config.Project != "" { 43 p.SetProjectid(config.Project) 44 } 45 46 if config.TemplateTag != "" { 47 p.SetTemplatetag(config.TemplateTag) 48 } 49 50 ui.Message("Retrieving the ROOT volume ID...") 51 volumeID, err := getRootVolumeID(client, instanceID) 52 if err != nil { 53 ui.Error(err.Error()) 54 return multistep.ActionHalt 55 } 56 57 // Set the volume ID from which to create the template. 58 p.SetVolumeid(volumeID) 59 60 ui.Message("Creating the new template...") 61 template, err := client.Template.CreateTemplate(p) 62 if err != nil { 63 ui.Error(fmt.Sprintf("Error creating the new template %s: %s", config.TemplateName, err)) 64 return multistep.ActionHalt 65 } 66 67 // This is kind of nasty, but it appears to be needed to prevent corrupt templates. 68 // When CloudStack says the template creation is done and you then delete the source 69 // volume shortly after, it seems to corrupt the newly created template. Giving it an 70 // additional 30 seconds to really finish up, seem to prevent that from happening. 71 time.Sleep(30 * time.Second) 72 73 ui.Message("Template has been created!") 74 75 // Store the template ID. 76 state.Put("template", template) 77 78 return multistep.ActionContinue 79 } 80 81 // Cleanup any resources that may have been created during the Run phase. 82 func (s *stepCreateTemplate) Cleanup(state multistep.StateBag) { 83 // Nothing to cleanup for this step. 84 } 85 86 func getRootVolumeID(client *cloudstack.CloudStackClient, instanceID string) (string, error) { 87 // Retrieve the virtual machine object. 88 p := client.Volume.NewListVolumesParams() 89 90 // Set the type and virtual machine ID 91 p.SetType("ROOT") 92 p.SetVirtualmachineid(instanceID) 93 94 volumes, err := client.Volume.ListVolumes(p) 95 if err != nil { 96 return "", fmt.Errorf("Failed to retrieve ROOT volume: %s", err) 97 } 98 if volumes.Count != 1 { 99 return "", fmt.Errorf("Could not find ROOT disk of instance %s", instanceID) 100 } 101 102 return volumes.Volumes[0].Id, nil 103 }