-
Notifications
You must be signed in to change notification settings - Fork 134
[CDTOOL-1321] Add DNS Zones and TSIG Keys Support #805
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 3 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
9ce25d6
feat(dns): add DNS zones and TSIG keys support
rcaril 8c34659
update changelog
rcaril 3fc4199
(fix): update incorrect JSON-decode for Delete operations and linting…
rcaril b0b4284
reorder error.go
rcaril e0f436b
feat(dns/dnszones): add support for updating the 'inbound_tsig_key_id…
rcaril 920d120
(dns): added support for the `Description` field to be `null`
rcaril a2fb351
(dns): added pagination to dnszones and tsigkeys
rcaril File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| // Package dns contains subpackages that offer maintenance around Fastly | ||
| // Domain Name System (DNS) zones and TSIG (Transaction Signature) keys. | ||
| package dns |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| package dnszones | ||
|
|
||
| import ( | ||
| "context" | ||
| "encoding/json" | ||
| "fmt" | ||
|
|
||
| "github.com/fastly/go-fastly/v14/fastly" | ||
| ) | ||
|
|
||
| // CreateInput specifies the information needed to create a zone. | ||
| type CreateInput struct { | ||
| // Name is the domain name for the DNS zone (required). | ||
| Name *string `json:"name"` | ||
| // Type is the type of the DNS zone (required). | ||
| Type *string `json:"type"` | ||
| // Description is a freeform descriptive note. | ||
| Description *string `json:"description,omitempty"` | ||
| // XfrConfigInbound contains attributes associated with inbound zone transfers. | ||
| XfrConfigInbound *XfrConfigInboundInput `json:"xfr_config_inbound,omitempty"` | ||
| } | ||
|
|
||
| // Create creates a new DNS Zone. | ||
| func Create(ctx context.Context, c *fastly.Client, i *CreateInput) (*Zone, error) { | ||
| if i.Name == nil { | ||
| return nil, fastly.ErrMissingName | ||
| } | ||
| if i.Type == nil { | ||
| return nil, fastly.ErrMissingType | ||
| } | ||
|
|
||
| resp, err := c.PostJSON(ctx, "/dns/v1/zones", i, fastly.CreateRequestOptions()) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| defer resp.Body.Close() | ||
|
|
||
| var zone *Zone | ||
| if err := json.NewDecoder(resp.Body).Decode(&zone); err != nil { | ||
| return nil, fmt.Errorf("failed to decode json response: %w", err) | ||
| } | ||
|
|
||
| return zone, nil | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| package dnszones | ||
|
|
||
| import ( | ||
| "context" | ||
|
|
||
| "github.com/fastly/go-fastly/v14/fastly" | ||
| ) | ||
|
|
||
| // DeleteInput specifies the information needed for the Delete() function to | ||
| // perform the operation. | ||
| type DeleteInput struct { | ||
| // ZoneID is the Zone Identifier (UUID) (required). | ||
| ZoneID *string `json:"-"` | ||
| } | ||
|
|
||
| // Delete deletes a specified DNS Zone. | ||
| func Delete(ctx context.Context, c *fastly.Client, i *DeleteInput) error { | ||
| if i.ZoneID == nil { | ||
| return fastly.ErrMissingID | ||
| } | ||
|
|
||
| path := fastly.ToSafeURL("dns", "v1", "zones", *i.ZoneID) | ||
|
|
||
| resp, err := c.Delete(ctx, path, fastly.CreateRequestOptions()) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| defer resp.Body.Close() | ||
|
|
||
| return nil | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| package dnszones | ||
|
|
||
| import ( | ||
| "context" | ||
| "encoding/json" | ||
| "fmt" | ||
|
|
||
| "github.com/fastly/go-fastly/v14/fastly" | ||
| ) | ||
|
|
||
| // GetInput specifies the information needed to get a zone. | ||
| type GetInput struct { | ||
| // ZoneID is the Zone Identifier (UUID) (required). | ||
| ZoneID *string `json:"-"` | ||
| } | ||
|
|
||
| // Get retrieves a specified DNS Zone. | ||
| func Get(ctx context.Context, c *fastly.Client, i *GetInput) (*Zone, error) { | ||
| if i.ZoneID == nil { | ||
| return nil, fastly.ErrMissingID | ||
| } | ||
|
|
||
| path := fastly.ToSafeURL("dns", "v1", "zones", *i.ZoneID) | ||
|
|
||
| resp, err := c.GetJSON(ctx, path, fastly.CreateRequestOptions()) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| defer resp.Body.Close() | ||
|
|
||
| var zone *Zone | ||
| if err := json.NewDecoder(resp.Body).Decode(&zone); err != nil { | ||
| return nil, fmt.Errorf("failed to decode json response: %w", err) | ||
| } | ||
|
|
||
| return zone, nil | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| package dnszones | ||
|
|
||
| import ( | ||
| "context" | ||
| "encoding/json" | ||
| "fmt" | ||
| "strconv" | ||
|
|
||
| "github.com/fastly/go-fastly/v14/fastly" | ||
| ) | ||
|
|
||
| // ListInput specifies the information needed to list zones. | ||
| type ListInput struct { | ||
| // Cursor is the value from the next_cursor field of a previous | ||
| // response, used to retrieve the next page. To request the first | ||
| // page, this should be empty. | ||
| Cursor *string | ||
| // Limit is how many results are returned. | ||
| Limit *int | ||
| // Name filters the list to return only zones that contain the provided name. | ||
| Name *string | ||
| // Sort is the order in which to list the results. | ||
| Sort *string | ||
| } | ||
|
|
||
| // List retrieves a paginated list of DNS Zones. | ||
| func List(ctx context.Context, c *fastly.Client, i *ListInput) (*Zones, error) { | ||
| path := fastly.ToSafeURL("dns", "v1", "zones") | ||
|
|
||
| requestOptions := fastly.CreateRequestOptions() | ||
| if i.Cursor != nil { | ||
| requestOptions.Params["cursor"] = *i.Cursor | ||
| } | ||
| if i.Limit != nil { | ||
| requestOptions.Params["limit"] = strconv.Itoa(*i.Limit) | ||
| } | ||
| if i.Name != nil { | ||
| requestOptions.Params["name"] = *i.Name | ||
| } | ||
| if i.Sort != nil { | ||
| requestOptions.Params["sort"] = *i.Sort | ||
| } | ||
|
|
||
| resp, err := c.GetJSON(ctx, path, requestOptions) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| defer resp.Body.Close() | ||
|
|
||
| var zones *Zones | ||
| if err := json.NewDecoder(resp.Body).Decode(&zones); err != nil { | ||
| return nil, fmt.Errorf("failed to decode json response: %w", err) | ||
| } | ||
|
|
||
| return zones, nil | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| package dnszones | ||
|
|
||
| // Zone is the API response structure for the create, update and get operations. | ||
| type Zone struct { | ||
| // ID is the zone identifier (UUID). | ||
| ID *string `json:"id"` | ||
| // Name is the domain name for your zone. | ||
| Name *string `json:"name"` | ||
| // Description is a freeform descriptive note. | ||
| Description *string `json:"description"` | ||
| // Type is the type of the zone. | ||
|
jedisct1 marked this conversation as resolved.
|
||
| Type *string `json:"type"` | ||
| // Serial is serial number of the zone's SOA record. | ||
| Serial *string `json:"serial"` | ||
| // Nameservers is an array of the nameserver hostnames assigned to the zone. | ||
| Nameservers []string `json:"nameservers"` | ||
| // XfrConfigInbound contains all attributes associated with inbound zone transfers. | ||
| XfrConfigInbound *XfrConfigInbound `json:"xfr_config_inbound"` | ||
| // CreatedAt is the date and time the zone was created. | ||
| CreatedAt *string `json:"created_at"` | ||
| // UpdatedAt is the date and time the zone was last updated. | ||
| UpdatedAt *string `json:"updated_at"` | ||
| } | ||
|
|
||
| // XfrConfigInbound contains all attributes associated with inbound zone transfers. | ||
| type XfrConfigInbound struct { | ||
| // Primaries is an array of the primary DNS server objects associated with inbound zone transfers. | ||
| Primaries []Primary `json:"primaries"` | ||
| // NotifyIPAddresses are IP addresses where Primary DNS servers can send NOTIFY messages. | ||
| NotifyIPAddresses *NotifyIPAddresses `json:"notify_ip_addresses"` | ||
| // InboundTSIGKeyID is the ID of the TSIG key used to secure inbound zone transfers. | ||
| InboundTSIGKeyID *string `json:"inbound_tsig_key_id"` | ||
| } | ||
|
|
||
| // XfrConfigInboundInput specifies the inbound zone transfer attributes for create and update requests. | ||
| type XfrConfigInboundInput struct { | ||
| // Primaries is an array of primary DNS server objects for inbound zone transfers. | ||
| Primaries []Primary `json:"primaries,omitempty"` | ||
|
jedisct1 marked this conversation as resolved.
|
||
| // InboundTSIGKeyID is the ID of the TSIG key used to secure inbound zone transfers. | ||
| InboundTSIGKeyID *string `json:"inbound_tsig_key_id,omitempty"` | ||
|
jedisct1 marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| // Primary represents a primary DNS server for inbound zone transfers. | ||
| type Primary struct { | ||
| // Address is an IPv4 address for the Primary DNS Server. | ||
| Address *string `json:"address"` | ||
| // Description is a description of the Primary DNS server. | ||
| Description *string `json:"description"` | ||
| } | ||
|
|
||
| // NotifyIPAddresses contains IP addresses where primary DNS servers can send NOTIFY messages. | ||
| type NotifyIPAddresses struct { | ||
| // IPv4 are IPv4 addresses where Primary DNS servers can send NOTIFY messages. | ||
| IPv4 []string `json:"ipv4"` | ||
| } | ||
|
|
||
| // Zones is the paginated API response for listing zones. | ||
| type Zones struct { | ||
| // Data is the list of zones. | ||
| Data []Zone `json:"data"` | ||
| // Meta contains pagination metadata. | ||
| Meta MetaZones `json:"meta"` | ||
| } | ||
|
|
||
| // MetaZones is a subset of the Zone response structure. | ||
| type MetaZones struct { | ||
| // NextCursor is the cursor value to use in the next request to retrieve the next page. | ||
| NextCursor *string `json:"next_cursor"` | ||
| // Limit is the maximum number of results returned. | ||
| Limit *int `json:"limit"` | ||
| // Sort is the order in which the results are listed. | ||
| Sort *string `json:"sort"` | ||
| // Total is the total number of zones. | ||
| Total *int `json:"total"` | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,134 @@ | ||
| package dnszones | ||
|
|
||
| import ( | ||
| "context" | ||
| "testing" | ||
|
|
||
| "github.com/stretchr/testify/require" | ||
|
|
||
| "github.com/fastly/go-fastly/v14/fastly" | ||
| ) | ||
|
|
||
| func TestZones(t *testing.T) { | ||
| ctx := context.TODO() | ||
|
|
||
| var err error | ||
|
|
||
| // Create dns zone. | ||
| var zone *Zone | ||
| fastly.Record(t, "create_zone", func(c *fastly.Client) { | ||
| zone, err = Create(ctx, c, &CreateInput{ | ||
| Name: fastly.ToPointer("go-fastly-test.com"), | ||
| Type: fastly.ToPointer("secondary"), | ||
| Description: fastly.ToPointer("go-fastly test zone"), | ||
| }) | ||
| }) | ||
| require.NoError(t, err) | ||
| require.NotNil(t, zone) | ||
| require.NotNil(t, zone.ID) | ||
| // The API normalizes zone names to fully-qualified domain names (trailing dot). | ||
| require.Equal(t, "go-fastly-test.com.", *zone.Name) | ||
| require.Equal(t, "secondary", *zone.Type) | ||
| require.Equal(t, "go-fastly test zone", *zone.Description) | ||
|
|
||
| defer func() { | ||
| fastly.Record(t, "delete_zone", func(c *fastly.Client) { | ||
| _ = Delete(ctx, c, &DeleteInput{ | ||
| ZoneID: zone.ID, | ||
| }) | ||
| }) | ||
| }() | ||
|
|
||
| // Get dns zone. | ||
| var got *Zone | ||
| fastly.Record(t, "get_zone", func(c *fastly.Client) { | ||
| got, err = Get(ctx, c, &GetInput{ | ||
| ZoneID: zone.ID, | ||
| }) | ||
| }) | ||
| require.NoError(t, err) | ||
| require.NotNil(t, got) | ||
| require.Equal(t, *zone.ID, *got.ID) | ||
| require.Equal(t, *zone.Name, *got.Name) | ||
|
|
||
| // Update | ||
| var updated *Zone | ||
| fastly.Record(t, "update_zone", func(c *fastly.Client) { | ||
| updated, err = Update(ctx, c, &UpdateInput{ | ||
| ZoneID: zone.ID, | ||
| Description: fastly.ToPointer("updated description"), | ||
| }) | ||
| }) | ||
| require.NoError(t, err) | ||
| require.NotNil(t, updated) | ||
| require.Equal(t, *zone.ID, *updated.ID) | ||
| require.Equal(t, "updated description", *updated.Description) | ||
|
|
||
| // Create a second dns zone for pagination testing. | ||
| var zone2 *Zone | ||
| fastly.Record(t, "create_zone_2", func(c *fastly.Client) { | ||
| zone2, err = Create(ctx, c, &CreateInput{ | ||
| Name: fastly.ToPointer("go-fastly-test-2.com"), | ||
| Type: fastly.ToPointer("secondary"), | ||
| Description: fastly.ToPointer("go-fastly test zone 2"), | ||
| }) | ||
| }) | ||
| require.NoError(t, err) | ||
| require.NotNil(t, zone2) | ||
|
|
||
| defer func() { | ||
| fastly.Record(t, "delete_zone_2", func(c *fastly.Client) { | ||
| _ = Delete(ctx, c, &DeleteInput{ | ||
| ZoneID: zone2.ID, | ||
| }) | ||
| }) | ||
| }() | ||
|
|
||
| // List dns zones — page 1. | ||
| var page1 *Zones | ||
| fastly.Record(t, "list_zones_page_1", func(c *fastly.Client) { | ||
| page1, err = List(ctx, c, &ListInput{ | ||
| Limit: fastly.ToPointer(1), | ||
| }) | ||
| }) | ||
| require.NoError(t, err) | ||
| require.NotNil(t, page1) | ||
| require.Len(t, page1.Data, 1) | ||
| require.NotNil(t, page1.Meta.NextCursor, "expected a next_cursor for page 2") | ||
|
|
||
| // List dns zones — page 2, using cursor from page 1. | ||
| var page2 *Zones | ||
| fastly.Record(t, "list_zones_page_2", func(c *fastly.Client) { | ||
| page2, err = List(ctx, c, &ListInput{ | ||
| Limit: fastly.ToPointer(1), | ||
| Cursor: page1.Meta.NextCursor, | ||
| }) | ||
| }) | ||
| require.NoError(t, err) | ||
| require.NotNil(t, page2) | ||
| require.Len(t, page2.Data, 1) | ||
| require.NotEqual(t, *page1.Data[0].ID, *page2.Data[0].ID, "pages should return different zones") | ||
| } | ||
|
|
||
| func TestZones_validation(t *testing.T) { | ||
| ctx := context.TODO() | ||
|
|
||
| _, err := Get(ctx, fastly.TestClient, &GetInput{ZoneID: nil}) | ||
| require.ErrorIs(t, err, fastly.ErrMissingID) | ||
|
|
||
| _, err = Create(ctx, fastly.TestClient, &CreateInput{ | ||
| Type: fastly.ToPointer("primary"), | ||
| }) | ||
| require.ErrorIs(t, err, fastly.ErrMissingName) | ||
|
|
||
| _, err = Create(ctx, fastly.TestClient, &CreateInput{ | ||
| Name: fastly.ToPointer("example.com"), | ||
| }) | ||
| require.ErrorIs(t, err, fastly.ErrMissingType) | ||
|
|
||
| _, err = Update(ctx, fastly.TestClient, &UpdateInput{ZoneID: nil}) | ||
| require.ErrorIs(t, err, fastly.ErrMissingID) | ||
|
|
||
| err = Delete(ctx, fastly.TestClient, &DeleteInput{ZoneID: nil}) | ||
| require.ErrorIs(t, err, fastly.ErrMissingID) | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.