github.com/andresvia/terraform@v0.6.15-0.20160412045437-d51c75946785/builtin/providers/cloudstack/resources.go (about) 1 package cloudstack 2 3 import ( 4 "fmt" 5 "log" 6 "regexp" 7 "strings" 8 "time" 9 10 "github.com/hashicorp/terraform/helper/schema" 11 "github.com/xanzy/go-cloudstack/cloudstack" 12 ) 13 14 // UnlimitedResourceID is a "special" ID to define an unlimited resource 15 const UnlimitedResourceID = "-1" 16 17 // Define a regexp for parsing the port 18 var splitPorts = regexp.MustCompile(`^(\d+)(?:-(\d+))?$`) 19 20 type retrieveError struct { 21 name string 22 value string 23 err error 24 } 25 26 func (e *retrieveError) Error() error { 27 return fmt.Errorf("Error retrieving ID of %s %s: %s", e.name, e.value, e.err) 28 } 29 30 func setValueOrID(d *schema.ResourceData, key string, value string, id string) { 31 if isID(d.Get(key).(string)) { 32 // If the given id is an empty string, check if the configured value matches 33 // the UnlimitedResourceID in which case we set id to UnlimitedResourceID 34 if id == "" && d.Get(key).(string) == UnlimitedResourceID { 35 id = UnlimitedResourceID 36 } 37 38 d.Set(key, id) 39 } else { 40 d.Set(key, value) 41 } 42 } 43 44 func retrieveID(cs *cloudstack.CloudStackClient, name, value string) (id string, e *retrieveError) { 45 // If the supplied value isn't a ID, try to retrieve the ID ourselves 46 if isID(value) { 47 return value, nil 48 } 49 50 log.Printf("[DEBUG] Retrieving ID of %s: %s", name, value) 51 52 var err error 53 switch name { 54 case "disk_offering": 55 id, err = cs.DiskOffering.GetDiskOfferingID(value) 56 case "virtual_machine": 57 id, err = cs.VirtualMachine.GetVirtualMachineID(value) 58 case "service_offering": 59 id, err = cs.ServiceOffering.GetServiceOfferingID(value) 60 case "network_offering": 61 id, err = cs.NetworkOffering.GetNetworkOfferingID(value) 62 case "project": 63 id, err = cs.Project.GetProjectID(value) 64 case "vpc_offering": 65 id, err = cs.VPC.GetVPCOfferingID(value) 66 case "vpc": 67 id, err = cs.VPC.GetVPCID(value) 68 case "network": 69 id, err = cs.Network.GetNetworkID(value) 70 case "zone": 71 id, err = cs.Zone.GetZoneID(value) 72 case "ip_address": 73 p := cs.Address.NewListPublicIpAddressesParams() 74 p.SetIpaddress(value) 75 l, e := cs.Address.ListPublicIpAddresses(p) 76 if e != nil { 77 err = e 78 break 79 } 80 if l.Count == 1 { 81 id = l.PublicIpAddresses[0].Id 82 break 83 } 84 err = fmt.Errorf("Could not find ID of IP address: %s", value) 85 case "os_type": 86 p := cs.GuestOS.NewListOsTypesParams() 87 p.SetDescription(value) 88 l, e := cs.GuestOS.ListOsTypes(p) 89 if e != nil { 90 err = e 91 break 92 } 93 if l.Count == 1 { 94 id = l.OsTypes[0].Id 95 break 96 } 97 err = fmt.Errorf("Could not find ID of OS Type: %s", value) 98 default: 99 return id, &retrieveError{name: name, value: value, 100 err: fmt.Errorf("Unknown request: %s", name)} 101 } 102 103 if err != nil { 104 return id, &retrieveError{name: name, value: value, err: err} 105 } 106 107 return id, nil 108 } 109 110 func retrieveTemplateID(cs *cloudstack.CloudStackClient, zoneid, value string) (id string, e *retrieveError) { 111 // If the supplied value isn't a ID, try to retrieve the ID ourselves 112 if isID(value) { 113 return value, nil 114 } 115 116 log.Printf("[DEBUG] Retrieving ID of template: %s", value) 117 118 id, err := cs.Template.GetTemplateID(value, "executable", zoneid) 119 if err != nil { 120 return id, &retrieveError{name: "template", value: value, err: err} 121 } 122 123 return id, nil 124 } 125 126 // ID can be either a UUID or a UnlimitedResourceID 127 func isID(id string) bool { 128 re := regexp.MustCompile(`^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|-1)$`) 129 return re.MatchString(id) 130 } 131 132 // RetryFunc is the function retried n times 133 type RetryFunc func() (interface{}, error) 134 135 // Retry is a wrapper around a RetryFunc that will retry a function 136 // n times or until it succeeds. 137 func Retry(n int, f RetryFunc) (interface{}, error) { 138 var lastErr error 139 140 for i := 0; i < n; i++ { 141 r, err := f() 142 if err == nil || err == cloudstack.AsyncTimeoutErr { 143 return r, err 144 } 145 146 lastErr = err 147 time.Sleep(30 * time.Second) 148 } 149 150 return nil, lastErr 151 } 152 153 // This is a temporary helper function to support both the new 154 // cidr_list and the deprecated source_cidr parameter 155 func retrieveCidrList(rule map[string]interface{}) []string { 156 sourceCidr := rule["source_cidr"].(string) 157 if sourceCidr != "" { 158 return []string{sourceCidr} 159 } 160 161 var cidrList []string 162 for _, cidr := range rule["cidr_list"].(*schema.Set).List() { 163 cidrList = append(cidrList, cidr.(string)) 164 } 165 166 return cidrList 167 } 168 169 // This is a temporary helper function to support both the new 170 // cidr_list and the deprecated source_cidr parameter 171 func setCidrList(rule map[string]interface{}, cidrList string) { 172 sourceCidr := rule["source_cidr"].(string) 173 if sourceCidr != "" { 174 rule["source_cidr"] = cidrList 175 return 176 } 177 178 cidrs := &schema.Set{F: schema.HashString} 179 for _, cidr := range strings.Split(cidrList, ",") { 180 cidrs.Add(cidr) 181 } 182 183 rule["cidr_list"] = cidrs 184 } 185 186 type projectidSetter interface { 187 SetProjectid(string) 188 } 189 190 // If there is a project supplied, we retrieve and set the project id 191 func setProjectid(p projectidSetter, cs *cloudstack.CloudStackClient, d *schema.ResourceData) error { 192 if project, ok := d.GetOk("project"); ok { 193 projectid, e := retrieveID(cs, "project", project.(string)) 194 if e != nil { 195 return e.Error() 196 } 197 p.SetProjectid(projectid) 198 } 199 200 return nil 201 }