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