From 9ffb4992fe751554d5c78b6215148e11332ddb70 Mon Sep 17 00:00:00 2001 From: Stanislau Petrusiou Date: Fri, 4 Jun 2021 14:32:11 +0200 Subject: [PATCH 1/7] Added RRSet comments support --- powerdns/client.go | 16 ++++++---- powerdns/resource_powerdns_record.go | 36 +++++++++++++++++++++++ powerdns/resource_powerdns_record_test.go | 35 ++++++++++++++++++++++ website/docs/r/record.html.markdown | 27 +++++++++++++++++ 4 files changed, 109 insertions(+), 5 deletions(-) diff --git a/powerdns/client.go b/powerdns/client.go index 78783dae..9c2fb2fd 100644 --- a/powerdns/client.go +++ b/powerdns/client.go @@ -178,11 +178,17 @@ type Record struct { // ResourceRecordSet represents a PowerDNS RRSet object type ResourceRecordSet struct { - Name string `json:"name"` - Type string `json:"type"` - ChangeType string `json:"changetype"` - TTL int `json:"ttl"` // For API v1 - Records []Record `json:"records,omitempty"` + Name string `json:"name"` + Type string `json:"type"` + ChangeType string `json:"changetype"` + TTL int `json:"ttl"` // For API v1 + Records []Record `json:"records,omitempty"` + Comments []Comment `json:"comments,omitempty"` +} + +type Comment struct { + Content string `json:"content,omitempty"` + Account string `json:"account,omitempty"` } type zonePatchRequest struct { diff --git a/powerdns/resource_powerdns_record.go b/powerdns/resource_powerdns_record.go index d2be002c..672fd93f 100644 --- a/powerdns/resource_powerdns_record.go +++ b/powerdns/resource_powerdns_record.go @@ -57,6 +57,27 @@ func resourcePDNSRecord() *schema.Resource { ForceNew: true, Description: "For A and AAAA records, if true, create corresponding PTR.", }, + + "comment": { + Type: schema.TypeSet, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "content": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "account": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + }, + Optional: true, + ForceNew: true, + Description: "A comment about an RRSet.", + }, }, } } @@ -70,6 +91,21 @@ func resourcePDNSRecordCreate(d *schema.ResourceData, meta interface{}) error { TTL: d.Get("ttl").(int), } + comments := d.Get("comment").(*schema.Set).List() + if len(comments) > 0 { + commentObjs := make([]Comment, 0, len(comments)) + for _, comment := range comments { + commentMap := comment.(map[string]interface{}) + commentObjs = append( + commentObjs, + Comment{ + Content: commentMap["content"].(string), + Account: commentMap["account"].(string), + }) + } + rrSet.Comments = commentObjs + } + zone := d.Get("zone").(string) ttl := d.Get("ttl").(int) recs := d.Get("records").(*schema.Set).List() diff --git a/powerdns/resource_powerdns_record_test.go b/powerdns/resource_powerdns_record_test.go index 4641387d..94ae8773 100644 --- a/powerdns/resource_powerdns_record_test.go +++ b/powerdns/resource_powerdns_record_test.go @@ -394,6 +394,22 @@ func TestAccPDNSRecord_TXT(t *testing.T) { }) } +func TestAccPDNSRecord_WithComments(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPDNSRecordDestroy, + Steps: []resource.TestStep{ + { + Config: testPDSNRecordWithComments, + Check: resource.ComposeTestCheckFunc( + testAccCheckPDNSRecordExists("powerdns_record.test-comments"), + ), + }, + }, + }) +} + func TestAccPDNSRecord_ALIAS(t *testing.T) { resourceName := "powerdns_record.test-alias" resourceID := `{"zone":"sysa.xyz.","id":"alias.sysa.xyz.:::ALIAS"}` @@ -654,3 +670,22 @@ resource "powerdns_record" "test-soa" { ttl = 3600 records = [ "something.something. hostmaster.sysa.xyz. 2019090301 10800 3600 604800 3600" ] }` + +const testPDSNRecordWithComments = ` +resource "powerdns_record" "test-comments" { + zone = "sysa.xyz." + name = "comment.sysa.xyz." + type = "A" + ttl = 60 + records = [ "1.1.1.1" ] + + comment { + content = "Test comment #1" + account = "Test account #1" + } + + comment { + content = "Test comment #2" + account = "Test account #2" + } +}` diff --git a/website/docs/r/record.html.markdown b/website/docs/r/record.html.markdown index aab47d04..7eb24a8e 100644 --- a/website/docs/r/record.html.markdown +++ b/website/docs/r/record.html.markdown @@ -42,6 +42,30 @@ resource "powerdns_record" "foobar" { } ``` +### Record with comments +An example creating a record with comments: + +```hcl +# Add a record with comments +resource "powerdns_record" "foobar" { + zone = "example.com." + name = "www.example.com." + type = "A" + ttl = 60 + records = [ "1.1.1.1" ] + + comment { + content = "Example comment #1" + account = "Example account #1" + } + + comment { + content = "Example comment #2" + account = "Example account #2" + } +} +``` + ### MX record example The following example shows, how to setup MX record with a priority of `10`. Please note that priority is not set as other `powerdns_record` properties; rather, it's part of the string that goes into `records` list. @@ -145,6 +169,9 @@ The following arguments are supported: * `ttl` - (Required) The TTL of the record. * `records` - (Required) A string list of records. * `set_ptr` - (Optional) [**_Deprecated in PowerDNS 4.3.0_**] A boolean (true/false), determining whether API server should automatically create PTR record in the matching reverse zone. Existing PTR records are replaced. If no matching reverse zone, an error is thrown. +* `comment` - (Optional) A comment about an RRSet. + * `content` - (Required) The content of the comment. + * `account` - (Required) The account of the comment. ### Attribute Reference From de70a43cbacf9c77cb686b51cc615ecd7c1ca833 Mon Sep 17 00:00:00 2001 From: Stanislau Petrusiou Date: Mon, 7 Jun 2021 16:32:22 +0200 Subject: [PATCH 2/7] Added RRSet comments --- powerdns/client.go | 67 ++++++++++++++++++----- powerdns/resource_powerdns_record.go | 11 ++++ powerdns/resource_powerdns_record_test.go | 11 +++- 3 files changed, 73 insertions(+), 16 deletions(-) diff --git a/powerdns/client.go b/powerdns/client.go index 9c2fb2fd..7872366e 100644 --- a/powerdns/client.go +++ b/powerdns/client.go @@ -428,26 +428,14 @@ func (client *Client) DeleteZone(name string) error { // ListRecords returns all records in Zone func (client *Client) ListRecords(zone string) ([]Record, error) { - req, err := client.newRequest("GET", fmt.Sprintf("/servers/localhost/zones/%s", zone), nil) - if err != nil { - return nil, err - } - - resp, err := client.HTTP.Do(req) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - zoneInfo := new(ZoneInfo) - err = json.NewDecoder(resp.Body).Decode(zoneInfo) + rrsets, err := client.ListRRSets(zone) if err != nil { return nil, err } - records := zoneInfo.Records + var records []Record // Convert the API v1 response to v0 record structure - for _, rrs := range zoneInfo.ResourceRecordSets { + for _, rrs := range rrsets { for _, record := range rrs.Records { records = append(records, Record{ Name: rrs.Name, @@ -461,6 +449,26 @@ func (client *Client) ListRecords(zone string) ([]Record, error) { return records, nil } +func (client *Client) getZoneInfo(zone string) (*ZoneInfo, error) { + req, err := client.newRequest("GET", fmt.Sprintf("/servers/localhost/zones/%s", zone), nil) + if err != nil { + return nil, err + } + + resp, err := client.HTTP.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + zoneInfo := new(ZoneInfo) + err = json.NewDecoder(resp.Body).Decode(zoneInfo) + if err != nil { + return nil, err + } + return zoneInfo, nil +} + // ListRecordsInRRSet returns only records of specified name and type func (client *Client) ListRecordsInRRSet(zone string, name string, tpe string) ([]Record, error) { allRecords, err := client.ListRecords(zone) @@ -487,6 +495,35 @@ func (client *Client) ListRecordsByID(zone string, recID string) ([]Record, erro return client.ListRecordsInRRSet(zone, name, tpe) } +//GetResourceRecordSet by zone and id +func (client *Client) GetRRSetOfRecord(zone string, recID string) (*ResourceRecordSet, error) { + name, tpe, err := parseID(recID) + if err != nil { + return nil, err + } + + rrsets, err := client.ListRRSets(zone) + if err != nil { + return nil, err + } + + for _, rrset := range rrsets { + if rrset.Name == name && rrset.Type == tpe { + return &rrset, nil + } + } + return nil, fmt.Errorf("Error getting rrset %s. Not found.", name) +} + +//ListRRSets by zone +func (client *Client) ListRRSets(zone string) ([]ResourceRecordSet, error) { + zoneInfo, err := client.getZoneInfo(zone) + if err != nil { + return nil, err + } + return zoneInfo.ResourceRecordSets, nil +} + // RecordExists checks if requested record exists in Zone func (client *Client) RecordExists(zone string, name string, tpe string) (bool, error) { allRecords, err := client.ListRecords(zone) diff --git a/powerdns/resource_powerdns_record.go b/powerdns/resource_powerdns_record.go index 672fd93f..c484c562 100644 --- a/powerdns/resource_powerdns_record.go +++ b/powerdns/resource_powerdns_record.go @@ -231,6 +231,8 @@ func resourcePDNSRecordImport(d *schema.ResourceData, meta interface{}) ([]*sche log.Printf("[INFO] importing PowerDNS Record %s in Zone: %s", recordID, zoneName) records, err := client.ListRecordsByID(zoneName, recordID) + rrset, err := client.GetRRSetOfRecord(zoneName, recordID) + if err != nil { return nil, fmt.Errorf("couldn't fetch PowerDNS Record: %s", err) } @@ -244,11 +246,20 @@ func resourcePDNSRecordImport(d *schema.ResourceData, meta interface{}) ([]*sche recs = append(recs, r.Content) } + commentsSet := make([]map[string]interface{}, len(rrset.Comments)) + for i, comment := range rrset.Comments { + commentsSet[i] = map[string]interface{}{ + "content": comment.Content, + "account": comment.Account, + } + } + d.Set("zone", zoneName) d.Set("name", records[0].Name) d.Set("ttl", records[0].TTL) d.Set("type", records[0].Type) d.Set("records", recs) + d.Set("comment", commentsSet) d.SetId(recordID) return []*schema.ResourceData{d}, nil diff --git a/powerdns/resource_powerdns_record_test.go b/powerdns/resource_powerdns_record_test.go index 94ae8773..dcd099e4 100644 --- a/powerdns/resource_powerdns_record_test.go +++ b/powerdns/resource_powerdns_record_test.go @@ -395,6 +395,9 @@ func TestAccPDNSRecord_TXT(t *testing.T) { } func TestAccPDNSRecord_WithComments(t *testing.T) { + resourceName := "powerdns_record.test-comments" + resourceID := `{"zone":"sysa.xyz.","id":"comment.sysa.xyz.:::A"}` + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -403,9 +406,15 @@ func TestAccPDNSRecord_WithComments(t *testing.T) { { Config: testPDSNRecordWithComments, Check: resource.ComposeTestCheckFunc( - testAccCheckPDNSRecordExists("powerdns_record.test-comments"), + testAccCheckPDNSRecordExists(resourceName), ), }, + { + ResourceName: resourceName, + ImportStateId: resourceID, + ImportState: true, + ImportStateVerify: true, + }, }, }) } From 13d20655d4f04839c818686ca9dd03a0cd96b0fd Mon Sep 17 00:00:00 2001 From: Stanislau Petrusiou Date: Thu, 17 Jun 2021 10:40:43 +0200 Subject: [PATCH 3/7] Fixed confusing comment --- powerdns/client.go | 1 - 1 file changed, 1 deletion(-) diff --git a/powerdns/client.go b/powerdns/client.go index 7872366e..8712c26b 100644 --- a/powerdns/client.go +++ b/powerdns/client.go @@ -434,7 +434,6 @@ func (client *Client) ListRecords(zone string) ([]Record, error) { } var records []Record - // Convert the API v1 response to v0 record structure for _, rrs := range rrsets { for _, record := range rrs.Records { records = append(records, Record{ From 78f18760eb3b914b039fba22e9ee293e29af4dba Mon Sep 17 00:00:00 2001 From: Stanislau Petrusiou Date: Thu, 17 Jun 2021 12:21:57 +0200 Subject: [PATCH 4/7] Fixed documentation indent --- website/docs/r/record.html.markdown | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/website/docs/r/record.html.markdown b/website/docs/r/record.html.markdown index 7eb24a8e..448a5a24 100644 --- a/website/docs/r/record.html.markdown +++ b/website/docs/r/record.html.markdown @@ -50,19 +50,19 @@ An example creating a record with comments: resource "powerdns_record" "foobar" { zone = "example.com." name = "www.example.com." - type = "A" - ttl = 60 - records = [ "1.1.1.1" ] - - comment { - content = "Example comment #1" - account = "Example account #1" - } - - comment { - content = "Example comment #2" - account = "Example account #2" - } + type = "A" + ttl = 60 + records = [ "1.1.1.1" ] + + comment { + content = "Example comment #1" + account = "Example account #1" + } + + comment { + content = "Example comment #2" + account = "Example account #2" + } } ``` From 09e5900130ab425b7df9434284ffc11405bc9645 Mon Sep 17 00:00:00 2001 From: Stanislau Petrusiou Date: Fri, 18 Jun 2021 15:01:03 +0200 Subject: [PATCH 5/7] Fixed caches error handling if its overflowed --- powerdns/client.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/powerdns/client.go b/powerdns/client.go index b41d8111..499ce310 100644 --- a/powerdns/client.go +++ b/powerdns/client.go @@ -12,8 +12,8 @@ import ( "strconv" "strings" - freecache "github.com/coocood/freecache" - cleanhttp "github.com/hashicorp/go-cleanhttp" + "github.com/coocood/freecache" + "github.com/hashicorp/go-cleanhttp" ) // DefaultSchema is the value used for the URL in case @@ -517,8 +517,8 @@ func (client *Client) getZoneInfo(zone string) (*ZoneInfo, error) { err = client.Cache.Set([]byte(zone), cacheValue, client.CacheTTL) if err != nil { - return nil, fmt.Errorf("The cache for REST API requests is enabled but the size isn't enough: cacheSize: %db \n %s", - DefaultCacheSize, err) + fmt.Printf("[WARN] The cache for REST API requests is enabled but"+ + " the size isn't enough: cacheSize: %db \n %s", DefaultCacheSize, err) } } } From 802fde72046eccaed9ede6ef9ecbdf9bc580de1d Mon Sep 17 00:00:00 2001 From: Stanislau Petrusiou Date: Fri, 18 Jun 2021 15:12:33 +0200 Subject: [PATCH 6/7] Changelog has extended --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 562db828..10477b34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ ## 1.5.0 (Unreleased) FEATURES: - * **Added option to cache PowerDNS API response ** ([#81](https://github.com/pan-net/terraform-provider-powerdns/pull/81), @menai34) + * **Added option to cache PowerDNS API response** ([#81](https://github.com/pan-net/terraform-provider-powerdns/pull/81), @menai34) + * **Added comments attribute for powerdns zone resource** ([#87](https://github.com/pan-net/terraform-provider-powerdns/pull/87), @PetrusHahol) ## 1.4.1 (January 21, 2021) From 486381164b93ab2ed80a51be4690316529bcc265 Mon Sep 17 00:00:00 2001 From: Stanislau Petrusiou Date: Fri, 18 Jun 2021 16:46:59 +0200 Subject: [PATCH 7/7] Through the error from Cache.Set --- powerdns/client.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/powerdns/client.go b/powerdns/client.go index 499ce310..4ef5220e 100644 --- a/powerdns/client.go +++ b/powerdns/client.go @@ -517,8 +517,7 @@ func (client *Client) getZoneInfo(zone string) (*ZoneInfo, error) { err = client.Cache.Set([]byte(zone), cacheValue, client.CacheTTL) if err != nil { - fmt.Printf("[WARN] The cache for REST API requests is enabled but"+ - " the size isn't enough: cacheSize: %db \n %s", DefaultCacheSize, err) + return nil, err } } }