Skip to content

Commit d783e83

Browse files
josephholstenstack72
authored andcommitted
ultradns providers and improvements (hashicorp#9788)
* vendor: update github.com/Ensighten/udnssdk to v1.2.1 * ultradns_tcpool: add * ultradns.baseurl: set default * ultradns.record: cleanup test * ultradns_record: extract common, cleanup * ultradns: extract common * ultradns_dirpool: add * ultradns_dirpool: fix rdata.ip_info.ips to be idempotent * ultradns_tcpool: add doc * ultradns_dirpool: fix rdata.geo_codes.codes to be idempotent * ultradns_dirpool: add doc * ultradns: cleanup testing * ultradns_record: rename resource * ultradns: log username from config, not client udnssdk.Client is being refactored to use x/oauth2, so don't assume we can access Username from it * ultradns_probe_ping: add * ultradns_probe_http: add * doc: add ultradns_probe_ping * doc: add ultradns_probe_http * ultradns_record: remove duplication from error messages * doc: cleanup typos in ultradns * ultradns_probe_ping: add test for pool-level probe * Clean documentation * ultradns: pull makeSetFromStrings() up to common.go * ultradns_dirpool: log hashIPInfoIPs Log the key and generated hashcode used to index ip_info.ips into a set. * ultradns: simplify hashLimits() Limits blocks only have the "name" attribute as their primary key, so hashLimits() needn't use a buffer to concatenate. Also changes log level to a more approriate DEBUG. * ultradns_tcpool: convert rdata to schema.Set RData blocks have the "host" attribute as their primary key, so it is used by hashRdatas() to create the hashcode. Tests are updated to use the new hashcode indexes instead of natural numbers. * ultradns_probe_http: convert agents to schema.Set Also pull the makeSetFromStrings() helper up to common.go * ultradns: pull hashRdatas() up to common * ultradns_dirpool: convert rdata to schema.Set Fixes TF-66 * ultradns_dirpool.conflict_resolve: fix default from response UltraDNS REST API User Guide claims that "Directional Pool Profile Fields" have a "conflictResolve" field which "If not specified, defaults to GEO." https://portal.ultradns.com/static/docs/REST-API_User_Guide.pdf But UltraDNS does not actually return a conflictResolve attribute when it has been updated to "GEO". We could fix it in udnssdk, but that would require either: * hide the response by coercing "" to "GEO" for everyone * use a pointer to allow checking for nil (requires all users to change if they fix this) An ideal solution would be to have the UltraDNS API respond with this attribute for every dirpool's rdata. So at the risk of foolish consistency in the sdk, we're going to solve it where it's visible to the user: by checking and overriding the parsing. I'm sorry. * ultradns_record: convert rdata to set UltraDNS does not store the ordering of rdata elements, so we need a way to identify if changes have been made even it the order changes. A perfect job for schema.Set. * ultradns_record: parse double-encoded answers for TXT records * ultradns: simplify hashLimits() Limits blocks only have the "name" attribute as their primary key, so hashLimits() needn't use a buffer to concatenate. * ultradns_dirpool.description: validate * ultradns_dirpool.rdata: doc need for set * ultradns_dirpool.conflict_resolve: validate
1 parent b215e7e commit d783e83

37 files changed

Lines changed: 3733 additions & 629 deletions
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
package ultradns
2+
3+
import (
4+
"fmt"
5+
"log"
6+
7+
"github.com/Ensighten/udnssdk"
8+
"github.com/hashicorp/terraform/helper/hashcode"
9+
"github.com/hashicorp/terraform/helper/schema"
10+
)
11+
12+
// Conversion helper functions
13+
type rRSetResource struct {
14+
OwnerName string
15+
RRType string
16+
RData []string
17+
TTL int
18+
Profile udnssdk.RawProfile
19+
Zone string
20+
}
21+
22+
// profileAttrSchemaMap is a map from each ultradns_tcpool attribute name onto its respective ProfileSchema URI
23+
var profileAttrSchemaMap = map[string]udnssdk.ProfileSchema{
24+
"dirpool_profile": udnssdk.DirPoolSchema,
25+
"rdpool_profile": udnssdk.RDPoolSchema,
26+
"sbpool_profile": udnssdk.SBPoolSchema,
27+
"tcpool_profile": udnssdk.TCPoolSchema,
28+
}
29+
30+
func (r rRSetResource) RRSetKey() udnssdk.RRSetKey {
31+
return udnssdk.RRSetKey{
32+
Zone: r.Zone,
33+
Type: r.RRType,
34+
Name: r.OwnerName,
35+
}
36+
}
37+
38+
func (r rRSetResource) RRSet() udnssdk.RRSet {
39+
return udnssdk.RRSet{
40+
OwnerName: r.OwnerName,
41+
RRType: r.RRType,
42+
RData: r.RData,
43+
TTL: r.TTL,
44+
Profile: r.Profile,
45+
}
46+
}
47+
48+
func (r rRSetResource) ID() string {
49+
return fmt.Sprintf("%s.%s", r.OwnerName, r.Zone)
50+
}
51+
52+
func unzipRdataHosts(configured []interface{}) []string {
53+
hs := make([]string, 0, len(configured))
54+
for _, rRaw := range configured {
55+
data := rRaw.(map[string]interface{})
56+
h := data["host"].(string)
57+
hs = append(hs, h)
58+
}
59+
return hs
60+
}
61+
62+
func schemaPingProbe() *schema.Resource {
63+
return &schema.Resource{
64+
Schema: map[string]*schema.Schema{
65+
"packets": &schema.Schema{
66+
Type: schema.TypeInt,
67+
Optional: true,
68+
Default: 3,
69+
},
70+
"packet_size": &schema.Schema{
71+
Type: schema.TypeInt,
72+
Optional: true,
73+
Default: 56,
74+
},
75+
"limit": &schema.Schema{
76+
Type: schema.TypeSet,
77+
Optional: true,
78+
Set: hashLimits,
79+
Elem: resourceProbeLimits(),
80+
},
81+
},
82+
}
83+
}
84+
85+
func resourceProbeLimits() *schema.Resource {
86+
return &schema.Resource{
87+
Schema: map[string]*schema.Schema{
88+
"name": &schema.Schema{
89+
Type: schema.TypeString,
90+
Required: true,
91+
},
92+
"warning": &schema.Schema{
93+
Type: schema.TypeInt,
94+
Required: true,
95+
},
96+
"critical": &schema.Schema{
97+
Type: schema.TypeInt,
98+
Required: true,
99+
},
100+
"fail": &schema.Schema{
101+
Type: schema.TypeInt,
102+
Required: true,
103+
},
104+
},
105+
}
106+
}
107+
108+
type probeResource struct {
109+
Name string
110+
Zone string
111+
ID string
112+
113+
Agents []string
114+
Interval string
115+
PoolRecord string
116+
Threshold int
117+
Type udnssdk.ProbeType
118+
119+
Details *udnssdk.ProbeDetailsDTO
120+
}
121+
122+
func (p probeResource) RRSetKey() udnssdk.RRSetKey {
123+
return p.Key().RRSetKey()
124+
}
125+
126+
func (p probeResource) ProbeInfoDTO() udnssdk.ProbeInfoDTO {
127+
return udnssdk.ProbeInfoDTO{
128+
ID: p.ID,
129+
PoolRecord: p.PoolRecord,
130+
ProbeType: p.Type,
131+
Interval: p.Interval,
132+
Agents: p.Agents,
133+
Threshold: p.Threshold,
134+
Details: p.Details,
135+
}
136+
}
137+
138+
func (p probeResource) Key() udnssdk.ProbeKey {
139+
return udnssdk.ProbeKey{
140+
Zone: p.Zone,
141+
Name: p.Name,
142+
ID: p.ID,
143+
}
144+
}
145+
146+
func mapFromLimit(name string, l udnssdk.ProbeDetailsLimitDTO) map[string]interface{} {
147+
return map[string]interface{}{
148+
"name": name,
149+
"warning": l.Warning,
150+
"critical": l.Critical,
151+
"fail": l.Fail,
152+
}
153+
}
154+
155+
// hashLimits generates a hashcode for a limits block
156+
func hashLimits(v interface{}) int {
157+
m := v.(map[string]interface{})
158+
h := hashcode.String(m["name"].(string))
159+
log.Printf("[INFO] hashLimits(): %v -> %v", m["name"].(string), h)
160+
return h
161+
}
162+
163+
// makeSetFromLimits encodes an array of Limits into a
164+
// *schema.Set in the appropriate structure for the schema
165+
func makeSetFromLimits(ls map[string]udnssdk.ProbeDetailsLimitDTO) *schema.Set {
166+
s := &schema.Set{F: hashLimits}
167+
for name, l := range ls {
168+
s.Add(mapFromLimit(name, l))
169+
}
170+
return s
171+
}
172+
173+
func makeProbeDetailsLimit(configured interface{}) *udnssdk.ProbeDetailsLimitDTO {
174+
l := configured.(map[string]interface{})
175+
return &udnssdk.ProbeDetailsLimitDTO{
176+
Warning: l["warning"].(int),
177+
Critical: l["critical"].(int),
178+
Fail: l["fail"].(int),
179+
}
180+
}
181+
182+
// makeSetFromStrings encodes an []string into a
183+
// *schema.Set in the appropriate structure for the schema
184+
func makeSetFromStrings(ss []string) *schema.Set {
185+
st := &schema.Set{F: schema.HashString}
186+
for _, s := range ss {
187+
st.Add(s)
188+
}
189+
return st
190+
}
191+
192+
// hashRdata generates a hashcode for an Rdata block
193+
func hashRdatas(v interface{}) int {
194+
m := v.(map[string]interface{})
195+
h := hashcode.String(m["host"].(string))
196+
log.Printf("[DEBUG] hashRdatas(): %v -> %v", m["host"].(string), h)
197+
return h
198+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package ultradns
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/Ensighten/udnssdk"
7+
"github.com/hashicorp/terraform/helper/resource"
8+
"github.com/hashicorp/terraform/terraform"
9+
)
10+
11+
func testAccTcpoolCheckDestroy(s *terraform.State) error {
12+
client := testAccProvider.Meta().(*udnssdk.Client)
13+
14+
for _, rs := range s.RootModule().Resources {
15+
if rs.Type != "ultradns_tcpool" {
16+
continue
17+
}
18+
19+
k := udnssdk.RRSetKey{
20+
Zone: rs.Primary.Attributes["zone"],
21+
Name: rs.Primary.Attributes["name"],
22+
Type: rs.Primary.Attributes["type"],
23+
}
24+
25+
_, err := client.RRSets.Select(k)
26+
if err == nil {
27+
return fmt.Errorf("Record still exists")
28+
}
29+
}
30+
31+
return nil
32+
}
33+
34+
func testAccCheckUltradnsRecordExists(n string, record *udnssdk.RRSet) resource.TestCheckFunc {
35+
return func(s *terraform.State) error {
36+
rs, ok := s.RootModule().Resources[n]
37+
38+
if !ok {
39+
return fmt.Errorf("Not found: %s", n)
40+
}
41+
42+
if rs.Primary.ID == "" {
43+
return fmt.Errorf("No Record ID is set")
44+
}
45+
46+
client := testAccProvider.Meta().(*udnssdk.Client)
47+
k := udnssdk.RRSetKey{
48+
Zone: rs.Primary.Attributes["zone"],
49+
Name: rs.Primary.Attributes["name"],
50+
Type: rs.Primary.Attributes["type"],
51+
}
52+
53+
foundRecord, err := client.RRSets.Select(k)
54+
55+
if err != nil {
56+
return err
57+
}
58+
59+
if foundRecord[0].OwnerName != rs.Primary.Attributes["hostname"] {
60+
return fmt.Errorf("Record not found: %+v,\n %+v\n", foundRecord, rs.Primary.Attributes)
61+
}
62+
63+
*record = foundRecord[0]
64+
65+
return nil
66+
}
67+
}

builtin/providers/ultradns/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func (c *Config) Client() (*udnssdk.Client, error) {
2222
return nil, fmt.Errorf("Error setting up client: %s", err)
2323
}
2424

25-
log.Printf("[INFO] UltraDNS Client configured for user: %s", client.Username)
25+
log.Printf("[INFO] UltraDNS Client configured for user: %s", c.Username)
2626

2727
return client, nil
2828
}

