Skip to content

Commit 2510755

Browse files
xlastack72
authored andcommitted
provider/cloudflare: Add proxied option (hashicorp#5508)
This change adds the support for the proxied configuration option for a record which enables origin protection for CloudFlare records. In order to do so the golang library needed to be changed as the old did not support the option and was using and outdated API version. Open issues which ask for this (hashicorp#5049, hashicorp#3805).
1 parent d692cf5 commit 2510755

21 files changed

Lines changed: 1175 additions & 91 deletions

Godeps/Godeps.json

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
package cloudflare
22

33
import (
4-
"fmt"
54
"log"
65

7-
"github.com/pearkes/cloudflare"
6+
"github.com/crackcomm/cloudflare"
87
)
98

109
type Config struct {
@@ -14,13 +13,12 @@ type Config struct {
1413

1514
// Client() returns a new client for accessing cloudflare.
1615
func (c *Config) Client() (*cloudflare.Client, error) {
17-
client, err := cloudflare.NewClient(c.Email, c.Token)
16+
client := cloudflare.New(&cloudflare.Options{
17+
Email: c.Email,
18+
Key: c.Token,
19+
})
1820

19-
if err != nil {
20-
return nil, fmt.Errorf("Error setting up client: %s", err)
21-
}
22-
23-
log.Printf("[INFO] CloudFlare Client configured for user: %s", client.Email)
21+
log.Printf("[INFO] CloudFlare Client configured for user: %s", c.Email)
2422

2523
return client, nil
2624
}

builtin/providers/cloudflare/provider_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,6 @@ func testAccPreCheck(t *testing.T) {
3838
}
3939

4040
if v := os.Getenv("CLOUDFLARE_DOMAIN"); v == "" {
41-
t.Fatal("CLOUDFLARE_DOMAIN must be set for acceptance tests. The domain is used to ` and destroy record against.")
41+
t.Fatal("CLOUDFLARE_DOMAIN must be set for acceptance tests. The domain is used to create and destroy record against.")
4242
}
4343
}

builtin/providers/cloudflare/resource_cloudflare_record.go

Lines changed: 149 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ import (
44
"fmt"
55
"log"
66
"strings"
7+
"time"
78

9+
"golang.org/x/net/context"
10+
11+
"github.com/crackcomm/cloudflare"
812
"github.com/hashicorp/terraform/helper/schema"
9-
"github.com/pearkes/cloudflare"
1013
)
1114

1215
func resourceCloudFlareRecord() *schema.Resource {
@@ -44,14 +47,25 @@ func resourceCloudFlareRecord() *schema.Resource {
4447
},
4548

4649
"ttl": &schema.Schema{
47-
Type: schema.TypeString,
50+
Type: schema.TypeInt,
4851
Optional: true,
4952
Computed: true,
5053
},
5154

5255
"priority": &schema.Schema{
53-
Type: schema.TypeString,
56+
Type: schema.TypeInt,
57+
Optional: true,
58+
},
59+
60+
"proxied": &schema.Schema{
61+
Default: false,
5462
Optional: true,
63+
Type: schema.TypeBool,
64+
},
65+
66+
"zone_id": &schema.Schema{
67+
Type: schema.TypeString,
68+
Computed: true,
5569
},
5670
},
5771
}
@@ -60,81 +74,111 @@ func resourceCloudFlareRecord() *schema.Resource {
6074
func resourceCloudFlareRecordCreate(d *schema.ResourceData, meta interface{}) error {
6175
client := meta.(*cloudflare.Client)
6276

63-
// Create the new record
64-
newRecord := &cloudflare.CreateRecord{
65-
Name: d.Get("name").(string),
66-
Type: d.Get("type").(string),
67-
Content: d.Get("value").(string),
77+
newRecord := &cloudflare.Record{
78+
Content: d.Get("value").(string),
79+
Name: d.Get("name").(string),
80+
Proxied: d.Get("proxied").(bool),
81+
Type: d.Get("type").(string),
82+
ZoneName: d.Get("domain").(string),
83+
}
84+
85+
if priority, ok := d.GetOk("priority"); ok {
86+
newRecord.Priority = priority.(int)
6887
}
6988

7089
if ttl, ok := d.GetOk("ttl"); ok {
71-
newRecord.Ttl = ttl.(string)
90+
newRecord.TTL = ttl.(int)
7291
}
7392

74-
if priority, ok := d.GetOk("priority"); ok {
75-
newRecord.Priority = priority.(string)
93+
zone, err := retrieveZone(client, newRecord.ZoneName)
94+
if err != nil {
95+
return err
7696
}
7797

98+
d.Set("zone_id", zone.ID)
99+
newRecord.ZoneID = zone.ID
100+
78101
log.Printf("[DEBUG] CloudFlare Record create configuration: %#v", newRecord)
79102

80-
rec, err := client.CreateRecord(d.Get("domain").(string), newRecord)
103+
ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(time.Second*30))
81104

105+
err = client.Records.Create(ctx, newRecord)
82106
if err != nil {
83-
return fmt.Errorf("Failed to create CloudFlare Record: %s", err)
107+
return fmt.Errorf("Failed to create record: %s", err)
84108
}
85109

86-
d.SetId(rec.Id)
110+
d.SetId(newRecord.ID)
111+
87112
log.Printf("[INFO] CloudFlare Record ID: %s", d.Id())
88113

89114
return resourceCloudFlareRecordRead(d, meta)
90115
}
91116

92117
func resourceCloudFlareRecordRead(d *schema.ResourceData, meta interface{}) error {
93-
client := meta.(*cloudflare.Client)
118+
var (
119+
client = meta.(*cloudflare.Client)
120+
domain = d.Get("domain").(string)
121+
rName = strings.Join([]string{d.Get("name").(string), domain}, ".")
122+
)
94123

95-
rec, err := client.RetrieveRecord(d.Get("domain").(string), d.Id())
124+
zone, err := retrieveZone(client, domain)
96125
if err != nil {
97-
if strings.Contains(err.Error(), "not found") {
98-
d.SetId("")
99-
return nil
100-
}
126+
return err
127+
}
101128

102-
return fmt.Errorf(
103-
"Couldn't find CloudFlare Record ID (%s) for domain (%s): %s",
104-
d.Id(), d.Get("domain").(string), err)
129+
record, err := retrieveRecord(client, zone, rName)
130+
if err != nil {
131+
return err
105132
}
106133

107-
d.Set("name", rec.Name)
108-
d.Set("hostname", rec.FullName)
109-
d.Set("type", rec.Type)
110-
d.Set("value", rec.Value)
111-
d.Set("ttl", rec.Ttl)
112-
d.Set("priority", rec.Priority)
134+
d.SetId(record.ID)
135+
d.Set("hostname", record.Name)
136+
d.Set("type", record.Type)
137+
d.Set("value", record.Content)
138+
d.Set("ttl", record.TTL)
139+
d.Set("priority", record.Priority)
140+
d.Set("proxied", record.Proxied)
141+
d.Set("zone_id", zone.ID)
113142

114143
return nil
115144
}
116145

117146
func resourceCloudFlareRecordUpdate(d *schema.ResourceData, meta interface{}) error {
118147
client := meta.(*cloudflare.Client)
119148

120-
// CloudFlare requires we send all values for an update request
121-
updateRecord := &cloudflare.UpdateRecord{
122-
Name: d.Get("name").(string),
123-
Type: d.Get("type").(string),
124-
Content: d.Get("value").(string),
149+
updateRecord := &cloudflare.Record{
150+
Content: d.Get("value").(string),
151+
ID: d.Id(),
152+
Name: d.Get("name").(string),
153+
Proxied: false,
154+
Type: d.Get("type").(string),
155+
ZoneName: d.Get("domain").(string),
156+
}
157+
158+
if priority, ok := d.GetOk("priority"); ok {
159+
updateRecord.Priority = priority.(int)
160+
}
161+
162+
if proxied, ok := d.GetOk("proxied"); ok {
163+
updateRecord.Proxied = proxied.(bool)
125164
}
126165

127166
if ttl, ok := d.GetOk("ttl"); ok {
128-
updateRecord.Ttl = ttl.(string)
167+
updateRecord.TTL = ttl.(int)
129168
}
130169

131-
if priority, ok := d.GetOk("priority"); ok {
132-
updateRecord.Priority = priority.(string)
170+
zone, err := retrieveZone(client, updateRecord.ZoneName)
171+
if err != nil {
172+
return err
133173
}
134174

175+
updateRecord.ZoneID = zone.ID
176+
135177
log.Printf("[DEBUG] CloudFlare Record update configuration: %#v", updateRecord)
136178

137-
err := client.UpdateRecord(d.Get("domain").(string), d.Id(), updateRecord)
179+
ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(time.Second*30))
180+
181+
err = client.Records.Patch(ctx, updateRecord)
138182
if err != nil {
139183
return fmt.Errorf("Failed to update CloudFlare Record: %s", err)
140184
}
@@ -143,15 +187,79 @@ func resourceCloudFlareRecordUpdate(d *schema.ResourceData, meta interface{}) er
143187
}
144188

145189
func resourceCloudFlareRecordDelete(d *schema.ResourceData, meta interface{}) error {
146-
client := meta.(*cloudflare.Client)
190+
var (
191+
client = meta.(*cloudflare.Client)
192+
domain = d.Get("domain").(string)
193+
rName = strings.Join([]string{d.Get("name").(string), domain}, ".")
194+
)
195+
196+
zone, err := retrieveZone(client, domain)
197+
if err != nil {
198+
return err
199+
}
147200

148-
log.Printf("[INFO] Deleting CloudFlare Record: %s, %s", d.Get("domain").(string), d.Id())
201+
record, err := retrieveRecord(client, zone, rName)
202+
if err != nil {
203+
return err
204+
}
149205

150-
err := client.DestroyRecord(d.Get("domain").(string), d.Id())
206+
log.Printf("[INFO] Deleting CloudFlare Record: %s, %s", domain, d.Id())
151207

208+
ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(time.Second*30))
209+
210+
err = client.Records.Delete(ctx, zone.ID, record.ID)
152211
if err != nil {
153212
return fmt.Errorf("Error deleting CloudFlare Record: %s", err)
154213
}
155214

156215
return nil
157216
}
217+
218+
func retrieveRecord(
219+
client *cloudflare.Client,
220+
zone *cloudflare.Zone,
221+
name string,
222+
) (*cloudflare.Record, error) {
223+
ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(time.Second*30))
224+
225+
rs, err := client.Records.List(ctx, zone.ID)
226+
if err != nil {
227+
return nil, fmt.Errorf("Unable to retrieve records for (%s): %s", zone.Name, err)
228+
}
229+
230+
var record *cloudflare.Record
231+
232+
for _, r := range rs {
233+
if r.Name == name {
234+
record = r
235+
}
236+
}
237+
if record == nil {
238+
return nil, fmt.Errorf("Unable to find Cloudflare record %s", name)
239+
}
240+
241+
return record, nil
242+
}
243+
244+
func retrieveZone(client *cloudflare.Client, domain string) (*cloudflare.Zone, error) {
245+
ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(time.Second*30))
246+
247+
zs, err := client.Zones.List(ctx)
248+
if err != nil {
249+
return nil, fmt.Errorf("Failed to fetch zone for %s: %s", domain, err)
250+
}
251+
252+
var zone *cloudflare.Zone
253+
254+
for _, z := range zs {
255+
if z.Name == domain {
256+
zone = z
257+
}
258+
}
259+
260+
if zone == nil {
261+
return nil, fmt.Errorf("Failed to find zone for: %s", domain)
262+
}
263+
264+
return zone, nil
265+
}

0 commit comments

Comments
 (0)