github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/ultradns/resource_ultradns_tcpool.go (about) 1 package ultradns 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 8 "github.com/Ensighten/udnssdk" 9 "github.com/hashicorp/terraform/helper/schema" 10 ) 11 12 func resourceUltradnsTcpool() *schema.Resource { 13 return &schema.Resource{ 14 Create: resourceUltradnsTcpoolCreate, 15 Read: resourceUltradnsTcpoolRead, 16 Update: resourceUltradnsTcpoolUpdate, 17 Delete: resourceUltradnsTcpoolDelete, 18 19 Schema: map[string]*schema.Schema{ 20 // Required 21 "zone": &schema.Schema{ 22 Type: schema.TypeString, 23 Required: true, 24 ForceNew: true, 25 }, 26 "name": &schema.Schema{ 27 Type: schema.TypeString, 28 Required: true, 29 ForceNew: true, 30 }, 31 "description": &schema.Schema{ 32 Type: schema.TypeString, 33 Required: true, 34 // 0-255 char 35 }, 36 "rdata": &schema.Schema{ 37 Type: schema.TypeSet, 38 Set: hashRdatas, 39 Required: true, 40 // Valid: len(rdataInfo) == len(rdata) 41 Elem: &schema.Resource{ 42 Schema: map[string]*schema.Schema{ 43 // Required 44 "host": &schema.Schema{ 45 Type: schema.TypeString, 46 Required: true, 47 }, 48 // Optional 49 "failover_delay": &schema.Schema{ 50 Type: schema.TypeInt, 51 Optional: true, 52 Default: 0, 53 // Valid: 0-30 54 // Units: Minutes 55 }, 56 "priority": &schema.Schema{ 57 Type: schema.TypeInt, 58 Optional: true, 59 Default: 1, 60 }, 61 "run_probes": &schema.Schema{ 62 Type: schema.TypeBool, 63 Optional: true, 64 Default: true, 65 }, 66 "state": &schema.Schema{ 67 Type: schema.TypeString, 68 Optional: true, 69 Default: "NORMAL", 70 }, 71 "threshold": &schema.Schema{ 72 Type: schema.TypeInt, 73 Optional: true, 74 Default: 1, 75 }, 76 "weight": &schema.Schema{ 77 Type: schema.TypeInt, 78 Optional: true, 79 Default: 2, 80 // Valid: i%2 == 0 && 2 <= i <= 100 81 }, 82 }, 83 }, 84 }, 85 // Optional 86 "ttl": &schema.Schema{ 87 Type: schema.TypeInt, 88 Optional: true, 89 Default: 3600, 90 }, 91 "run_probes": &schema.Schema{ 92 Type: schema.TypeBool, 93 Optional: true, 94 Default: true, 95 }, 96 "act_on_probes": &schema.Schema{ 97 Type: schema.TypeBool, 98 Optional: true, 99 Default: true, 100 }, 101 "max_to_lb": &schema.Schema{ 102 Type: schema.TypeInt, 103 Optional: true, 104 // Valid: 0 <= i <= len(rdata) 105 }, 106 "backup_record_rdata": &schema.Schema{ 107 Type: schema.TypeString, 108 Optional: true, 109 // Valid: IPv4 address or CNAME 110 }, 111 "backup_record_failover_delay": &schema.Schema{ 112 Type: schema.TypeInt, 113 Optional: true, 114 // Valid: 0-30 115 // Units: Minutes 116 }, 117 // Computed 118 "hostname": &schema.Schema{ 119 Type: schema.TypeString, 120 Computed: true, 121 }, 122 }, 123 } 124 } 125 126 // CRUD Operations 127 128 func resourceUltradnsTcpoolCreate(d *schema.ResourceData, meta interface{}) error { 129 client := meta.(*udnssdk.Client) 130 131 r, err := newRRSetResourceFromTcpool(d) 132 if err != nil { 133 return err 134 } 135 136 log.Printf("[INFO] ultradns_tcpool create: %#v", r) 137 _, err = client.RRSets.Create(r.RRSetKey(), r.RRSet()) 138 if err != nil { 139 return fmt.Errorf("create failed: %#v -> %v", r, err) 140 } 141 142 d.SetId(r.ID()) 143 log.Printf("[INFO] ultradns_tcpool.id: %v", d.Id()) 144 145 return resourceUltradnsTcpoolRead(d, meta) 146 } 147 148 func resourceUltradnsTcpoolRead(d *schema.ResourceData, meta interface{}) error { 149 client := meta.(*udnssdk.Client) 150 151 rr, err := newRRSetResourceFromTcpool(d) 152 if err != nil { 153 return err 154 } 155 156 rrsets, err := client.RRSets.Select(rr.RRSetKey()) 157 if err != nil { 158 uderr, ok := err.(*udnssdk.ErrorResponseList) 159 if ok { 160 for _, resps := range uderr.Responses { 161 // 70002 means Records Not Found 162 if resps.ErrorCode == 70002 { 163 d.SetId("") 164 return nil 165 } 166 return fmt.Errorf("resource not found: %v", err) 167 } 168 } 169 return fmt.Errorf("resource not found: %v", err) 170 } 171 172 r := rrsets[0] 173 174 zone := d.Get("zone") 175 // ttl 176 d.Set("ttl", r.TTL) 177 // hostname 178 if r.OwnerName == "" { 179 d.Set("hostname", zone) 180 } else { 181 if strings.HasSuffix(r.OwnerName, ".") { 182 d.Set("hostname", r.OwnerName) 183 } else { 184 d.Set("hostname", fmt.Sprintf("%s.%s", r.OwnerName, zone)) 185 } 186 } 187 188 // And now... the Profile! 189 if r.Profile == nil { 190 return fmt.Errorf("RRSet.profile missing: invalid TCPool schema in: %#v", r) 191 } 192 p, err := r.Profile.TCPoolProfile() 193 if err != nil { 194 return fmt.Errorf("RRSet.profile could not be unmarshalled: %v\n", err) 195 } 196 197 // Set simple values 198 d.Set("description", p.Description) 199 d.Set("run_probes", p.RunProbes) 200 d.Set("act_on_probes", p.ActOnProbes) 201 d.Set("max_to_lb", p.MaxToLB) 202 if p.BackupRecord != nil { 203 d.Set("backup_record_rdata", p.BackupRecord.RData) 204 d.Set("backup_record_failover_delay", p.BackupRecord.FailoverDelay) 205 } 206 207 // TODO: rigorously test this to see if we can remove the error handling 208 err = d.Set("rdata", makeSetFromRdata(r.RData, p.RDataInfo)) 209 if err != nil { 210 return fmt.Errorf("rdata set failed: %#v", err) 211 } 212 return nil 213 } 214 215 func resourceUltradnsTcpoolUpdate(d *schema.ResourceData, meta interface{}) error { 216 client := meta.(*udnssdk.Client) 217 218 r, err := newRRSetResourceFromTcpool(d) 219 if err != nil { 220 return err 221 } 222 223 log.Printf("[INFO] ultradns_tcpool update: %+v", r) 224 _, err = client.RRSets.Update(r.RRSetKey(), r.RRSet()) 225 if err != nil { 226 return fmt.Errorf("resource update failed: %v", err) 227 } 228 229 return resourceUltradnsTcpoolRead(d, meta) 230 } 231 232 func resourceUltradnsTcpoolDelete(d *schema.ResourceData, meta interface{}) error { 233 client := meta.(*udnssdk.Client) 234 235 r, err := newRRSetResourceFromTcpool(d) 236 if err != nil { 237 return err 238 } 239 240 log.Printf("[INFO] ultradns_tcpool delete: %+v", r) 241 _, err = client.RRSets.Delete(r.RRSetKey()) 242 if err != nil { 243 return fmt.Errorf("resource delete failed: %v", err) 244 } 245 246 return nil 247 } 248 249 // Resource Helpers 250 251 func newRRSetResourceFromTcpool(d *schema.ResourceData) (rRSetResource, error) { 252 rDataRaw := d.Get("rdata").(*schema.Set).List() 253 r := rRSetResource{ 254 // "The only valid rrtype value for SiteBacker or Traffic Controller pools is A" 255 // per https://portal.ultradns.com/static/docs/REST-API_User_Guide.pdf 256 RRType: "A", 257 Zone: d.Get("zone").(string), 258 OwnerName: d.Get("name").(string), 259 TTL: d.Get("ttl").(int), 260 RData: unzipRdataHosts(rDataRaw), 261 } 262 263 profile := udnssdk.TCPoolProfile{ 264 Context: udnssdk.TCPoolSchema, 265 ActOnProbes: d.Get("act_on_probes").(bool), 266 Description: d.Get("description").(string), 267 MaxToLB: d.Get("max_to_lb").(int), 268 RunProbes: d.Get("run_probes").(bool), 269 RDataInfo: unzipRdataInfos(rDataRaw), 270 } 271 272 // Only send BackupRecord if present 273 br := d.Get("backup_record_rdata").(string) 274 if br != "" { 275 profile.BackupRecord = &udnssdk.BackupRecord{ 276 RData: d.Get("backup_record_rdata").(string), 277 FailoverDelay: d.Get("backup_record_failover_delay").(int), 278 } 279 } 280 281 rp := profile.RawProfile() 282 r.Profile = rp 283 284 return r, nil 285 } 286 287 func unzipRdataInfos(configured []interface{}) []udnssdk.SBRDataInfo { 288 rdataInfos := make([]udnssdk.SBRDataInfo, 0, len(configured)) 289 for _, rRaw := range configured { 290 data := rRaw.(map[string]interface{}) 291 r := udnssdk.SBRDataInfo{ 292 FailoverDelay: data["failover_delay"].(int), 293 Priority: data["priority"].(int), 294 RunProbes: data["run_probes"].(bool), 295 State: data["state"].(string), 296 Threshold: data["threshold"].(int), 297 Weight: data["weight"].(int), 298 } 299 rdataInfos = append(rdataInfos, r) 300 } 301 return rdataInfos 302 } 303 304 // collate and zip RData and RDataInfo into []map[string]interface{} 305 func zipRData(rds []string, rdis []udnssdk.SBRDataInfo) []map[string]interface{} { 306 result := make([]map[string]interface{}, 0, len(rds)) 307 for i, rdi := range rdis { 308 r := map[string]interface{}{ 309 "host": rds[i], 310 "failover_delay": rdi.FailoverDelay, 311 "priority": rdi.Priority, 312 "run_probes": rdi.RunProbes, 313 "state": rdi.State, 314 "threshold": rdi.Threshold, 315 "weight": rdi.Weight, 316 } 317 result = append(result, r) 318 } 319 return result 320 } 321 322 // makeSetFromRdatas encodes an array of Rdata into a 323 // *schema.Set in the appropriate structure for the schema 324 func makeSetFromRdata(rds []string, rdis []udnssdk.SBRDataInfo) *schema.Set { 325 s := &schema.Set{F: hashRdatas} 326 rs := zipRData(rds, rdis) 327 for _, r := range rs { 328 s.Add(r) 329 } 330 return s 331 }