builtin/providers/ultradns/provider.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package ultradns
22

33
import (
4+
"github.com/Ensighten/udnssdk"
45
"github.com/hashicorp/terraform/helper/schema"
56
"github.com/hashicorp/terraform/terraform"
67
)
@@ -24,14 +25,19 @@ func Provider() terraform.ResourceProvider {
2425
},
2526
"baseurl": &schema.Schema{
2627
Type: schema.TypeString,
27-
Required: true,
28+
Optional: true,
2829
DefaultFunc: schema.EnvDefaultFunc("ULTRADNS_BASEURL", nil),
29-
Description: "UltraDNS Base url(defaults to testing)",
30+
Default: udnssdk.DefaultLiveBaseURL,
31+
Description: "UltraDNS Base URL",
3032
},
3133
},
3234

3335
ResourcesMap: map[string]*schema.Resource{
34-
"ultradns_record": resourceUltraDNSRecord(),
36+
"ultradns_dirpool": resourceUltradnsDirpool(),
37+
"ultradns_probe_http": resourceUltradnsProbeHTTP(),
38+
"ultradns_probe_ping": resourceUltradnsProbePing(),
39+
"ultradns_record": resourceUltradnsRecord(),
40+
"ultradns_tcpool": resourceUltradnsTcpool(),
3541
},
3642

3743
ConfigureFunc: providerConfigure,

0 commit comments

Comments
 (0)