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