github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/builder/cloudstack/step_prepare_config.go (about) 1 package cloudstack 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "regexp" 7 8 "github.com/hashicorp/packer/packer" 9 "github.com/mitchellh/multistep" 10 "github.com/xanzy/go-cloudstack/cloudstack" 11 ) 12 13 type stepPrepareConfig struct{} 14 15 func (s *stepPrepareConfig) Run(state multistep.StateBag) multistep.StepAction { 16 client := state.Get("client").(*cloudstack.CloudStackClient) 17 config := state.Get("config").(*Config) 18 ui := state.Get("ui").(packer.Ui) 19 20 ui.Say("Preparing config...") 21 22 var err error 23 var errs *packer.MultiError 24 25 // First get the project and zone UUID's so we can use them in other calls when needed. 26 if config.Project != "" && !isUUID(config.Project) { 27 config.Project, _, err = client.Project.GetProjectID(config.Project) 28 if err != nil { 29 errs = packer.MultiErrorAppend(errs, &retrieveErr{"project", config.Project, err}) 30 } 31 } 32 33 if config.UserDataFile != "" { 34 userdata, err := ioutil.ReadFile(config.UserDataFile) 35 if err != nil { 36 errs = packer.MultiErrorAppend(errs, fmt.Errorf("problem reading user data file: %s", err)) 37 } 38 config.UserData = string(userdata) 39 } 40 41 if !isUUID(config.Zone) { 42 config.Zone, _, err = client.Zone.GetZoneID(config.Zone) 43 if err != nil { 44 errs = packer.MultiErrorAppend(errs, &retrieveErr{"zone", config.Zone, err}) 45 } 46 } 47 48 // Then try to get the remaining UUID's. 49 if config.DiskOffering != "" && !isUUID(config.DiskOffering) { 50 config.DiskOffering, _, err = client.DiskOffering.GetDiskOfferingID(config.DiskOffering) 51 if err != nil { 52 errs = packer.MultiErrorAppend(errs, &retrieveErr{"disk offering", config.DiskOffering, err}) 53 } 54 } 55 56 if config.PublicIPAddress != "" { 57 if isUUID(config.PublicIPAddress) { 58 ip, _, err := client.Address.GetPublicIpAddressByID(config.PublicIPAddress) 59 if err != nil { 60 errs = packer.MultiErrorAppend(errs, fmt.Errorf("Failed to retrieve IP address: %s", err)) 61 } 62 state.Put("ipaddress", ip.Ipaddress) 63 } else { 64 // Save the public IP address before replacing it with it's UUID. 65 state.Put("ipaddress", config.PublicIPAddress) 66 67 p := client.Address.NewListPublicIpAddressesParams() 68 p.SetIpaddress(config.PublicIPAddress) 69 70 if config.Project != "" { 71 p.SetProjectid(config.Project) 72 } 73 74 ipAddrs, err := client.Address.ListPublicIpAddresses(p) 75 if err != nil { 76 errs = packer.MultiErrorAppend(errs, &retrieveErr{"IP address", config.PublicIPAddress, err}) 77 } 78 if err == nil && ipAddrs.Count != 1 { 79 errs = packer.MultiErrorAppend(errs, &retrieveErr{"IP address", config.PublicIPAddress, ipAddrs}) 80 } 81 if err == nil && ipAddrs.Count == 1 { 82 config.PublicIPAddress = ipAddrs.PublicIpAddresses[0].Id 83 } 84 } 85 } 86 87 if !isUUID(config.Network) { 88 config.Network, _, err = client.Network.GetNetworkID(config.Network, cloudstack.WithProject(config.Project)) 89 if err != nil { 90 errs = packer.MultiErrorAppend(errs, &retrieveErr{"network", config.Network, err}) 91 } 92 } 93 94 // Then try to get the SG's UUID's. 95 if len(config.SecurityGroups) > 0 { 96 for i := range config.SecurityGroups { 97 if !isUUID(config.SecurityGroups[i]) { 98 config.SecurityGroups[i], _, err = client.SecurityGroup.GetSecurityGroupID(config.SecurityGroups[i], cloudstack.WithProject(config.Project)) 99 if err != nil { 100 errs = packer.MultiErrorAppend(errs, &retrieveErr{"network", config.SecurityGroups[i], err}) 101 } 102 } 103 } 104 } 105 106 if !isUUID(config.ServiceOffering) { 107 config.ServiceOffering, _, err = client.ServiceOffering.GetServiceOfferingID(config.ServiceOffering) 108 if err != nil { 109 errs = packer.MultiErrorAppend(errs, &retrieveErr{"service offering", config.ServiceOffering, err}) 110 } 111 } 112 113 if config.SourceISO != "" { 114 if isUUID(config.SourceISO) { 115 state.Put("source", config.SourceISO) 116 } else { 117 isoID, _, err := client.ISO.GetIsoID(config.SourceISO, "executable", config.Zone) 118 if err != nil { 119 errs = packer.MultiErrorAppend(errs, &retrieveErr{"ISO", config.SourceISO, err}) 120 } 121 state.Put("source", isoID) 122 } 123 } 124 125 if config.SourceTemplate != "" { 126 if isUUID(config.SourceTemplate) { 127 state.Put("source", config.SourceTemplate) 128 } else { 129 templateID, _, err := client.Template.GetTemplateID(config.SourceTemplate, "executable", config.Zone) 130 if err != nil { 131 errs = packer.MultiErrorAppend(errs, &retrieveErr{"template", config.SourceTemplate, err}) 132 } 133 state.Put("source", templateID) 134 } 135 } 136 137 if !isUUID(config.TemplateOS) { 138 p := client.GuestOS.NewListOsTypesParams() 139 p.SetDescription(config.TemplateOS) 140 141 types, err := client.GuestOS.ListOsTypes(p) 142 if err != nil { 143 errs = packer.MultiErrorAppend(errs, &retrieveErr{"OS type", config.TemplateOS, err}) 144 } 145 if err == nil && types.Count != 1 { 146 errs = packer.MultiErrorAppend(errs, &retrieveErr{"OS type", config.TemplateOS, types}) 147 } 148 if err == nil && types.Count == 1 { 149 config.TemplateOS = types.OsTypes[0].Id 150 } 151 } 152 153 // This is needed because nil is not always nil. When returning *packer.MultiError(nil) 154 // as an error interface, that interface will no longer be equal to nil but it will be 155 // an interface with type *packer.MultiError and value nil which is different then a 156 // nil interface. 157 if errs != nil && len(errs.Errors) > 0 { 158 state.Put("error", errs) 159 ui.Error(errs.Error()) 160 return multistep.ActionHalt 161 } 162 163 ui.Message("Config has been prepared!") 164 return multistep.ActionContinue 165 } 166 167 func (s *stepPrepareConfig) Cleanup(state multistep.StateBag) { 168 // Nothing to cleanup for this step. 169 } 170 171 type retrieveErr struct { 172 name string 173 value string 174 result interface{} 175 } 176 177 func (e *retrieveErr) Error() string { 178 if err, ok := e.result.(error); ok { 179 e.result = err.Error() 180 } 181 return fmt.Sprintf("Error retrieving UUID of %s %s: %v", e.name, e.value, e.result) 182 } 183 184 var uuidRegex = regexp.MustCompile(`^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`) 185 186 func isUUID(uuid string) bool { 187 return uuidRegex.MatchString(uuid) 188 }