Skip to content
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

feat: add account level custom nameservers #1304

Merged
merged 9 commits into from
Jun 14, 2023
3 changes: 3 additions & 0 deletions .changelog/1304.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
account_level_custom_hostnames: add support for the account level custom hostname api
```
162 changes: 162 additions & 0 deletions account_level_custom_nameservers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package cloudflare

import (
"context"
"encoding/json"
"fmt"
"net/http"
)

type CustomNameserverRecord struct {
Type string `json:"type"`
Value string `json:"value"`
}

type CustomNameserver struct {
NSName string `json:"ns_name"`
NSSet int `json:"ns_set"`
}

type CustomNameserverResult struct {
DNSRecords []CustomNameserverRecord `json:"dns_records"`
NSName string `json:"ns_name"`
NSSet int `json:"ns_set"`
Status string `json:"status"`
ZoneTag string `json:"zone_tag"`
}

type CustomNameserverZoneMetadata struct {
Type string `json:"type"`
NSSet string `json:"ns_set"`
Enabled bool `json:"enabled"`
}

type customNameserverListResponse struct {
Response
Result []CustomNameserverResult `json:"result"`
}

type customNameserverCreateResponse struct {
Response
Result CustomNameserverResult `json:"result"`
}

type customNameserverZoneMetadata struct {
Response
Result CustomNameserverZoneMetadata
}

// GetAccountCustomNameservers lists an account's custom nameservers.
//
// API documentation: https://developers.cloudflare.com/api/operations/account-level-custom-nameservers-list-account-custom-nameservers
func (api *API) GetAccountCustomNameservers(ctx context.Context, rc *ResourceContainer) ([]CustomNameserverResult, error) {
uri := fmt.Sprintf("/accounts/%s/custom_ns", rc.Identifier)
jacobbednarz marked this conversation as resolved.
Show resolved Hide resolved

res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}

response := &customNameserverListResponse{}
err = json.Unmarshal(res, &response)
if err != nil {
return nil, fmt.Errorf("%s: %w", errUnmarshalError, err)
}

return response.Result, nil
}

// CreateAccountCustomNameserver adds an account custom nameserver.
//
// API documentation: https://developers.cloudflare.com/api/operations/account-level-custom-nameservers-add-account-custom-nameserver
func (api *API) CreateAccountCustomNameserver(ctx context.Context, rc *ResourceContainer, param CustomNameserver) (CustomNameserverResult, error) {
uri := fmt.Sprintf("/accounts/%s/custom_ns", rc.Identifier)

res, err := api.makeRequestContext(ctx, http.MethodPost, uri, param)
if err != nil {
return CustomNameserverResult{}, err
}

response := &customNameserverCreateResponse{}
err = json.Unmarshal(res, &response)
if err != nil {
return CustomNameserverResult{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
}

return response.Result, nil
}

// DeleteAccountCustomNameserver removes an account custom nameserver.
//
// API documentation: https://developers.cloudflare.com/api/operations/account-level-custom-nameservers-delete-account-custom-nameserver
func (api *API) DeleteAccountCustomNameserver(ctx context.Context, rc *ResourceContainer, nsName string) error {
uri := fmt.Sprintf("/accounts/%s/custom_ns/%s", rc.Identifier, nsName)

_, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil)
if err != nil {
return err
}

return nil
}

// GetEligibleZonesAccountCustomNameservers lists zones eligible for account custom nameservers.
//
// API documentation: https://developers.cloudflare.com/api/operations/account-level-custom-nameservers-get-eligible-zones-for-account-custom-nameservers
func (api *API) GetEligibleZonesAccountCustomNameservers(ctx context.Context, rc *ResourceContainer) ([]string, error) {
uri := fmt.Sprintf("/accounts/%s/custom_ns/availability", rc.Identifier)

res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, err
}

response := struct {
Result []string `json:"result"`
}{}

err = json.Unmarshal(res, &response)
if err != nil {
return nil, fmt.Errorf("%s: %w", errUnmarshalError, err)
}

return response.Result, nil
}

// GetAccountCustomNameserverZoneMetadata get metadata for account-level custom nameservers on a zone.
//
// API documentation: https://developers.cloudflare.com/api/operations/account-level-custom-nameservers-usage-for-a-zone-get-account-custom-nameserver-related-zone-metadata
func (api *API) GetAccountCustomNameserverZoneMetadata(ctx context.Context, rc *ResourceContainer) (CustomNameserverZoneMetadata, error) {
uri := fmt.Sprintf("/zones/%s/custom_ns", rc.Identifier)

res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
if err != nil {
return CustomNameserverZoneMetadata{}, err
}

response := &customNameserverZoneMetadata{}

err = json.Unmarshal(res, &response)
if err != nil {
return CustomNameserverZoneMetadata{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
}

return response.Result, nil
}

// UpdateAccountCustomNameserverZoneMetadata set metadata for account-level custom nameservers on a zone.
//
// API documentation: https://developers.cloudflare.com/api/operations/account-level-custom-nameservers-usage-for-a-zone-set-account-custom-nameserver-related-zone-metadata
func (api *API) UpdateAccountCustomNameserverZoneMetadata(ctx context.Context, rc *ResourceContainer, param CustomNameserverZoneMetadata) error {
uri := fmt.Sprintf("/zones/%s/custom_ns", rc.Identifier)

param.Type = ""
res, err := api.makeRequestContext(ctx, http.MethodPut, uri, param)
if err != nil {
return nil

Check failure on line 156 in account_level_custom_nameservers.go

View workflow job for this annotation

GitHub Actions / lint

error is not nil (line 154) but it returns nil (nilerr)
}

fmt.Println(string(res))

return nil
}
223 changes: 223 additions & 0 deletions account_level_custom_nameservers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
package cloudflare

import (
"context"
"fmt"
"net/http"
"testing"

"github.com/stretchr/testify/assert"
)

func TestAccountCustomNameserver_Get(t *testing.T) {
setup()
defer teardown()

handler := func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
w.Header().Set("content-type", "application/json")
fmt.Fprintf(w, `{
"success": true,
"errors": [],
"messages": [],
"result": [
{
"ns_name": "ns1.example.com",
"ns_set": 1,
"dns_records": [
{
"type": "A",
"value": "192.0.2.1"
},
{
"type": "AAAA",
"value": "2400:cb00:2049:1::ffff:ffee"
}
]
},
{
"ns_name": "ns2.example.com",
"ns_set": 1,
"dns_records": [
{
"type": "A",
"value": "192.0.2.2"
},
{
"type": "AAAA",
"value": "2400:cb00:2049:1::ffff:fffe"
}
]
}
]
}`)
}

mux.HandleFunc("/accounts/01a7362d577a6c3019a474fd6f485823/custom_ns", handler)
want := []CustomNameserverResult{
{
DNSRecords: []CustomNameserverRecord{
{
Type: "A",
Value: "192.0.2.1",
},
{
Type: "AAAA",
Value: "2400:cb00:2049:1::ffff:ffee",
},
},
NSName: "ns1.example.com",
NSSet: 1,
},
{
DNSRecords: []CustomNameserverRecord{
{
Type: "A",
Value: "192.0.2.2",
},
{
Type: "AAAA",
Value: "2400:cb00:2049:1::ffff:fffe",
},
},
NSName: "ns2.example.com",
NSSet: 1,
},
}

actual, err := client.GetAccountCustomNameservers(context.Background(), AccountIdentifier("01a7362d577a6c3019a474fd6f485823"))

if assert.NoError(t, err) {
assert.Equal(t, want, actual)
}
}

func TestAccountCustomNameserver_Create(t *testing.T) {
setup()
defer teardown()

handler := func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodPost, r.Method, "Expected method 'GET', got %s", r.Method)
w.Header().Set("content-type", "application/json")
fmt.Fprintf(w, `{
"success": true,
"errors": [],
"messages": [],
"result": {
"ns_name": "ns1.example.com",
"ns_set": 1,
"dns_records": [
{
"type": "A",
"value": "192.0.2.1"
},
{
"type": "AAAA",
"value": "2400:cb00:2049:1::ffff:ffee"
}
]
}
}`)
}

mux.HandleFunc("/accounts/01a7362d577a6c3019a474fd6f485823/custom_ns", handler)
want := CustomNameserverResult{
DNSRecords: []CustomNameserverRecord{
{
Type: "A",
Value: "192.0.2.1",
},
{
Type: "AAAA",
Value: "2400:cb00:2049:1::ffff:ffee",
},
},
NSName: "ns1.example.com",
NSSet: 1,
}

actual, err := client.CreateAccountCustomNameserver(
context.Background(),
AccountIdentifier("01a7362d577a6c3019a474fd6f485823"),
CustomNameserver{
NSName: "ns1.example.com",
NSSet: 1,
},
)

if assert.NoError(t, err) {
assert.Equal(t, want, actual)
}
}

func TestAccountCustomNameserver_GetEligibleZones(t *testing.T) {
setup()
defer teardown()

handler := func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
w.Header().Set("content-type", "application/json")
fmt.Fprintf(w, `{
"result": [
"example.com",
"example2.com",
"example3.com"
],
"success": true,
"errors": [],
"messages": []
}`)
}

mux.HandleFunc("/accounts/01a7362d577a6c3019a474fd6f485823/custom_ns/availability", handler)
want := []string{
"example.com",
"example2.com",
"example3.com",
}

actual, err := client.GetEligibleZonesAccountCustomNameservers(
context.Background(),
AccountIdentifier("01a7362d577a6c3019a474fd6f485823"),
)

if assert.NoError(t, err) {
assert.Equal(t, want, actual)
}
}

func TestAccountCustomNameserver_GetAccountCustomNameserverZoneMetadata(t *testing.T) {
setup()
defer teardown()

handler := func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
w.Header().Set("content-type", "application/json")
fmt.Fprintf(w, `{
"result": {
"type": "account",
"ns_set": "1",
"enabled": true
},
"success": true,
"errors": [],
"messages": []
}`)
}

mux.HandleFunc("/zones/023e105f4ecef8ad9ca31a8372d0c353/custom_ns", handler)
want := CustomNameserverZoneMetadata{
Type: "account",
NSSet: "1",
Enabled: true,
}

actual, err := client.GetAccountCustomNameserverZoneMetadata(
context.Background(),
ZoneIdentifier("023e105f4ecef8ad9ca31a8372d0c353"),
)

if assert.NoError(t, err) {
assert.Equal(t, want, actual)
}
}