mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2026-05-05 06:36:11 +02:00
commit
9ed9bae16d
8
Gopkg.lock
generated
8
Gopkg.lock
generated
@ -284,6 +284,12 @@
|
||||
packages = ["pbutil"]
|
||||
revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/nesv/go-dynect"
|
||||
packages = ["dynect"]
|
||||
revision = "cdd946344b54bdf7dbeac406c2f1fe93150f08ea"
|
||||
version = "v0.6.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/pkg/errors"
|
||||
packages = ["."]
|
||||
@ -616,6 +622,6 @@
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "9056760f59de670713a6534dc50e7b4ef8f14b1ad25e5a4eb0e269d2d60c4a51"
|
||||
inputs-digest = "7af57b8d195abce34060c82b92243ddba947f5d882be8f9a08b1aa827a9061fa"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
||||
@ -59,3 +59,7 @@ ignored = ["github.com/kubernetes/repo-infra/kazel"]
|
||||
[[override]]
|
||||
name = "github.com/kubernetes/repo-infra"
|
||||
revision = "2d2eb5e12b4663fc4d764b5db9daab39334d3f37"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/nesv/go-dynect"
|
||||
version = "0.6.0"
|
||||
|
||||
2
Makefile
2
Makefile
@ -46,7 +46,7 @@ SOURCES = $(shell find . -name '*.go')
|
||||
IMAGE ?= registry.opensource.zalan.do/teapot/$(BINARY)
|
||||
VERSION ?= $(shell git describe --tags --always --dirty)
|
||||
BUILD_FLAGS ?= -v
|
||||
LDFLAGS ?= -X github.com/kubernetes-incubator/external-dns/pkg/apis/externaldns.version=$(VERSION) -w -s
|
||||
LDFLAGS ?= -X github.com/kubernetes-incubator/external-dns/pkg/apis/externaldns.Version=$(VERSION) -w -s
|
||||
|
||||
build: build/$(BINARY)
|
||||
|
||||
|
||||
@ -31,6 +31,7 @@ ExternalDNS' current release is `v0.4`. This version allows you to keep selected
|
||||
* [DigitalOcean](https://www.digitalocean.com/products/networking)
|
||||
* [DNSimple](https://dnsimple.com/)
|
||||
* [Infoblox](https://www.infoblox.com/products/dns/)
|
||||
* [Dyn](https://dyn.com/dns/)
|
||||
|
||||
From this release, ExternalDNS can become aware of the records it is managing (enabled via `--registry=txt`), therefore ExternalDNS can safely manage non-empty hosted zones. We strongly encourage you to use `v0.4` with `--registry=txt` enabled and `--txt-owner-id` set to a unique value that doesn't change for the lifetime of your cluster. You might also want to run ExternalDNS in a dry run mode (`--dry-run` flag) to see the changes to be submitted to your DNS Provider API.
|
||||
|
||||
@ -47,6 +48,7 @@ The following tutorials are provided:
|
||||
* [Cloudflare](docs/tutorials/cloudflare.md)
|
||||
* [DigitalOcean](docs/tutorials/digitalocean.md)
|
||||
* [Infoblox](docs/tutorials/infoblox.md)
|
||||
* [Dyn](docs/tutorials/dyn.md)
|
||||
* Google Container Engine
|
||||
* [Using Google's Default Ingress Controller](docs/tutorials/gke.md)
|
||||
* [Using the Nginx Ingress Controller](docs/tutorials/nginx-ingress.md)
|
||||
|
||||
145
docs/tutorials/dyn.md
Normal file
145
docs/tutorials/dyn.md
Normal file
@ -0,0 +1,145 @@
|
||||
# Setting up ExternalDNS for Dyn
|
||||
|
||||
## Creating a Dyn Configuration Secret
|
||||
|
||||
For ExternalDNS to access the Dyn API, create a Kubernetes secret.
|
||||
|
||||
To create the secret:
|
||||
|
||||
```
|
||||
$ kubectl create secret generic external-dns \
|
||||
--from-literal=EXTERNAL_DNS_DYN_CUSTOMER_NAME=${DYN_CUSTOMER_NAME} \
|
||||
--from-literal=EXTERNAL_DNS_DYN_USERNAME=${DYN_USERNAME} \
|
||||
--from-literal=EXTERNAL_DNS_DYN_PASSWORD=${DYN_PASSWORD}
|
||||
```
|
||||
|
||||
The credentials are the same ones created during account registration. As best practise, you are advised to
|
||||
create an API-only user that is entitled to only the zones intended to be changed by ExternalDNS
|
||||
|
||||
## Deploy ExternalDNS
|
||||
The rest of this tutorial assumes you own `example.com` domain and your DNS provider is Dyn. Change `example.com`
|
||||
with a domain/zone that you really own.
|
||||
|
||||
In case of the dyn provider, the flag `--zone-id-filter` is mandatory as it specifies which zones to scan for records. Without it
|
||||
|
||||
|
||||
Create a deployment file called `externaldns.yaml` with the following contents:
|
||||
|
||||
```
|
||||
$ cat > externaldns.yaml <<EOF
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: external-dns
|
||||
spec:
|
||||
strategy:
|
||||
type: Recreate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: external-dns
|
||||
spec:
|
||||
containers:
|
||||
- name: external-dns
|
||||
image: registry.opensource.zalan.do/teapot/external-dns:v0.4.8
|
||||
args:
|
||||
- --source=ingress
|
||||
- --txt-prefix=_d
|
||||
- --namespace=example
|
||||
- --zone-id-filter=example.com
|
||||
- --domain-filter=example.com
|
||||
- --provider=dyn
|
||||
env:
|
||||
- name: EXTERNAL_DNS_DYN_CUSTOMER_NAME
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: external-dns
|
||||
key: EXTERNAL_DNS_DYN_CUSTOMER_NAME
|
||||
- name: EXTERNAL_DNS_DYN_USERNAME
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: external-dns
|
||||
key: EXTERNAL_DNS_DYN_USERNAME
|
||||
- name: EXTERNAL_DNS_DYN_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: external-dns
|
||||
key: EXTERNAL_DNS_DYN_PASSWORD
|
||||
EOF
|
||||
```
|
||||
|
||||
As we'll be creating an Ingress resource, you need `--txt-prefix=_d` as a CNAME cannot coexist with a TXT record. You can change the prefix to
|
||||
any valid start of a FQDN.
|
||||
|
||||
Create the deployment for ExternalDNS:
|
||||
|
||||
```
|
||||
$ kubectl create -f externaldns.yaml
|
||||
```
|
||||
|
||||
## Running a locally build version
|
||||
If you just want to test ExternalDNS in dry-run mode locally without doing the above deployment you can also do it.
|
||||
Make sure your kubectl is configured correctly . Assuming you have the sources, build and run it like so:
|
||||
|
||||
```bash
|
||||
make
|
||||
# output skipped
|
||||
|
||||
./build/external-dns \
|
||||
--provider=dyn \
|
||||
--dyn-customer-name=${DYN_CUSTOMER_NAME} \
|
||||
--dyn-username=${DYN_USERNAME} \
|
||||
--dyn-password=${DYN_PASSWORD} \
|
||||
--domain-filter=example.com \
|
||||
--zone-id-filter=example.com \
|
||||
--namespace=example \
|
||||
--log-level=debug \
|
||||
--txt-prefix=_ \
|
||||
--dry-run=true
|
||||
INFO[0000] running in dry-run mode. No changes to DNS records will be made.
|
||||
INFO[0000] Connected to cluster at https://some-k8s-cluster.example.com
|
||||
INFO[0001] Zones: [example.com]
|
||||
# output skipped
|
||||
```
|
||||
|
||||
Having `--dry-run=true` and `--log-level=debug` is a great way to see _exactly_ what DynamicDNS is doing or is about to do.
|
||||
|
||||
## Deploying an Ingress Resource
|
||||
|
||||
Create a file called 'test-ingress.yaml' with the following contents:
|
||||
|
||||
```yaml
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: test-ingress
|
||||
namespace: example
|
||||
spec:
|
||||
rules:
|
||||
- host: test-ingress.example.com
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
serviceName: my-awesome-service
|
||||
servicePort: 8080
|
||||
|
||||
```
|
||||
|
||||
As the DNS name `test-ingress.example.com` matches the filter, external-dns will create two records:
|
||||
a CNAME for test-ingress.example.com and TXT for _dtest-ingress.example.com.
|
||||
|
||||
Create the Igress:
|
||||
|
||||
```
|
||||
$ kubectl create -f test-ingress.yaml
|
||||
```
|
||||
|
||||
By default external-dns scans for changes every minute so give it some time to catch up with the
|
||||
## Verifying Dyn DNS records
|
||||
|
||||
Login to the console at https://portal.dynect.net/login/ and verify records are created
|
||||
|
||||
## Clean up
|
||||
|
||||
Login to the console at https://portal.dynect.net/login/ and delete the records created. Alternatively, just delete the sample
|
||||
Ingress resources and external-dns will delete the records.
|
||||
12
main.go
12
main.go
@ -118,6 +118,18 @@ func main() {
|
||||
DryRun: cfg.DryRun,
|
||||
},
|
||||
)
|
||||
case "dyn":
|
||||
p, err = provider.NewDynProvider(
|
||||
provider.DynConfig{
|
||||
DomainFilter: domainFilter,
|
||||
ZoneIDFilter: zoneIDFilter,
|
||||
DryRun: cfg.DryRun,
|
||||
CustomerName: cfg.DynCustomerName,
|
||||
Username: cfg.DynUsername,
|
||||
Password: cfg.DynPassword,
|
||||
AppVersion: externaldns.Version,
|
||||
},
|
||||
)
|
||||
case "inmemory":
|
||||
p, err = provider.NewInMemoryProvider(provider.InMemoryInitZones(cfg.InMemoryZones), provider.InMemoryWithDomain(domainFilter), provider.InMemoryWithLogging()), nil
|
||||
default:
|
||||
|
||||
@ -25,7 +25,8 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
version = "unknown"
|
||||
// Version is the current version of the app, generated at build time
|
||||
Version = "unknown"
|
||||
)
|
||||
|
||||
// Config is a project-wide configuration
|
||||
@ -52,6 +53,9 @@ type Config struct {
|
||||
InfobloxWapiPassword string
|
||||
InfobloxWapiVersion string
|
||||
InfobloxSSLVerify bool
|
||||
DynCustomerName string
|
||||
DynUsername string
|
||||
DynPassword string
|
||||
InMemoryZones []string
|
||||
Policy string
|
||||
Registry string
|
||||
@ -117,7 +121,7 @@ func allLogLevelsAsStrings() []string {
|
||||
// ParseFlags adds and parses flags from command line
|
||||
func (cfg *Config) ParseFlags(args []string) error {
|
||||
app := kingpin.New("external-dns", "ExternalDNS synchronizes exposed Kubernetes Services and Ingresses with DNS providers.\n\nNote that all flags may be replaced with env vars - `--flag` -> `EXTERNAL_DNS_FLAG=1` or `--flag value` -> `EXTERNAL_DNS_FLAG=value`")
|
||||
app.Version(version)
|
||||
app.Version(Version)
|
||||
app.DefaultEnvars()
|
||||
|
||||
// Flags related to Kubernetes
|
||||
@ -133,7 +137,7 @@ func (cfg *Config) ParseFlags(args []string) error {
|
||||
app.Flag("publish-internal-services", "Allow external-dns to publish DNS records for ClusterIP services (optional)").BoolVar(&cfg.PublishInternal)
|
||||
|
||||
// Flags related to providers
|
||||
app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, google, azure, cloudflare, digitalocean, dnsimple, infoblox, inmemory)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "google", "azure", "cloudflare", "digitalocean", "dnsimple", "infoblox", "inmemory")
|
||||
app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, google, azure, cloudflare, digitalocean, dnsimple, infoblox, dyn, inmemory)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "google", "azure", "cloudflare", "digitalocean", "dnsimple", "infoblox", "dyn", "inmemory")
|
||||
app.Flag("domain-filter", "Limit possible target zones by a domain suffix; specify multiple times for multiple domains (optional)").Default("").StringsVar(&cfg.DomainFilter)
|
||||
app.Flag("zone-id-filter", "Filter target zones by hosted zone id; specify multiple times for multiple zones (optional)").Default("").StringsVar(&cfg.ZoneIDFilter)
|
||||
app.Flag("google-project", "When using the Google provider, specify the Google project (required when --provider=google)").Default(defaultConfig.GoogleProject).StringVar(&cfg.GoogleProject)
|
||||
@ -147,6 +151,9 @@ func (cfg *Config) ParseFlags(args []string) error {
|
||||
app.Flag("infoblox-wapi-password", "When using the Infoblox provider, specify the WAPI password (required when --provider=infoblox)").Default(defaultConfig.InfobloxWapiPassword).StringVar(&cfg.InfobloxWapiPassword)
|
||||
app.Flag("infoblox-wapi-version", "When using the Infoblox provider, specify the WAPI version (default: 2.3.1)").Default(defaultConfig.InfobloxWapiVersion).StringVar(&cfg.InfobloxWapiVersion)
|
||||
app.Flag("infoblox-ssl-verify", "When using the Infoblox provider, specify whether to verify the SSL certificate (default: true, disable with --no-infoblox-ssl-verify)").Default(strconv.FormatBool(defaultConfig.InfobloxSSLVerify)).BoolVar(&cfg.InfobloxSSLVerify)
|
||||
app.Flag("dyn-customer-name", "When using the Dyn provider, specify the Customer Name").Default("").StringVar(&cfg.DynCustomerName)
|
||||
app.Flag("dyn-username", "When using the Dyn provider, specify the Username").Default("").StringVar(&cfg.DynUsername)
|
||||
app.Flag("dyn-password", "When using the Dyn provider, specify the pasword").Default("").StringVar(&cfg.DynPassword)
|
||||
app.Flag("inmemory-zone", "Provide a list of pre-configured zones for the inmemory provider; specify multiple times for multiple zones (optional)").Default("").StringsVar(&cfg.InMemoryZones)
|
||||
|
||||
// Flags related to policies
|
||||
|
||||
564
provider/dyn.go
Normal file
564
provider/dyn.go
Normal file
@ -0,0 +1,564 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package provider
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/nesv/go-dynect/dynect"
|
||||
|
||||
"github.com/kubernetes-incubator/external-dns/endpoint"
|
||||
"github.com/kubernetes-incubator/external-dns/plan"
|
||||
)
|
||||
|
||||
const (
|
||||
// 10 minutes default timeout if not configured using flags
|
||||
dynDefaultTTL = 600
|
||||
// can store 20000 entries globally, that's about 4MB of memory
|
||||
// may be made configurable in the future but 20K records seems like enough for a few zones
|
||||
cacheMaxSize = 20000
|
||||
|
||||
// this prefix must be stripped from resource links before feeding them to dynect.Client.Do()
|
||||
restAPIPrefix = "/REST/"
|
||||
)
|
||||
|
||||
// A simple non-thread-safe cache with TTL. The TTL of the records is used here to
|
||||
// This cache is used to save on requests to DynAPI
|
||||
type cache struct {
|
||||
contents map[string]*entry
|
||||
}
|
||||
|
||||
type entry struct {
|
||||
expires int64
|
||||
ep *endpoint.Endpoint
|
||||
}
|
||||
|
||||
func (c *cache) Put(link string, ep *endpoint.Endpoint) {
|
||||
// flush the whole cache on overflow
|
||||
if len(c.contents) >= cacheMaxSize {
|
||||
c.contents = make(map[string]*entry)
|
||||
}
|
||||
|
||||
c.contents[link] = &entry{
|
||||
ep: ep,
|
||||
expires: int64(time.Now().Unix()) + int64(ep.RecordTTL),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cache) Get(link string) *endpoint.Endpoint {
|
||||
result, ok := c.contents[link]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
now := int64(time.Now().Unix())
|
||||
|
||||
if result.expires < now {
|
||||
delete(c.contents, link)
|
||||
return nil
|
||||
}
|
||||
|
||||
return result.ep
|
||||
}
|
||||
|
||||
// DynConfig hold connection parameters to dyn.com and interanl state
|
||||
type DynConfig struct {
|
||||
DomainFilter DomainFilter
|
||||
ZoneIDFilter ZoneIDFilter
|
||||
DryRun bool
|
||||
CustomerName string
|
||||
Username string
|
||||
Password string
|
||||
AppVersion string
|
||||
DynVersion string
|
||||
}
|
||||
|
||||
// DynProvider is the actual interface impl.
|
||||
type dynProviderState struct {
|
||||
DynConfig
|
||||
Cache *cache
|
||||
}
|
||||
|
||||
// ZoneChange is missing from dynect: https://help.dyn.com/get-zone-changeset-api/
|
||||
type ZoneChange struct {
|
||||
ID int `json:"id"`
|
||||
UserID int `json:"user_id"`
|
||||
Zone string `json:"zone"`
|
||||
FQDN string `json:"FQDN"`
|
||||
Serial int `json:"serial"`
|
||||
TTL int `json:"ttl"`
|
||||
Type string `json:"rdata_type"`
|
||||
RData dynect.DataBlock `json:"rdata"`
|
||||
}
|
||||
|
||||
// ZoneChangesResponse is missing from dynect: https://help.dyn.com/get-zone-changeset-api/
|
||||
type ZoneChangesResponse struct {
|
||||
dynect.ResponseBlock
|
||||
Data []ZoneChange `json:"data"`
|
||||
}
|
||||
|
||||
// ZonePublishRequest is missing from dynect but the notes field is a nice place to let
|
||||
// external-dns report some internal info during commit
|
||||
type ZonePublishRequest struct {
|
||||
Publish bool `json:"publish"`
|
||||
Notes string `json:"notes"`
|
||||
}
|
||||
|
||||
// ZonePublisResponse holds the status after publish
|
||||
type ZonePublisResponse struct {
|
||||
dynect.ResponseBlock
|
||||
Data map[string]interface{} `json:"data"`
|
||||
}
|
||||
|
||||
// NewDynProvider initializes a new Dyn Provider.
|
||||
func NewDynProvider(config DynConfig) (Provider, error) {
|
||||
return &dynProviderState{
|
||||
DynConfig: config,
|
||||
Cache: &cache{
|
||||
contents: make(map[string]*entry),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// filterAndFixLinks removes from `links` all the records we don't care about
|
||||
// and strops the /REST/ prefix
|
||||
func filterAndFixLinks(links []string, filter DomainFilter) []string {
|
||||
var result []string
|
||||
for _, link := range links {
|
||||
|
||||
link = strings.TrimPrefix(link, restAPIPrefix)
|
||||
|
||||
// covert resource link to just the FQDN so we can filter on it
|
||||
domain := link[0:strings.LastIndexByte(link, '/')]
|
||||
domain = domain[strings.LastIndexByte(domain, '/')+1:]
|
||||
|
||||
// simply ignore all record types we don't care about
|
||||
if !strings.HasPrefix(link, endpoint.RecordTypeA) &&
|
||||
!strings.HasPrefix(link, endpoint.RecordTypeCNAME) &&
|
||||
!strings.HasPrefix(link, endpoint.RecordTypeTXT) {
|
||||
continue
|
||||
}
|
||||
|
||||
if filter.Match(domain) {
|
||||
result = append(result, link)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func fixMissingTTL(ttl endpoint.TTL) string {
|
||||
i := dynDefaultTTL
|
||||
if ttl.IsConfigured() {
|
||||
i = int(ttl)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%d", i)
|
||||
}
|
||||
|
||||
// merge produces a singe list of records that can be used as a replacement.
|
||||
// Dyn allows to replace all records with a single call
|
||||
// Invariant: the result contains only elements from the updateNew parameter
|
||||
func merge(updateOld, updateNew []*endpoint.Endpoint) []*endpoint.Endpoint {
|
||||
findMatch := func(template *endpoint.Endpoint) *endpoint.Endpoint {
|
||||
for _, new := range updateNew {
|
||||
if template.DNSName == new.DNSName &&
|
||||
template.RecordType == new.RecordType {
|
||||
return new
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var result []*endpoint.Endpoint
|
||||
for _, old := range updateOld {
|
||||
matchingNew := findMatch(old)
|
||||
if matchingNew == nil {
|
||||
// no match, shouldn't happen
|
||||
continue
|
||||
}
|
||||
|
||||
if matchingNew.Target != old.Target {
|
||||
// new target: always update, TTL will be overwritten too if necessary
|
||||
result = append(result, matchingNew)
|
||||
continue
|
||||
}
|
||||
|
||||
if matchingNew.RecordTTL != 0 && matchingNew.RecordTTL != old.RecordTTL {
|
||||
// same target, but new non-zero TTL set in k8s, must update
|
||||
// probably would happen only if there is a bug in the code calling the provider
|
||||
result = append(result, matchingNew)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// extractTarget populates the correct field given a record type.
|
||||
// See dynect.DataBlock comments for details. Empty response means nothing
|
||||
// was populated - basically an error
|
||||
func extractTarget(recType string, data *dynect.DataBlock) string {
|
||||
result := ""
|
||||
if recType == endpoint.RecordTypeA {
|
||||
result = data.Address
|
||||
}
|
||||
|
||||
if recType == endpoint.RecordTypeCNAME {
|
||||
result = data.CName
|
||||
result = strings.TrimSuffix(result, ".")
|
||||
}
|
||||
|
||||
if recType == endpoint.RecordTypeTXT {
|
||||
result = data.TxtData
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// recordLinkToEndpoint makes an Endpoint given a resource link optinally making a remote call if a cached entry is expired
|
||||
func (d *dynProviderState) recordLinkToEndpoint(client *dynect.Client, recordLink string) (*endpoint.Endpoint, error) {
|
||||
result := d.Cache.Get(recordLink)
|
||||
if result != nil {
|
||||
log.Infof("Using cached endpoint for %s: %+v", recordLink, result)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
rec := dynect.RecordResponse{}
|
||||
err := client.Do("GET", recordLink, nil, &rec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// ignore all records but the types supported by external-
|
||||
target := extractTarget(rec.Data.RecordType, &rec.Data.RData)
|
||||
if target == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
result = &endpoint.Endpoint{
|
||||
DNSName: rec.Data.FQDN,
|
||||
RecordTTL: endpoint.TTL(rec.Data.TTL),
|
||||
RecordType: rec.Data.RecordType,
|
||||
Target: target,
|
||||
}
|
||||
|
||||
log.Debugf("Fetched new endpoint for %s: %+v", recordLink, result)
|
||||
d.Cache.Put(recordLink, result)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func errorOrValue(err error, value interface{}) interface{} {
|
||||
if err == nil {
|
||||
return value
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// endpointToRecord puts the Target of an Endpoint in the correct field of DataBlock.
|
||||
// See DataBlock comments for more info
|
||||
func endpointToRecord(ep *endpoint.Endpoint) *dynect.DataBlock {
|
||||
result := dynect.DataBlock{}
|
||||
|
||||
if ep.RecordType == endpoint.RecordTypeA {
|
||||
result.Address = ep.Target
|
||||
} else if ep.RecordType == endpoint.RecordTypeCNAME {
|
||||
result.CName = ep.Target
|
||||
} else if ep.RecordType == endpoint.RecordTypeTXT {
|
||||
result.TxtData = ep.Target
|
||||
}
|
||||
|
||||
return &result
|
||||
}
|
||||
|
||||
// fetchAllRecordLinksInZone list all records in a zone with a single call. Records not matched by the
|
||||
// DomainFilter are ignored. The response is a list of links that can be fed to dynect.Client.Do()
|
||||
// directly
|
||||
func (d *dynProviderState) fetchAllRecordLinksInZone(client *dynect.Client, zone string) ([]string, error) {
|
||||
var allRecords dynect.AllRecordsResponse
|
||||
err := client.Do("GET", fmt.Sprintf("AllRecord/%s/", zone), nil, &allRecords)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return filterAndFixLinks(allRecords.Data, d.DomainFilter), nil
|
||||
}
|
||||
|
||||
// buildLinkToRecord build a resource link. The symmetry of the dyn API is used to save
|
||||
// switch-case boilerplate.
|
||||
// Empty response means the endpoint is not mappable to a records link: either because the fqdn
|
||||
// is not matched by the domainFilter or it is in the wrong zone
|
||||
func (d *dynProviderState) buildLinkToRecord(ep *endpoint.Endpoint) string {
|
||||
if ep == nil {
|
||||
return ""
|
||||
}
|
||||
var matchingZone = ""
|
||||
for _, zone := range d.ZoneIDFilter.zoneIDs {
|
||||
if strings.HasSuffix(ep.DNSName, zone) {
|
||||
matchingZone = zone
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if matchingZone == "" {
|
||||
fmt.Printf("no zone")
|
||||
// no matching zone, ignore
|
||||
return ""
|
||||
}
|
||||
|
||||
if !d.DomainFilter.Match(ep.DNSName) {
|
||||
// no matching domain, ignore
|
||||
return ""
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%sRecord/%s/%s/", ep.RecordType, matchingZone, ep.DNSName)
|
||||
}
|
||||
|
||||
// create a dynect client and performs login. You need to clean it up.
|
||||
// This method also stores the DynAPI version.
|
||||
// Don't user the dynect.Client.Login()
|
||||
func (d *dynProviderState) login() (*dynect.Client, error) {
|
||||
client := dynect.NewClient(d.CustomerName)
|
||||
|
||||
var req = dynect.LoginBlock{
|
||||
Username: d.Username,
|
||||
Password: d.Password,
|
||||
CustomerName: d.CustomerName}
|
||||
|
||||
var resp dynect.LoginResponse
|
||||
|
||||
err := client.Do("POST", "Session", req, &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client.Token = resp.Data.Token
|
||||
|
||||
// this is the only change from the original
|
||||
d.DynVersion = resp.Data.Version
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// the zones we are allowed to touch. Currently only exact matches are considered, not all
|
||||
// zones with the given suffix
|
||||
func (d *dynProviderState) zones(client *dynect.Client) []string {
|
||||
return d.ZoneIDFilter.zoneIDs
|
||||
}
|
||||
|
||||
func (d *dynProviderState) buildRecordRequest(ep *endpoint.Endpoint) (string, *dynect.RecordRequest) {
|
||||
link := d.buildLinkToRecord(ep)
|
||||
if link == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
record := dynect.RecordRequest{
|
||||
TTL: fixMissingTTL(ep.RecordTTL),
|
||||
RData: *endpointToRecord(ep),
|
||||
}
|
||||
return link, &record
|
||||
}
|
||||
|
||||
// deleteRecord deletes all existing records (CNAME, TXT, A) for the given Endpoint.DNSName with 1 API call
|
||||
func (d *dynProviderState) deleteRecord(client *dynect.Client, ep *endpoint.Endpoint) error {
|
||||
link := d.buildLinkToRecord(ep)
|
||||
if link == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
response := dynect.RecordResponse{}
|
||||
err := client.Do("DELETE", link, nil, &response)
|
||||
log.Debugf("Deleting record %s: %+v,", link, errorOrValue(err, &response))
|
||||
return err
|
||||
}
|
||||
|
||||
// replaceRecord replaces all existing records pf the given type for the Endpoint.DNSName with 1 API call
|
||||
func (d *dynProviderState) replaceRecord(client *dynect.Client, ep *endpoint.Endpoint) error {
|
||||
link, record := d.buildRecordRequest(ep)
|
||||
if link == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
response := dynect.RecordResponse{}
|
||||
err := client.Do("PUT", link, record, &response)
|
||||
log.Debugf("Replacing record %s: %+v,", link, errorOrValue(err, &response))
|
||||
return err
|
||||
}
|
||||
|
||||
// createRecord creates a single record with 1 API call
|
||||
func (d *dynProviderState) createRecord(client *dynect.Client, ep *endpoint.Endpoint) error {
|
||||
link, record := d.buildRecordRequest(ep)
|
||||
if link == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
response := dynect.RecordResponse{}
|
||||
err := client.Do("POST", link, record, &response)
|
||||
log.Debugf("Creating record %s: %+v,", link, errorOrValue(err, &response))
|
||||
return err
|
||||
}
|
||||
|
||||
// commit commits all pending changes. It will always attempt to commit, if there are no
|
||||
func (d *dynProviderState) commit(client *dynect.Client) error {
|
||||
errs := []error{}
|
||||
|
||||
for _, zone := range d.zones(client) {
|
||||
// extra call if in debug mode to fetch pending changes
|
||||
if log.GetLevel() >= log.DebugLevel {
|
||||
response := ZoneChangesResponse{}
|
||||
err := client.Do("GET", fmt.Sprintf("ZoneChanges/%s/", zone), nil, &response)
|
||||
log.Debugf("Pending changes for zone %s: %+v", zone, errorOrValue(err, &response))
|
||||
}
|
||||
|
||||
h, err := os.Hostname()
|
||||
if err != nil {
|
||||
h = "unknown-host"
|
||||
}
|
||||
notes := fmt.Sprintf("Change by external-dns@%s, DynAPI@%s, %s on %s",
|
||||
d.AppVersion,
|
||||
d.DynVersion,
|
||||
time.Now().Format(time.RFC3339),
|
||||
h,
|
||||
)
|
||||
|
||||
zonePublish := ZonePublishRequest{
|
||||
Publish: true,
|
||||
Notes: notes,
|
||||
}
|
||||
|
||||
response := ZonePublisResponse{}
|
||||
err = client.Do("PUT", fmt.Sprintf("Zone/%s/", zone), &zonePublish, &response)
|
||||
log.Infof("Commiting changes for zone %s: %+v", zone, errorOrValue(err, &response))
|
||||
}
|
||||
|
||||
switch len(errs) {
|
||||
case 0:
|
||||
return nil
|
||||
case 1:
|
||||
return errs[0]
|
||||
default:
|
||||
return fmt.Errorf("Multiple errors committing: %+v", errs)
|
||||
}
|
||||
}
|
||||
|
||||
// Records makes on average C + 2*Z requests (Z = number of zones): 1 login + 1 fetchAllRecords
|
||||
// A cache is used to avoid querying for every single record found. C is proportional to the number
|
||||
// of expired/changed records
|
||||
func (d *dynProviderState) Records() ([]*endpoint.Endpoint, error) {
|
||||
client, err := d.login()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer client.Logout()
|
||||
|
||||
log.Debugf("Using DynAPI@%s", d.DynVersion)
|
||||
|
||||
var result []*endpoint.Endpoint
|
||||
|
||||
zones := d.zones(client)
|
||||
log.Infof("Zones found: %+v", zones)
|
||||
for _, zone := range zones {
|
||||
recordLinks, err := d.fetchAllRecordLinksInZone(client, zone)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Infof("Relevant records found in zone %s: %+v", zone, recordLinks)
|
||||
for _, link := range recordLinks {
|
||||
ep, err := d.recordLinkToEndpoint(client, link)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ep != nil {
|
||||
result = append(result, ep)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// this method does C + 2*Z requests: C=total number of changes, Z = number of
|
||||
// affected zones (1 login + 1 commit)
|
||||
func (d *dynProviderState) ApplyChanges(changes *plan.Changes) error {
|
||||
log.Debugf("Processing chages: %+v", changes)
|
||||
|
||||
if d.DryRun {
|
||||
log.Infof("Will NOT delete these records: %+v", changes.Delete)
|
||||
log.Infof("Will NOT create these records: %+v", changes.Create)
|
||||
log.Infof("Will NOT update these records: %+v", merge(changes.UpdateOld, changes.UpdateNew))
|
||||
return nil
|
||||
}
|
||||
|
||||
client, err := d.login()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Logout()
|
||||
|
||||
var errs []error
|
||||
|
||||
needsCommit := false
|
||||
|
||||
for _, ep := range changes.Delete {
|
||||
err := d.deleteRecord(client, ep)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
} else {
|
||||
needsCommit = true
|
||||
}
|
||||
}
|
||||
|
||||
for _, ep := range changes.Create {
|
||||
err := d.createRecord(client, ep)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
} else {
|
||||
needsCommit = true
|
||||
}
|
||||
}
|
||||
|
||||
updates := merge(changes.UpdateOld, changes.UpdateNew)
|
||||
log.Debugf("Updates after merging: %+v", updates)
|
||||
for _, ep := range updates {
|
||||
err := d.replaceRecord(client, ep)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
} else {
|
||||
needsCommit = true
|
||||
}
|
||||
}
|
||||
|
||||
switch len(errs) {
|
||||
case 0:
|
||||
case 1:
|
||||
return errs[0]
|
||||
default:
|
||||
return fmt.Errorf("Multiple errors committing: %+v", errs)
|
||||
}
|
||||
|
||||
if needsCommit {
|
||||
return d.commit(client)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
298
provider/dyn_test.go
Normal file
298
provider/dyn_test.go
Normal file
@ -0,0 +1,298 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package provider
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/nesv/go-dynect/dynect"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/kubernetes-incubator/external-dns/endpoint"
|
||||
)
|
||||
|
||||
func TestDynMerge_NoUpdateOnTTL0Changes(t *testing.T) {
|
||||
updateOld := []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "name1",
|
||||
Target: "target1",
|
||||
RecordTTL: endpoint.TTL(1),
|
||||
RecordType: endpoint.RecordTypeA,
|
||||
},
|
||||
{
|
||||
DNSName: "name2",
|
||||
Target: "target2",
|
||||
RecordTTL: endpoint.TTL(1),
|
||||
RecordType: endpoint.RecordTypeA,
|
||||
},
|
||||
}
|
||||
|
||||
updateNew := []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "name1",
|
||||
Target: "target1",
|
||||
RecordTTL: endpoint.TTL(0),
|
||||
RecordType: endpoint.RecordTypeCNAME,
|
||||
},
|
||||
{
|
||||
DNSName: "name2",
|
||||
Target: "target2",
|
||||
RecordTTL: endpoint.TTL(0),
|
||||
RecordType: endpoint.RecordTypeCNAME,
|
||||
},
|
||||
}
|
||||
|
||||
assert.Equal(t, 0, len(merge(updateOld, updateNew)))
|
||||
}
|
||||
|
||||
func TestDynMerge_UpdateOnTTLChanges(t *testing.T) {
|
||||
updateOld := []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "name1",
|
||||
Target: "target1",
|
||||
RecordTTL: endpoint.TTL(1),
|
||||
RecordType: endpoint.RecordTypeCNAME,
|
||||
},
|
||||
{
|
||||
DNSName: "name2",
|
||||
Target: "target2",
|
||||
RecordTTL: endpoint.TTL(1),
|
||||
RecordType: endpoint.RecordTypeCNAME,
|
||||
},
|
||||
}
|
||||
|
||||
updateNew := []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "name1",
|
||||
Target: "target1",
|
||||
RecordTTL: endpoint.TTL(77),
|
||||
RecordType: endpoint.RecordTypeCNAME,
|
||||
},
|
||||
{
|
||||
DNSName: "name2",
|
||||
Target: "target2",
|
||||
RecordTTL: endpoint.TTL(10),
|
||||
RecordType: endpoint.RecordTypeCNAME,
|
||||
},
|
||||
}
|
||||
|
||||
merged := merge(updateOld, updateNew)
|
||||
assert.Equal(t, 2, len(merged))
|
||||
assert.Equal(t, "name1", merged[0].DNSName)
|
||||
}
|
||||
|
||||
func TestDynMerge_AlwaysUpdateTarget(t *testing.T) {
|
||||
updateOld := []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "name1",
|
||||
Target: "target1",
|
||||
RecordTTL: endpoint.TTL(1),
|
||||
RecordType: endpoint.RecordTypeCNAME,
|
||||
},
|
||||
{
|
||||
DNSName: "name2",
|
||||
Target: "target2",
|
||||
RecordTTL: endpoint.TTL(1),
|
||||
RecordType: endpoint.RecordTypeCNAME,
|
||||
},
|
||||
}
|
||||
|
||||
updateNew := []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "name1",
|
||||
Target: "target1-changed",
|
||||
RecordTTL: endpoint.TTL(0),
|
||||
RecordType: endpoint.RecordTypeCNAME,
|
||||
},
|
||||
{
|
||||
DNSName: "name2",
|
||||
Target: "target2",
|
||||
RecordTTL: endpoint.TTL(0),
|
||||
RecordType: endpoint.RecordTypeCNAME,
|
||||
},
|
||||
}
|
||||
|
||||
merged := merge(updateOld, updateNew)
|
||||
assert.Equal(t, 1, len(merged))
|
||||
assert.Equal(t, "target1-changed", merged[0].Target)
|
||||
}
|
||||
|
||||
func TestDynMerge_NoUpdateIfTTLUnchanged(t *testing.T) {
|
||||
updateOld := []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "name1",
|
||||
Target: "target1",
|
||||
RecordTTL: endpoint.TTL(55),
|
||||
RecordType: endpoint.RecordTypeCNAME,
|
||||
},
|
||||
{
|
||||
DNSName: "name2",
|
||||
Target: "target2",
|
||||
RecordTTL: endpoint.TTL(55),
|
||||
RecordType: endpoint.RecordTypeCNAME,
|
||||
},
|
||||
}
|
||||
|
||||
updateNew := []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "name1",
|
||||
Target: "target1",
|
||||
RecordTTL: endpoint.TTL(55),
|
||||
RecordType: endpoint.RecordTypeCNAME,
|
||||
},
|
||||
{
|
||||
DNSName: "name2",
|
||||
Target: "target2",
|
||||
RecordTTL: endpoint.TTL(55),
|
||||
RecordType: endpoint.RecordTypeCNAME,
|
||||
},
|
||||
}
|
||||
|
||||
merged := merge(updateOld, updateNew)
|
||||
assert.Equal(t, 0, len(merged))
|
||||
}
|
||||
|
||||
func TestDyn_extractTarget(t *testing.T) {
|
||||
tests := []struct {
|
||||
recordType string
|
||||
block *dynect.DataBlock
|
||||
target string
|
||||
}{
|
||||
{"A", &dynect.DataBlock{Address: "address"}, "address"},
|
||||
{"CNAME", &dynect.DataBlock{CName: "name."}, "name"}, // note trailing dot is trimmed for CNAMEs
|
||||
{"TXT", &dynect.DataBlock{TxtData: "text."}, "text."},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
assert.Equal(t, tc.target, extractTarget(tc.recordType, tc.block))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDyn_endpointToRecord(t *testing.T) {
|
||||
tests := []struct {
|
||||
ep *endpoint.Endpoint
|
||||
extractor func(*dynect.DataBlock) string
|
||||
}{
|
||||
{endpoint.NewEndpoint("address", "the-target", "A"), func(b *dynect.DataBlock) string { return b.Address }},
|
||||
{endpoint.NewEndpoint("cname", "the-target", "CNAME"), func(b *dynect.DataBlock) string { return b.CName }},
|
||||
{endpoint.NewEndpoint("text", "the-target", "TXT"), func(b *dynect.DataBlock) string { return b.TxtData }},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
block := endpointToRecord(tc.ep)
|
||||
assert.Equal(t, "the-target", tc.extractor(block))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDyn_buildLinkToRecord(t *testing.T) {
|
||||
provider := &dynProviderState{
|
||||
DynConfig: DynConfig{
|
||||
ZoneIDFilter: NewZoneIDFilter([]string{"example.com"}),
|
||||
DomainFilter: NewDomainFilter([]string{"the-target.example.com"}),
|
||||
},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
ep *endpoint.Endpoint
|
||||
link string
|
||||
}{
|
||||
{endpoint.NewEndpoint("sub.the-target.example.com", "address", "A"), "ARecord/example.com/sub.the-target.example.com/"},
|
||||
{endpoint.NewEndpoint("the-target.example.com", "cname", "CNAME"), "CNAMERecord/example.com/the-target.example.com/"},
|
||||
{endpoint.NewEndpoint("the-target.example.com", "text", "TXT"), "TXTRecord/example.com/the-target.example.com/"},
|
||||
{endpoint.NewEndpoint("the-target.google.com", "text", "TXT"), ""},
|
||||
{endpoint.NewEndpoint("mail.example.com", "text", "TXT"), ""},
|
||||
{nil, ""},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
assert.Equal(t, tc.link, provider.buildLinkToRecord(tc.ep))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDyn_errorOrValue(t *testing.T) {
|
||||
e := errors.New("an error")
|
||||
val := "value"
|
||||
assert.Equal(t, e, errorOrValue(e, val))
|
||||
assert.Equal(t, val, errorOrValue(nil, val))
|
||||
}
|
||||
|
||||
func TestDyn_filterAndFixLinks(t *testing.T) {
|
||||
links := []string{
|
||||
"/REST/ARecord/example.com/the-target.example.com/",
|
||||
"/REST/ARecord/example.com/the-target.google.com/",
|
||||
"/REST/TXTRecord/example.com/the-target.example.com/",
|
||||
"/REST/TXTRecord/example.com/the-target.google.com/",
|
||||
"/REST/CNAMERecord/example.com/the-target.google.com/",
|
||||
"/REST/CNAMERecord/example.com/the-target.example.com/",
|
||||
"/REST/NSRecord/example.com/the-target.google.com/",
|
||||
"/REST/NSRecord/example.com/the-target.example.com/",
|
||||
}
|
||||
filter := NewDomainFilter([]string{"example.com"})
|
||||
result := filterAndFixLinks(links, filter)
|
||||
|
||||
// should skip non-example.com records and NS records too
|
||||
assert.Equal(t, 3, len(result))
|
||||
assert.Equal(t, "ARecord/example.com/the-target.example.com/", result[0])
|
||||
assert.Equal(t, "TXTRecord/example.com/the-target.example.com/", result[1])
|
||||
assert.Equal(t, "CNAMERecord/example.com/the-target.example.com/", result[2])
|
||||
}
|
||||
|
||||
func TestDyn_fixMissingTTL(t *testing.T) {
|
||||
assert.Equal(t, fmt.Sprintf("%v", dynDefaultTTL), fixMissingTTL(endpoint.TTL(0)))
|
||||
|
||||
// nothing to fix
|
||||
assert.Equal(t, "111", fixMissingTTL(endpoint.TTL(111)))
|
||||
}
|
||||
|
||||
func TestDyn_cachePut(t *testing.T) {
|
||||
c := cache{
|
||||
contents: make(map[string]*entry),
|
||||
}
|
||||
|
||||
c.Put("link", &endpoint.Endpoint{
|
||||
DNSName: "name",
|
||||
Target: "target",
|
||||
RecordTTL: endpoint.TTL(10000),
|
||||
RecordType: "A",
|
||||
})
|
||||
|
||||
found := c.Get("link")
|
||||
assert.NotNil(t, found)
|
||||
}
|
||||
|
||||
func TestDyn_cachePutExpired(t *testing.T) {
|
||||
c := cache{
|
||||
contents: make(map[string]*entry),
|
||||
}
|
||||
|
||||
c.Put("link", &endpoint.Endpoint{
|
||||
DNSName: "name",
|
||||
Target: "target",
|
||||
RecordTTL: endpoint.TTL(0),
|
||||
RecordType: "A",
|
||||
})
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
found := c.Get("link")
|
||||
assert.Nil(t, found)
|
||||
|
||||
assert.Nil(t, c.Get("no-such-records"))
|
||||
}
|
||||
102
vendor/github.com/nesv/go-dynect/CHANGELOG.md
generated
vendored
Normal file
102
vendor/github.com/nesv/go-dynect/CHANGELOG.md
generated
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
# Changelog
|
||||
|
||||
## Tue Jan 9 2018 - 0.6.0
|
||||
|
||||
- use VCR and fixtures for tests
|
||||
- test ConvenientClient operations
|
||||
- add support for zone create/delete operations
|
||||
|
||||
## Wed Aug 23 2017 - 0.5.3
|
||||
|
||||
- BUG-FIX: don't prepend dot for record with FQDN of Zone name
|
||||
|
||||
## Fri Aug 18 2017 - 0.5.2
|
||||
|
||||
- Handle errors reading response body in verbose mode (PR#20)
|
||||
|
||||
## Mon Jun 5 2017 - 0.5.1
|
||||
|
||||
- Update CHANGELOG
|
||||
|
||||
## Mon Jun 5 2017 - 0.5.0
|
||||
|
||||
- Add support for ALIAS, MX, NS, and SOA records, to the ConvenientClient
|
||||
(PR#17)
|
||||
|
||||
## Mon Jun 5 2017 - 0.4.1
|
||||
|
||||
- Handle rate limit errors
|
||||
|
||||
## Mon Jun 5 2017 - 0.4.0
|
||||
|
||||
- Fix nil-transport issue with the ConvenientClinent (PR#16)
|
||||
|
||||
## Fri Apr 21 2017 - 0.3.1
|
||||
|
||||
- Proxy support configurable with HTTP(S)_PROXY env variables
|
||||
- BACKPORT: Handle rate limit errors
|
||||
|
||||
## Thu Sep 22 2016 - 0.3.0
|
||||
|
||||
- Verbose mode prints full url
|
||||
- Handle Job redirections
|
||||
- Support for unknown Content-Length
|
||||
- Addition of ConvenientClient
|
||||
- Support for Traffic Director (DSF) service
|
||||
|
||||
- BUGFIX: Don't override global log prefix
|
||||
|
||||
## Fri Nov 15 2013 - 0.2.0
|
||||
|
||||
- Fixed some struct field types
|
||||
- Modified some of the tests
|
||||
- Felt like it deserved a minor version bump
|
||||
|
||||
## Thu Nov 14 2013 - 0.1.9
|
||||
|
||||
- If verbosity is enabled, any unmarshaling errors will print the complete
|
||||
response body out, via logger
|
||||
|
||||
## Thu Nov 14 2013 - 0.1.8
|
||||
|
||||
## Wed Nov 13 2013 - 0.1.7
|
||||
|
||||
- Fixed a bug where empty request bodies would result in the API service
|
||||
responding with a 400 Bad Request
|
||||
- Added some proper tests
|
||||
|
||||
## Wed Nov 13 2013 - 0.1.6
|
||||
|
||||
- Added a "verbose" mode to the client
|
||||
|
||||
## Tue Nov 12 2013 - 0.1.5
|
||||
|
||||
- Bug fixes
|
||||
- Logic bug in the *Client.Do() function, where it would not allow the
|
||||
POST /Session call if the client was logged out (POST /Session is used for
|
||||
logging in)
|
||||
|
||||
## Tue Nov 12 2013 - 0.1.4
|
||||
|
||||
- Includes 0.1.3
|
||||
- Bug fixes
|
||||
- Testing laid out, but there is not much there, as of right now
|
||||
|
||||
## Tue Nov 12 2013 - 0.1.2
|
||||
|
||||
- Bug fixes
|
||||
|
||||
## Tue Nov 12 2013 - 0.1.1
|
||||
|
||||
- Added structs for zone responses
|
||||
|
||||
## Tue Nov 12 2013 - 0.1.0
|
||||
|
||||
- Initial release
|
||||
- The base client is complete; it will allow you to establish a session,
|
||||
terminate a session, and issue requests to the DynECT REST API endpoints
|
||||
- TODO
|
||||
- Structs for marshaling and unmarshaling requests and responses still need
|
||||
to be done, as the current set of provided struct is all that is needed
|
||||
to be able to log in and create a session
|
||||
- More structs will be added on an "as I need them" basis
|
||||
21
vendor/github.com/nesv/go-dynect/LICENSE.md
generated
vendored
Normal file
21
vendor/github.com/nesv/go-dynect/LICENSE.md
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Nick Saika
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
43
vendor/github.com/nesv/go-dynect/README.md
generated
vendored
Normal file
43
vendor/github.com/nesv/go-dynect/README.md
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
# go-dynect
|
||||
|
||||
A DynECT REST client for the Go programming language.
|
||||
|
||||
## Installation
|
||||
|
||||
$ go get github.com/nesv/go-dynect/dynect
|
||||
|
||||
## Usage
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/nesv/go-dynect/dynect"
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
client := dynect.NewClient("my-dyn-customer-name")
|
||||
err := client.Login("my-dyn-username", "my-dyn-password")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := client.Logout()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Make a request to the API, to get a list of all, managed DNS zones
|
||||
var response dynect.ZonesResponse
|
||||
if err := client.Do("GET", "Zone", nil, &response); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
for _, zone := range response.Data {
|
||||
log.Println("Zone", zone)
|
||||
}
|
||||
}
|
||||
|
||||
More to come!
|
||||
281
vendor/github.com/nesv/go-dynect/dynect/client.go
generated
vendored
Normal file
281
vendor/github.com/nesv/go-dynect/dynect/client.go
generated
vendored
Normal file
@ -0,0 +1,281 @@
|
||||
package dynect
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
DynAPIPrefix = "https://api.dynect.net/REST"
|
||||
)
|
||||
|
||||
var (
|
||||
PollingInterval = 1 * time.Second
|
||||
ErrPromotedToJob = errors.New("promoted to job")
|
||||
ErrRateLimited = errors.New("too many requests")
|
||||
)
|
||||
|
||||
// handleJobRedirect overrides the net/http.DefaultClient's redirection policy
|
||||
// function.
|
||||
//
|
||||
// This function will set the Content-Type, and Auth-Token headers, so that we
|
||||
// don't get an error back from the API.
|
||||
func handleJobRedirect(req *http.Request, via []*http.Request) error {
|
||||
// Set the Content-Type header.
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
// Now, try and divine the Auth-Token header's value from previous
|
||||
// requests.
|
||||
for _, r := range via {
|
||||
if authHdr := r.Header.Get("Auth-Token"); authHdr != "" {
|
||||
req.Header.Set("Auth-Token", authHdr)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("failed to set Auth-Token header from previous requests")
|
||||
}
|
||||
|
||||
// A client for use with DynECT's REST API.
|
||||
type Client struct {
|
||||
Token string
|
||||
CustomerName string
|
||||
Transport http.RoundTripper
|
||||
verbose bool
|
||||
}
|
||||
|
||||
// Creates a new Httpclient.
|
||||
func NewClient(customerName string) *Client {
|
||||
return &Client{
|
||||
CustomerName: customerName,
|
||||
Transport: &http.Transport{Proxy: http.ProxyFromEnvironment},
|
||||
}
|
||||
}
|
||||
|
||||
// Sets the transport for the client.
|
||||
func (c *Client) SetTransport(t http.RoundTripper) {
|
||||
c.Transport = t
|
||||
}
|
||||
|
||||
// Enable, or disable verbose output from the client.
|
||||
//
|
||||
// This will enable (or disable) logging messages that explain what the client
|
||||
// is about to do, like the endpoint it is about to make a request to. If the
|
||||
// request fails with an unexpected HTTP response code, then the response body
|
||||
// will be logged out, as well.
|
||||
func (c *Client) Verbose(p bool) {
|
||||
c.verbose = p
|
||||
}
|
||||
|
||||
// Establishes a new session with the DynECT API.
|
||||
func (c *Client) Login(username, password string) error {
|
||||
var req = LoginBlock{
|
||||
Username: username,
|
||||
Password: password,
|
||||
CustomerName: c.CustomerName}
|
||||
|
||||
var resp LoginResponse
|
||||
|
||||
err := c.Do("POST", "Session", req, &resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.Token = resp.Data.Token
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) LoggedIn() bool {
|
||||
return len(c.Token) > 0
|
||||
}
|
||||
|
||||
func (c *Client) Logout() error {
|
||||
return c.Do("DELETE", "Session", nil, nil)
|
||||
}
|
||||
|
||||
// newRequest creates a new *http.Request, and sets the following headers:
|
||||
// <ul>
|
||||
// <li>Auth-Token</li>
|
||||
// <li>Content-Type</li>
|
||||
// </ul>
|
||||
func (c *Client) newRequest(method, urlStr string, data []byte) (*http.Request, error) {
|
||||
var r *http.Request
|
||||
var err error
|
||||
|
||||
if data != nil {
|
||||
r, err = http.NewRequest(method, urlStr, bytes.NewReader(data))
|
||||
} else {
|
||||
r, err = http.NewRequest(method, urlStr, nil)
|
||||
}
|
||||
|
||||
r.Header.Set("Auth-Token", c.Token)
|
||||
r.Header.Set("Content-Type", "application/json")
|
||||
|
||||
return r, err
|
||||
}
|
||||
|
||||
func (c *Client) Do(method, endpoint string, requestData, responseData interface{}) error {
|
||||
// Throw an error if the user tries to make a request if the client is
|
||||
// logged out/unauthenticated, but make an exemption for when the
|
||||
// caller is trying to log in.
|
||||
if !c.LoggedIn() && method != "POST" && endpoint != "Session" {
|
||||
return errors.New("Will not perform request; client is closed")
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
// Marshal the request data into a byte slice.
|
||||
if c.verbose {
|
||||
log.Println("dynect: marshaling request data")
|
||||
}
|
||||
var js []byte
|
||||
if requestData != nil {
|
||||
js, err = json.Marshal(requestData)
|
||||
} else {
|
||||
js = []byte("")
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
urlStr := fmt.Sprintf("%s/%s", DynAPIPrefix, endpoint)
|
||||
|
||||
// Create a new http.Request.
|
||||
req, err := c.newRequest(method, urlStr, js)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.verbose {
|
||||
log.Printf("Making %s request to %q", method, urlStr)
|
||||
}
|
||||
|
||||
var resp *http.Response
|
||||
resp, err = c.Transport.RoundTrip(req)
|
||||
|
||||
if err != nil {
|
||||
if c.verbose {
|
||||
respBody, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Printf("%s", string(respBody))
|
||||
}
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
switch resp.StatusCode {
|
||||
case 200:
|
||||
if resp.ContentLength == 0 {
|
||||
// Zero-length content body?
|
||||
log.Println("dynect: warning: zero-length response body; skipping decoding of response")
|
||||
return nil
|
||||
}
|
||||
|
||||
//dec := json.NewDecoder(resp.Body)
|
||||
text, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Could not read response body")
|
||||
}
|
||||
if err := json.Unmarshal(text, &responseData); err != nil {
|
||||
return fmt.Errorf("Error unmarshalling response:", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
case 307:
|
||||
// Handle the temporary redirect, which should point to a
|
||||
// /REST/Jobs endpoint.
|
||||
loc := resp.Header.Get("Location")
|
||||
log.Println("dynect: request is taking too long to complete: redirecting to", loc)
|
||||
|
||||
// Going in to this blind, the documentation says that it will
|
||||
// return a URI when promoting a long-running request to a
|
||||
// job.
|
||||
//
|
||||
// Since a URL is technically a URI, we should do some checks
|
||||
// on the returned URI to sanitize it, and make sure that it is
|
||||
// in the format we would like it to be.
|
||||
if strings.HasPrefix(loc, "/REST/") {
|
||||
loc = strings.TrimLeft(loc, "/REST/")
|
||||
}
|
||||
if !strings.HasPrefix(loc, DynAPIPrefix) {
|
||||
loc = fmt.Sprintf("%s/%s", DynAPIPrefix, loc)
|
||||
}
|
||||
|
||||
log.Println("Fetching location:", loc)
|
||||
|
||||
// Generate a new request.
|
||||
req, err := c.newRequest("GET", loc, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var jobData JobData
|
||||
|
||||
// Poll the API endpoint, until we get a response back.
|
||||
for {
|
||||
select {
|
||||
case <-time.After(PollingInterval):
|
||||
resp, err := c.Transport.RoundTrip(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
text, err := ioutil.ReadAll(resp.Body)
|
||||
//log.Println(string(text))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Could not read response body:", err)
|
||||
}
|
||||
if err := json.Unmarshal(text, &jobData); err != nil {
|
||||
return fmt.Errorf("failed to decode job response body:", err)
|
||||
}
|
||||
|
||||
// Check to see the status of the job.
|
||||
//
|
||||
// If it is "incomplete", loop around again.
|
||||
//
|
||||
// Should the job's status be "success", then
|
||||
// return the data, business-as-usual.
|
||||
//
|
||||
// TODO(nesv): Figure out what to do in the
|
||||
// event of a "failure" job status.
|
||||
|
||||
switch jobData.Status {
|
||||
case "incomplete":
|
||||
continue
|
||||
case "success":
|
||||
if err := json.Unmarshal(text, &responseData); err != nil {
|
||||
return fmt.Errorf("failed to decode response body:", err)
|
||||
}
|
||||
return nil
|
||||
case "failure":
|
||||
return fmt.Errorf("request failed: %v", jobData.Messages)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
case 429:
|
||||
return ErrRateLimited
|
||||
}
|
||||
|
||||
// If we got here, this means that the client does not know how to
|
||||
// interpret the response, and it should just error out.
|
||||
reason, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read in response body")
|
||||
}
|
||||
return fmt.Errorf("server responded with %v: %v",
|
||||
resp.Status,
|
||||
string(reason))
|
||||
}
|
||||
123
vendor/github.com/nesv/go-dynect/dynect/client_test.go
generated
vendored
Normal file
123
vendor/github.com/nesv/go-dynect/dynect/client_test.go
generated
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
package dynect
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/dnaeon/go-vcr/recorder"
|
||||
)
|
||||
|
||||
var (
|
||||
DynCustomerName string
|
||||
DynUsername string
|
||||
DynPassword string
|
||||
testZone string
|
||||
)
|
||||
|
||||
func getenv(key, defaultValue string) string {
|
||||
if value, ok := os.LookupEnv(key); ok {
|
||||
return value
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
func init() {
|
||||
DynCustomerName = getenv("DYNECT_CUSTOMER_NAME", "go-dynect")
|
||||
DynUsername = getenv("DYNECT_USER_NAME", "dynect-user")
|
||||
DynPassword = getenv("DYNECT_PASSWORD", "p@55w0rd")
|
||||
testZone = getenv("DYNECT_TEST_ZONE", "go-dynect.test")
|
||||
}
|
||||
|
||||
// test helper to begin recording or playback of vcr cassette
|
||||
func withCassette(cassetteName string, f func(*recorder.Recorder)) {
|
||||
r, err := recorder.New(cassetteName)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
defer r.Stop()
|
||||
|
||||
f(r)
|
||||
}
|
||||
|
||||
// test helper to setup client with vcr cassette
|
||||
func withClient(cassetteName string, f func(*Client)) {
|
||||
withCassette(cassetteName, func(r *recorder.Recorder) {
|
||||
c := NewClient(DynCustomerName)
|
||||
c.SetTransport(r)
|
||||
c.Verbose(true)
|
||||
|
||||
f(c)
|
||||
})
|
||||
}
|
||||
|
||||
// test helper to setup authenticated client with vcr cassette
|
||||
func testWithClientSession(cassetteName string, t *testing.T, f func(*Client)) {
|
||||
withClient(cassetteName, func(c *Client) {
|
||||
if err := c.Login(DynUsername, DynPassword); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := c.Logout(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}()
|
||||
|
||||
f(c)
|
||||
})
|
||||
}
|
||||
|
||||
func TestLoginLogout(t *testing.T) {
|
||||
withClient("fixtures/login_logout", func(c *Client) {
|
||||
if err := c.Login(DynUsername, DynPassword); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if err := c.Logout(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestZonesRequest(t *testing.T) {
|
||||
testWithClientSession("fixtures/zones_request", t, func(c *Client) {
|
||||
var resp ZonesResponse
|
||||
|
||||
if err := c.Do("GET", "Zone", nil, &resp); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
nresults := len(resp.Data)
|
||||
for i, zone := range resp.Data {
|
||||
parts := strings.Split(zone, "/")
|
||||
t.Logf("(%d/%d) %q", i+1, nresults, parts[len(parts)-2])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestFetchingAllZoneRecords(t *testing.T) {
|
||||
testWithClientSession("fixtures/fetching_all_zone_records", t, func(c *Client) {
|
||||
var resp AllRecordsResponse
|
||||
|
||||
if err := c.Do("GET", "AllRecord/"+testZone, nil, &resp); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
for _, zr := range resp.Data {
|
||||
parts := strings.Split(zr, "/")
|
||||
uri := strings.Join(parts[2:], "/")
|
||||
t.Log(uri)
|
||||
|
||||
var record RecordResponse
|
||||
|
||||
if err := c.Do("GET", uri, nil, &record); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Log("OK")
|
||||
}
|
||||
})
|
||||
}
|
||||
242
vendor/github.com/nesv/go-dynect/dynect/convenient_client.go
generated
vendored
Normal file
242
vendor/github.com/nesv/go-dynect/dynect/convenient_client.go
generated
vendored
Normal file
@ -0,0 +1,242 @@
|
||||
package dynect
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ConvenientClient A client with extra helper methods for common actions
|
||||
type ConvenientClient struct {
|
||||
Client
|
||||
}
|
||||
|
||||
// NewConvenientClient Creates a new ConvenientClient
|
||||
func NewConvenientClient(customerName string) *ConvenientClient {
|
||||
return &ConvenientClient{
|
||||
Client{
|
||||
CustomerName: customerName,
|
||||
Transport: &http.Transport{Proxy: http.ProxyFromEnvironment},
|
||||
}}
|
||||
}
|
||||
|
||||
// CreateZone method to create a zone
|
||||
func (c *ConvenientClient) CreateZone(zone, rname, serialStyle, ttl string) error {
|
||||
url := fmt.Sprintf("Zone/%s/", zone)
|
||||
data := &CreateZoneBlock{
|
||||
RName: rname,
|
||||
SerialStyle: serialStyle,
|
||||
TTL: ttl,
|
||||
}
|
||||
|
||||
if err := c.Do("POST", url, data, nil); err != nil {
|
||||
return fmt.Errorf("Failed to create zone: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetZone method to read a zone
|
||||
func (c *ConvenientClient) GetZone(z *Zone) error {
|
||||
url := fmt.Sprintf("Zone/%s", z.Zone)
|
||||
data := &ZoneResponse{}
|
||||
|
||||
if err := c.Do("GET", url, nil, data); err != nil {
|
||||
return fmt.Errorf("Failed to get zone: %s", err)
|
||||
}
|
||||
|
||||
z.Serial = strconv.Itoa(data.Data.Serial)
|
||||
z.SerialStyle = data.Data.SerialStyle
|
||||
z.Zone = data.Data.Zone
|
||||
z.Type = data.Data.ZoneType
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PublishZone Publish a specific zone and the changes for the current session
|
||||
func (c *ConvenientClient) PublishZone(zone string) error {
|
||||
url := fmt.Sprintf("Zone/%s", zone)
|
||||
data := &PublishZoneBlock{
|
||||
Publish: true,
|
||||
}
|
||||
|
||||
if err := c.Do("PUT", url, data, nil); err != nil {
|
||||
return fmt.Errorf("Failed to publish zone: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteZoneNode method to delete everything in a zone
|
||||
func (c *ConvenientClient) DeleteZoneNode(zone string) error {
|
||||
parentZone := strings.Join(strings.Split(zone, ".")[1:], ".")
|
||||
url := fmt.Sprintf("Node/%s/%s", parentZone, zone)
|
||||
|
||||
if err := c.Do("DELETE", url, nil, nil); err != nil {
|
||||
return fmt.Errorf("Failed to delete zone node: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteZone method to delete a zone
|
||||
func (c *ConvenientClient) DeleteZone(zone string) error {
|
||||
url := fmt.Sprintf("Zone/%s/", zone)
|
||||
|
||||
if err := c.Do("DELETE", url, nil, nil); err != nil {
|
||||
return fmt.Errorf("Failed to delete zone: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetRecordID finds the dns record ID by fetching all records for a FQDN
|
||||
func (c *ConvenientClient) GetRecordID(record *Record) error {
|
||||
finalID := ""
|
||||
url := fmt.Sprintf("AllRecord/%s/%s", record.Zone, record.FQDN)
|
||||
var records AllRecordsResponse
|
||||
err := c.Do("GET", url, nil, &records)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to find Dyn record id: %s", err)
|
||||
}
|
||||
for _, recordURL := range records.Data {
|
||||
id := strings.TrimPrefix(recordURL, fmt.Sprintf("/REST/%sRecord/%s/%s/", record.Type, record.Zone, record.FQDN))
|
||||
if !strings.Contains(id, "/") && id != "" {
|
||||
finalID = id
|
||||
log.Printf("[INFO] Found Dyn record ID: %s", id)
|
||||
}
|
||||
}
|
||||
if finalID == "" {
|
||||
return fmt.Errorf("Failed to find Dyn record id!")
|
||||
}
|
||||
|
||||
record.ID = finalID
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateRecord Method to create a DNS record
|
||||
func (c *ConvenientClient) CreateRecord(record *Record) error {
|
||||
if record.FQDN == "" && record.Name == "" {
|
||||
record.FQDN = record.Zone
|
||||
} else if record.FQDN == "" {
|
||||
record.FQDN = fmt.Sprintf("%s.%s", record.Name, record.Zone)
|
||||
}
|
||||
rdata, err := buildRData(record)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to create Dyn RData: %s", err)
|
||||
}
|
||||
url := fmt.Sprintf("%sRecord/%s/%s", record.Type, record.Zone, record.FQDN)
|
||||
data := &RecordRequest{
|
||||
RData: rdata,
|
||||
TTL: record.TTL,
|
||||
}
|
||||
return c.Do("POST", url, data, nil)
|
||||
}
|
||||
|
||||
// UpdateRecord Method to update a DNS record
|
||||
func (c *ConvenientClient) UpdateRecord(record *Record) error {
|
||||
if record.FQDN == "" {
|
||||
record.FQDN = fmt.Sprintf("%s.%s", record.Name, record.Zone)
|
||||
}
|
||||
rdata, err := buildRData(record)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to create Dyn RData: %s", err)
|
||||
}
|
||||
url := fmt.Sprintf("%sRecord/%s/%s/%s", record.Type, record.Zone, record.FQDN, record.ID)
|
||||
data := &RecordRequest{
|
||||
RData: rdata,
|
||||
TTL: record.TTL,
|
||||
}
|
||||
return c.Do("PUT", url, data, nil)
|
||||
}
|
||||
|
||||
// DeleteRecord Method to delete a DNS record
|
||||
func (c *ConvenientClient) DeleteRecord(record *Record) error {
|
||||
if record.FQDN == "" {
|
||||
record.FQDN = fmt.Sprintf("%s.%s", record.Name, record.Zone)
|
||||
}
|
||||
// safety check that we have an ID, otherwise we could accidentally delete everything
|
||||
if record.ID == "" {
|
||||
return fmt.Errorf("No ID found! We can't continue!")
|
||||
}
|
||||
url := fmt.Sprintf("%sRecord/%s/%s/%s", record.Type, record.Zone, record.FQDN, record.ID)
|
||||
return c.Do("DELETE", url, nil, nil)
|
||||
}
|
||||
|
||||
// GetRecord Method to get record details
|
||||
func (c *ConvenientClient) GetRecord(record *Record) error {
|
||||
url := fmt.Sprintf("%sRecord/%s/%s/%s", record.Type, record.Zone, record.FQDN, record.ID)
|
||||
var rec RecordResponse
|
||||
err := c.Do("GET", url, nil, &rec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
record.Zone = rec.Data.Zone
|
||||
record.FQDN = rec.Data.FQDN
|
||||
record.Name = strings.TrimSuffix(rec.Data.FQDN, "."+rec.Data.Zone)
|
||||
record.Type = rec.Data.RecordType
|
||||
record.TTL = strconv.Itoa(rec.Data.TTL)
|
||||
|
||||
switch rec.Data.RecordType {
|
||||
case "A", "AAAA":
|
||||
record.Value = rec.Data.RData.Address
|
||||
case "ALIAS":
|
||||
record.Value = rec.Data.RData.Alias
|
||||
case "CNAME":
|
||||
record.Value = rec.Data.RData.CName
|
||||
case "MX":
|
||||
record.Value = fmt.Sprintf("%d %s", rec.Data.RData.Preference, rec.Data.RData.Exchange)
|
||||
case "NS":
|
||||
record.Value = rec.Data.RData.NSDName
|
||||
case "SOA":
|
||||
record.Value = rec.Data.RData.RName
|
||||
case "TXT", "SPF":
|
||||
record.Value = rec.Data.RData.TxtData
|
||||
default:
|
||||
fmt.Println("unknown response", rec)
|
||||
return fmt.Errorf("Invalid Dyn record type: %s", rec.Data.RecordType)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildRData(r *Record) (DataBlock, error) {
|
||||
var rdata DataBlock
|
||||
|
||||
switch r.Type {
|
||||
case "A", "AAAA":
|
||||
rdata = DataBlock{
|
||||
Address: r.Value,
|
||||
}
|
||||
case "ALIAS":
|
||||
rdata = DataBlock{
|
||||
Alias: r.Value,
|
||||
}
|
||||
case "CNAME":
|
||||
rdata = DataBlock{
|
||||
CName: r.Value,
|
||||
}
|
||||
case "MX":
|
||||
rdata = DataBlock{}
|
||||
fmt.Sscanf(r.Value, "%d %s", &rdata.Preference, &rdata.Exchange)
|
||||
case "NS":
|
||||
rdata = DataBlock{
|
||||
NSDName: r.Value,
|
||||
}
|
||||
case "SOA":
|
||||
rdata = DataBlock{
|
||||
RName: r.Value,
|
||||
}
|
||||
case "TXT", "SPF":
|
||||
rdata = DataBlock{
|
||||
TxtData: r.Value,
|
||||
}
|
||||
default:
|
||||
return rdata, fmt.Errorf("Invalid Dyn record type: %s", r.Type)
|
||||
}
|
||||
|
||||
return rdata, nil
|
||||
}
|
||||
241
vendor/github.com/nesv/go-dynect/dynect/convenient_client_test.go
generated
vendored
Normal file
241
vendor/github.com/nesv/go-dynect/dynect/convenient_client_test.go
generated
vendored
Normal file
@ -0,0 +1,241 @@
|
||||
package dynect
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/dnaeon/go-vcr/recorder"
|
||||
)
|
||||
|
||||
// test helper to setup convenient client with vcr cassette
|
||||
func withConvenientClient(cassetteName string, f func(*ConvenientClient)) {
|
||||
withCassette(cassetteName, func(r *recorder.Recorder) {
|
||||
c := NewConvenientClient(DynCustomerName)
|
||||
c.SetTransport(r)
|
||||
c.Verbose(true)
|
||||
|
||||
f(c)
|
||||
})
|
||||
}
|
||||
|
||||
// test helper to setup authenticated convenient client with vcr cassette
|
||||
func testWithConvenientClientSession(cassetteName string, t *testing.T, f func(*ConvenientClient)) {
|
||||
withConvenientClient(cassetteName, func(c *ConvenientClient) {
|
||||
if err := c.Login(DynUsername, DynPassword); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := c.Logout(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}()
|
||||
|
||||
f(c)
|
||||
})
|
||||
}
|
||||
|
||||
func TestConvenientLoginLogout(t *testing.T) {
|
||||
withConvenientClient("fixtures/login_logout", func(c *ConvenientClient) {
|
||||
if err := c.Login(DynUsername, DynPassword); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if err := c.Logout(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestConvenientGetA(t *testing.T) {
|
||||
testWithConvenientClientSession("fixtures/convenient_get_a", t, func(c *ConvenientClient) {
|
||||
actual := Record{
|
||||
Zone: testZone,
|
||||
Type: "A",
|
||||
FQDN: "foobar." + testZone,
|
||||
}
|
||||
|
||||
if err := c.GetRecordID(&actual); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := c.GetRecord(&actual); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if actual.Value != "10.9.8.7" {
|
||||
t.Fatalf("Incorrect value %q for %q (expected %q)", actual.Value, actual.FQDN, "foobar.go-dynect.test.")
|
||||
}
|
||||
|
||||
t.Log("OK")
|
||||
})
|
||||
}
|
||||
|
||||
func TestConvenientGetANotFound(t *testing.T) {
|
||||
testWithConvenientClientSession("fixtures/convenient_get_a_not_found", t, func(c *ConvenientClient) {
|
||||
actual := Record{
|
||||
Zone: testZone,
|
||||
Type: "A",
|
||||
FQDN: "unknown." + testZone,
|
||||
}
|
||||
|
||||
if err := c.GetRecordID(&actual); err == nil {
|
||||
t.Fatalf("Expected error getting %q", actual.FQDN)
|
||||
} else if !strings.HasPrefix(err.Error(), "Failed to find Dyn record id:") {
|
||||
t.Fatalf("Expected error %q for %q (actual error %q)", "Failed to find Dyn record id:", actual.FQDN, err.Error())
|
||||
}
|
||||
|
||||
t.Log("OK")
|
||||
})
|
||||
}
|
||||
|
||||
func TestConvenientGetCNAME(t *testing.T) {
|
||||
testWithConvenientClientSession("fixtures/convenient_get_cname", t, func(c *ConvenientClient) {
|
||||
actual := Record{
|
||||
Zone: testZone,
|
||||
Type: "CNAME",
|
||||
FQDN: "foo." + testZone,
|
||||
}
|
||||
|
||||
if err := c.GetRecordID(&actual); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := c.GetRecord(&actual); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if actual.Value != "foobar.go-dynect.test." {
|
||||
t.Fatalf("Incorrect value %q (expected %q)", actual.Value, "foobar.go-dynect.test.")
|
||||
}
|
||||
|
||||
t.Log("OK")
|
||||
})
|
||||
}
|
||||
|
||||
func TestConvenientCreateMX(t *testing.T) {
|
||||
testWithConvenientClientSession("fixtures/convenient_create_mx", t, func(c *ConvenientClient) {
|
||||
record := Record{
|
||||
Zone: testZone,
|
||||
Type: "MX",
|
||||
Value: "123 mx.example.com.",
|
||||
TTL: "12345",
|
||||
}
|
||||
|
||||
if err := c.CreateRecord(&record); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := c.PublishZone(testZone); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := c.GetRecordID(&record); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := c.GetRecord(&record); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if record.FQDN != testZone {
|
||||
t.Fatalf("Expected FQDN %q (actual %q)", testZone, record.FQDN)
|
||||
}
|
||||
|
||||
id, err := strconv.Atoi(record.ID)
|
||||
if err != nil || id <= 0 {
|
||||
t.Fatalf("Expected ID to be positive integer (actual %q)", record.ID)
|
||||
}
|
||||
|
||||
ttl, err := strconv.Atoi(record.TTL)
|
||||
if err != nil || ttl != 12345 {
|
||||
t.Fatalf("Expected ID to be 12345 (actual %q)", record.TTL)
|
||||
}
|
||||
|
||||
t.Log("OK")
|
||||
})
|
||||
}
|
||||
|
||||
func TestConvenientCreateZone(t *testing.T) {
|
||||
testWithConvenientClientSession("fixtures/convenient_create_zone", t, func(c *ConvenientClient) {
|
||||
subZone := fmt.Sprintf("subzone.%s", testZone)
|
||||
|
||||
if err := c.CreateZone(subZone, "admin@example.com", "day", "1800"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := c.PublishZone(subZone); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
z := &Zone{Zone: subZone}
|
||||
|
||||
if err := c.GetZone(z); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if z.Zone != subZone {
|
||||
t.Fatalf("Expected Zone of %q (actual %q)", subZone, z.Zone)
|
||||
}
|
||||
|
||||
if z.Type != "Primary" {
|
||||
t.Fatalf("Expected Zone Type of %q (actual %q)", "Primary", z.Type)
|
||||
}
|
||||
|
||||
if z.SerialStyle != "day" {
|
||||
t.Fatalf("Expected SerialStyle of %q (actual %q)", "day", z.SerialStyle)
|
||||
}
|
||||
|
||||
if z.Serial == "" {
|
||||
t.Fatalf("Expected non-empty Serial (actual %q)", z.Serial)
|
||||
}
|
||||
|
||||
t.Log("OK")
|
||||
})
|
||||
}
|
||||
|
||||
func TestConvenientDeleteZone(t *testing.T) {
|
||||
testWithConvenientClientSession("fixtures/convenient_delete_zone", t, func(c *ConvenientClient) {
|
||||
subZone := fmt.Sprintf("zone-%s", testZone)
|
||||
|
||||
if err := c.DeleteZone(subZone); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
z := &Zone{Zone: subZone}
|
||||
|
||||
if err := c.GetZone(z); err == nil {
|
||||
t.Fatalf("Zone %q not deleted", subZone)
|
||||
}
|
||||
|
||||
t.Log("OK")
|
||||
})
|
||||
}
|
||||
|
||||
func TestConvenientDeleteSubZone(t *testing.T) {
|
||||
testWithConvenientClientSession("fixtures/convenient_delete_sub_zone", t, func(c *ConvenientClient) {
|
||||
subZone := fmt.Sprintf("subzone.%s", testZone)
|
||||
|
||||
if err := c.DeleteZone(subZone); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := c.DeleteZoneNode(subZone); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := c.PublishZone(testZone); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
z := &Zone{Zone: subZone}
|
||||
|
||||
if err := c.GetZone(z); err == nil {
|
||||
t.Fatalf("Zone %q not deleted", subZone)
|
||||
}
|
||||
|
||||
t.Log("OK")
|
||||
})
|
||||
}
|
||||
117
vendor/github.com/nesv/go-dynect/dynect/dsfs.go
generated
vendored
Normal file
117
vendor/github.com/nesv/go-dynect/dynect/dsfs.go
generated
vendored
Normal file
@ -0,0 +1,117 @@
|
||||
package dynect
|
||||
|
||||
// DSFSResponse is used for holding the data returned by a call to
|
||||
// "https://api.dynect.net/REST/DSF/" with 'detail: Y'.
|
||||
type AllDSFDetailedResponse struct {
|
||||
ResponseBlock
|
||||
Data []DSFService `json:"data"`
|
||||
}
|
||||
|
||||
// DSFResponse is used for holding the data returned by a call to
|
||||
// "https://api.dynect.net/REST/DSF/SERVICE_ID".
|
||||
type DSFResponse struct {
|
||||
ResponseBlock
|
||||
Data DSFService `json:"data"`
|
||||
}
|
||||
|
||||
// Type DSFService is used as a nested struct, which holds the data for a
|
||||
// DSF Service returned by a call to "https://api.dynect.net/REST/DSF/SERVICE_ID".
|
||||
type DSFService struct {
|
||||
ID string `json:"service_id"`
|
||||
Label string `json:"label"`
|
||||
Active string `json:"active"`
|
||||
TTL string `json:"ttl"`
|
||||
PendingChange string `json:"pending_change"`
|
||||
Notifiers []Notifier `json:"notifiers"`
|
||||
Nodes []DSFNode `json:"nodes"`
|
||||
Rulesets []DSFRuleset `json:"rulesets"`
|
||||
}
|
||||
|
||||
type DSFRuleset struct {
|
||||
ID string `json:"dsf_ruleset_id`
|
||||
Label string `json:"label"`
|
||||
CriteriaType string `json:"criteria_type"`
|
||||
Criteria interface{} `json:"criteria"`
|
||||
Ordering string `json:"ordering"`
|
||||
Eligible string `json:"eligible"`
|
||||
PendingChange string `json:"pending_change"`
|
||||
ResponsePools []DSFResponsePool `json:"response_pools"`
|
||||
}
|
||||
|
||||
type DSFResponsePool struct {
|
||||
ID string `json:"dsf_response_pool_id"`
|
||||
Label string `json:"label"`
|
||||
Automation string `json:"automation"`
|
||||
CoreSetCount string `json:"core_set_count"`
|
||||
Eligible string `json:"eligible"`
|
||||
PendingChange string `json:"pending_change"`
|
||||
RsChains []DSFRecordSetChain `json:"rs_chains"`
|
||||
Rulesets []DSFRuleset `json:"rulesets"`
|
||||
Status string `json:"status"`
|
||||
LastMonitored string `json:"last_monitored"`
|
||||
Notifier string `json:"notifier"`
|
||||
}
|
||||
|
||||
type DSFRecordSetChain struct {
|
||||
ID string `json:"dsf_record_set_failover_chain_id"`
|
||||
Status string `json:"status"`
|
||||
Core string `json:"core"`
|
||||
Label string `json:"label"`
|
||||
DSFResponsePoolID string `json:"dsf_response_pool_id"`
|
||||
DSFServiceID string `json:"service_id"`
|
||||
PendingChange string `json:"pending_change"`
|
||||
DSFRecordSets []DSFRecordSet `json:"record_sets"`
|
||||
}
|
||||
|
||||
type DSFRecordSet struct {
|
||||
Status string `json:"status"`
|
||||
Eligible string `json:"eligible"`
|
||||
ID string `json:"dsf_record_set_id"`
|
||||
MonitorID string `json:"dsf_monitor_id"`
|
||||
Label string `json:"label"`
|
||||
TroubleCount string `json:"trouble_count"`
|
||||
Records []DSFRecord `json:"records"`
|
||||
FailCount string `json:"fail_count"`
|
||||
TorpidityMax string `json:"torpidity_max"`
|
||||
TTLDerived string `json:"ttl_derived"`
|
||||
LastMonitored string `json:"last_monitored"`
|
||||
TTL string `json:"ttl"`
|
||||
ServiceID string `json:"service_id"`
|
||||
ServeCount string `json:"serve_count"`
|
||||
Automation string `json:"automation"`
|
||||
PendingChange string `json:"pending_change"`
|
||||
}
|
||||
|
||||
type DSFRecord struct {
|
||||
Status string `json:"status"`
|
||||
Endpoints []string `json:"endpoints"`
|
||||
RDataClass string `json:"rdata_class"`
|
||||
Weight int `json:"weight"`
|
||||
Eligible string `json:"eligible"`
|
||||
ID string `json:"dsf_record_id"`
|
||||
DSFRecordSetID string `json:"dsf_record_set_id"`
|
||||
//RData interface{} `json:"rdata"`
|
||||
EndpointUpCount int `json:"endpoint_up_count"`
|
||||
Label string `json:"label"`
|
||||
MasterLine string `json:"master_line"`
|
||||
Torpidity int `json:"torpidity"`
|
||||
LastMonitored int `json:"last_monitored"`
|
||||
TTL string `json:"ttl"`
|
||||
DSFServiceID string `json:"service_id"`
|
||||
PendingChange string `json:"pending_change"`
|
||||
Automation string `json:"automation"`
|
||||
ReponseTime int `json:"response_time"`
|
||||
Publish string `json:"publish",omit_empty`
|
||||
}
|
||||
|
||||
type DSFNode struct {
|
||||
Zone string `json:"zone"`
|
||||
FQDN string `json:"fqdn"`
|
||||
}
|
||||
|
||||
type Notifier struct {
|
||||
ID int `json:"notifier_id"`
|
||||
Label string `json:"label"`
|
||||
Recipients string `json:"recipients"`
|
||||
Active string `json:"active"`
|
||||
}
|
||||
161
vendor/github.com/nesv/go-dynect/dynect/fixtures/convenient_create_mx.yaml
generated
vendored
Normal file
161
vendor/github.com/nesv/go-dynect/dynect/fixtures/convenient_create_mx.yaml
generated
vendored
Normal file
@ -0,0 +1,161 @@
|
||||
---
|
||||
version: 1
|
||||
rwmutex: {}
|
||||
interactions:
|
||||
- request:
|
||||
body: '{"user_name":"dynect-user","password":"p@55w0rd","customer_name":"go-dynect"}'
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- ""
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Session
|
||||
method: POST
|
||||
response:
|
||||
body: '{"status": "success", "data": {"token": "5Trj0G1M2B0g1t1IY09yFwGpn31tjWNRNU81RhYHaUp6kxGa3UVK5F9hQqlZBu9SNLxkj6cAk6q93ndW246hIesr496yLD+eOHeJSdBtxxKgB+Gmk4ydsrR1trDIlK0Yq3l9J2XVPTT+/pKtyKmRxLWwNGHvhdJDfs92MiS3+7M=",
|
||||
"version": "3.7.9"}, "job_id": 4342593698, "msgs": [{"INFO": "login: Login successful",
|
||||
"SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 14:45:37 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: '{"rdata":{"exchange":"mx.example.com.","preference":123},"ttl":"12345"}'
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- 5Trj0G1M2B0g1t1IY09yFwGpn31tjWNRNU81RhYHaUp6kxGa3UVK5F9hQqlZBu9SNLxkj6cAk6q93ndW246hIesr496yLD+eOHeJSdBtxxKgB+Gmk4ydsrR1trDIlK0Yq3l9J2XVPTT+/pKtyKmRxLWwNGHvhdJDfs92MiS3+7M=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/MXRecord/go-dynect.test/go-dynect.test
|
||||
method: POST
|
||||
response:
|
||||
body: '{"status": "success", "data": {"zone": "go-dynect.test", "ttl": 12345,
|
||||
"fqdn": "go-dynect.test", "record_type": "MX", "rdata": {"preference": 123,
|
||||
"exchange": "mx.example.com."}, "record_id": 0}, "job_id": 4342593703, "msgs":
|
||||
[{"INFO": "add: Record added", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 14:45:37 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: '{"publish":true}'
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- 5Trj0G1M2B0g1t1IY09yFwGpn31tjWNRNU81RhYHaUp6kxGa3UVK5F9hQqlZBu9SNLxkj6cAk6q93ndW246hIesr496yLD+eOHeJSdBtxxKgB+Gmk4ydsrR1trDIlK0Yq3l9J2XVPTT+/pKtyKmRxLWwNGHvhdJDfs92MiS3+7M=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Zone/go-dynect.test
|
||||
method: PUT
|
||||
response:
|
||||
body: '{"status": "success", "data": {"zone_type": "Primary", "task_id": "230305365",
|
||||
"serial": 2017122005, "serial_style": "day", "zone": "go-dynect.test"}, "job_id":
|
||||
4342593710, "msgs": [{"INFO": "publish: go-dynect.test published", "SOURCE":
|
||||
"BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 14:45:37 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- 5Trj0G1M2B0g1t1IY09yFwGpn31tjWNRNU81RhYHaUp6kxGa3UVK5F9hQqlZBu9SNLxkj6cAk6q93ndW246hIesr496yLD+eOHeJSdBtxxKgB+Gmk4ydsrR1trDIlK0Yq3l9J2XVPTT+/pKtyKmRxLWwNGHvhdJDfs92MiS3+7M=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/AllRecord/go-dynect.test/go-dynect.test
|
||||
method: GET
|
||||
response:
|
||||
body: '{"status": "success", "data": ["/REST/CNAMERecord/go-dynect.test/foo.go-dynect.test/318905322",
|
||||
"/REST/SOARecord/go-dynect.test/go-dynect.test/318812133", "/REST/MXRecord/go-dynect.test/go-dynect.test/319018246",
|
||||
"/REST/NSRecord/go-dynect.test/go-dynect.test/318812135", "/REST/NSRecord/go-dynect.test/go-dynect.test/318812136",
|
||||
"/REST/NSRecord/go-dynect.test/go-dynect.test/318812137", "/REST/NSRecord/go-dynect.test/go-dynect.test/318812138",
|
||||
"/REST/ARecord/go-dynect.test/foobar.go-dynect.test/319014258"], "job_id": 4342593722,
|
||||
"msgs": [{"INFO": "get_tree: Here is your zone tree", "SOURCE": "BLL", "ERR_CD":
|
||||
null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 14:45:37 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- 5Trj0G1M2B0g1t1IY09yFwGpn31tjWNRNU81RhYHaUp6kxGa3UVK5F9hQqlZBu9SNLxkj6cAk6q93ndW246hIesr496yLD+eOHeJSdBtxxKgB+Gmk4ydsrR1trDIlK0Yq3l9J2XVPTT+/pKtyKmRxLWwNGHvhdJDfs92MiS3+7M=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/MXRecord/go-dynect.test/go-dynect.test/319018246
|
||||
method: GET
|
||||
response:
|
||||
body: '{"status": "success", "data": {"zone": "go-dynect.test", "ttl": 12345,
|
||||
"fqdn": "go-dynect.test", "record_type": "MX", "rdata": {"preference": 123,
|
||||
"exchange": "mx.example.com."}, "record_id": 319018246}, "job_id": 4342593727,
|
||||
"msgs": [{"INFO": "get: Found the record", "SOURCE": "API-B", "ERR_CD": null,
|
||||
"LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 14:45:37 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- 5Trj0G1M2B0g1t1IY09yFwGpn31tjWNRNU81RhYHaUp6kxGa3UVK5F9hQqlZBu9SNLxkj6cAk6q93ndW246hIesr496yLD+eOHeJSdBtxxKgB+Gmk4ydsrR1trDIlK0Yq3l9J2XVPTT+/pKtyKmRxLWwNGHvhdJDfs92MiS3+7M=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Session
|
||||
method: DELETE
|
||||
response:
|
||||
body: '{"status": "success", "data": {}, "job_id": 4342593732, "msgs": [{"INFO":
|
||||
"logout: Logout successful", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 14:45:37 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
134
vendor/github.com/nesv/go-dynect/dynect/fixtures/convenient_create_zone.yaml
generated
vendored
Normal file
134
vendor/github.com/nesv/go-dynect/dynect/fixtures/convenient_create_zone.yaml
generated
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
---
|
||||
version: 1
|
||||
rwmutex: {}
|
||||
interactions:
|
||||
- request:
|
||||
body: '{"user_name":"dynect-user","password":"p@55w0rd","customer_name":"go-dynect"}'
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- ""
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Session
|
||||
method: POST
|
||||
response:
|
||||
body: '{"status": "success", "data": {"token": "vTjIj83plGwG5lf+2gzYpI/JlEh8JQSM88ang3OVjUQfe8JfirVWlvl1786+nJbsg987HR6aiIcx6MuseIOvvNaeqxFwwR9xTJvP5EikWS2Cn/Xg/WVDulJ66xl1vjxusJVVlhgLY0MF0nGlBbVMjIYILxbg9pbkB7N4WL+dgu4=",
|
||||
"version": "3.7.9"}, "job_id": 4344013458, "msgs": [{"INFO": "login: Login successful",
|
||||
"SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Thu, 21 Dec 2017 00:57:07 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: '{"rname":"admin@example.com","serial_style":"day","ttl":"1800"}'
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- vTjIj83plGwG5lf+2gzYpI/JlEh8JQSM88ang3OVjUQfe8JfirVWlvl1786+nJbsg987HR6aiIcx6MuseIOvvNaeqxFwwR9xTJvP5EikWS2Cn/Xg/WVDulJ66xl1vjxusJVVlhgLY0MF0nGlBbVMjIYILxbg9pbkB7N4WL+dgu4=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Zone/subzone.go-dynect.test/
|
||||
method: POST
|
||||
response:
|
||||
body: '{"status": "success", "data": {"zone_type": "Primary", "serial_style":
|
||||
"day", "serial": 0, "zone": "subzone.go-dynect.test"}, "job_id": 4344013466,
|
||||
"msgs": [{"INFO": "setup: If you plan to provide your own secondary DNS for
|
||||
the zone, allow notify requests from these IP addresses on your nameserver:
|
||||
208.78.68.66, 2600:2003:0:1::66", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"},
|
||||
{"INFO": "create: New zone subzone.go-dynect.test created. Publish it to put
|
||||
it on our server.", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Thu, 21 Dec 2017 00:57:09 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: '{"publish":true}'
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- vTjIj83plGwG5lf+2gzYpI/JlEh8JQSM88ang3OVjUQfe8JfirVWlvl1786+nJbsg987HR6aiIcx6MuseIOvvNaeqxFwwR9xTJvP5EikWS2Cn/Xg/WVDulJ66xl1vjxusJVVlhgLY0MF0nGlBbVMjIYILxbg9pbkB7N4WL+dgu4=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Zone/subzone.go-dynect.test
|
||||
method: PUT
|
||||
response:
|
||||
body: '{"status": "success", "data": {"zone_type": "Primary", "task_id": "230378639",
|
||||
"serial": 2017122100, "serial_style": "day", "zone": "subzone.go-dynect.test"},
|
||||
"job_id": 4344013515, "msgs": [{"INFO": "publish: subzone.go-dynect.test published",
|
||||
"SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Thu, 21 Dec 2017 00:57:09 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- vTjIj83plGwG5lf+2gzYpI/JlEh8JQSM88ang3OVjUQfe8JfirVWlvl1786+nJbsg987HR6aiIcx6MuseIOvvNaeqxFwwR9xTJvP5EikWS2Cn/Xg/WVDulJ66xl1vjxusJVVlhgLY0MF0nGlBbVMjIYILxbg9pbkB7N4WL+dgu4=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Zone/subzone.go-dynect.test
|
||||
method: GET
|
||||
response:
|
||||
body: '{"status": "success", "data": {"zone_type": "Primary", "serial_style":
|
||||
"day", "serial": 2017122100, "zone": "subzone.go-dynect.test"}, "job_id": 4344013521,
|
||||
"msgs": [{"INFO": "get: Your zone, subzone.go-dynect.test", "SOURCE": "BLL",
|
||||
"ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Thu, 21 Dec 2017 00:57:09 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- vTjIj83plGwG5lf+2gzYpI/JlEh8JQSM88ang3OVjUQfe8JfirVWlvl1786+nJbsg987HR6aiIcx6MuseIOvvNaeqxFwwR9xTJvP5EikWS2Cn/Xg/WVDulJ66xl1vjxusJVVlhgLY0MF0nGlBbVMjIYILxbg9pbkB7N4WL+dgu4=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Session
|
||||
method: DELETE
|
||||
response:
|
||||
body: '{"status": "success", "data": {}, "job_id": 4344013527, "msgs": [{"INFO":
|
||||
"logout: Logout successful", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Thu, 21 Dec 2017 00:57:09 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
153
vendor/github.com/nesv/go-dynect/dynect/fixtures/convenient_delete_sub_zone.yaml
generated
vendored
Normal file
153
vendor/github.com/nesv/go-dynect/dynect/fixtures/convenient_delete_sub_zone.yaml
generated
vendored
Normal file
@ -0,0 +1,153 @@
|
||||
---
|
||||
version: 1
|
||||
rwmutex: {}
|
||||
interactions:
|
||||
- request:
|
||||
body: '{"user_name":"dynect-user","password":"p@55w0rd","customer_name":"go-dynect"}'
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- ""
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Session
|
||||
method: POST
|
||||
response:
|
||||
body: '{"status": "success", "data": {"token": "THqiI1SkDZateC3XF1y3bF6ZlPlYlIP+uEAr7mE9G3XT84cwTLNkbmArR4xGPnfJmsKYOT+mN3PO0z1G8wu4R7W4DufXuywZoNQWYxv51+X3ZQd0MkFA7OMvtPTRxts+E0Kc5HGLjqmZLD/AEpfHu/5XemknyRMD",
|
||||
"version": "3.7.9"}, "job_id": 4349697720, "msgs": [{"INFO": "login: Login successful",
|
||||
"SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Fri, 22 Dec 2017 17:43:51 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- THqiI1SkDZateC3XF1y3bF6ZlPlYlIP+uEAr7mE9G3XT84cwTLNkbmArR4xGPnfJmsKYOT+mN3PO0z1G8wu4R7W4DufXuywZoNQWYxv51+X3ZQd0MkFA7OMvtPTRxts+E0Kc5HGLjqmZLD/AEpfHu/5XemknyRMD
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Zone/subzone.go-dynect.test/
|
||||
method: DELETE
|
||||
response:
|
||||
body: '{"status": "success", "data": {}, "job_id": 4349697722, "msgs": [{"INFO":
|
||||
"remove: Zone removed", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Fri, 22 Dec 2017 17:43:51 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- THqiI1SkDZateC3XF1y3bF6ZlPlYlIP+uEAr7mE9G3XT84cwTLNkbmArR4xGPnfJmsKYOT+mN3PO0z1G8wu4R7W4DufXuywZoNQWYxv51+X3ZQd0MkFA7OMvtPTRxts+E0Kc5HGLjqmZLD/AEpfHu/5XemknyRMD
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Node/go-dynect.test/subzone.go-dynect.test
|
||||
method: DELETE
|
||||
response:
|
||||
body: '{"status": "success", "data": {"zone_type": "Primary", "serial_style":
|
||||
"day", "serial": 2017122201, "zone": "go-dynect.test"}, "job_id": 4349697733,
|
||||
"msgs": [{"INFO": "remove_node: subzone.go-dynect.test removed from tree. All
|
||||
records also removed.", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Fri, 22 Dec 2017 17:43:51 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: '{"publish":true}'
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- THqiI1SkDZateC3XF1y3bF6ZlPlYlIP+uEAr7mE9G3XT84cwTLNkbmArR4xGPnfJmsKYOT+mN3PO0z1G8wu4R7W4DufXuywZoNQWYxv51+X3ZQd0MkFA7OMvtPTRxts+E0Kc5HGLjqmZLD/AEpfHu/5XemknyRMD
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Zone/go-dynect.test
|
||||
method: PUT
|
||||
response:
|
||||
body: '{"status": "success", "data": {"zone_type": "Primary", "task_id": "230665571",
|
||||
"serial": 2017122202, "serial_style": "day", "zone": "go-dynect.test"}, "job_id":
|
||||
4349697739, "msgs": [{"INFO": "publish: go-dynect.test published", "SOURCE":
|
||||
"BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Fri, 22 Dec 2017 17:43:52 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- THqiI1SkDZateC3XF1y3bF6ZlPlYlIP+uEAr7mE9G3XT84cwTLNkbmArR4xGPnfJmsKYOT+mN3PO0z1G8wu4R7W4DufXuywZoNQWYxv51+X3ZQd0MkFA7OMvtPTRxts+E0Kc5HGLjqmZLD/AEpfHu/5XemknyRMD
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Zone/subzone.go-dynect.test
|
||||
method: GET
|
||||
response:
|
||||
body: '{"status": "failure", "data": {}, "job_id": 4349697747, "msgs": [{"INFO":
|
||||
"zone: No such zone", "SOURCE": "API-B", "ERR_CD": "NOT_FOUND", "LVL": "ERROR"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Fri, 22 Dec 2017 17:43:52 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 404 Not Found
|
||||
code: 404
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- THqiI1SkDZateC3XF1y3bF6ZlPlYlIP+uEAr7mE9G3XT84cwTLNkbmArR4xGPnfJmsKYOT+mN3PO0z1G8wu4R7W4DufXuywZoNQWYxv51+X3ZQd0MkFA7OMvtPTRxts+E0Kc5HGLjqmZLD/AEpfHu/5XemknyRMD
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Session
|
||||
method: DELETE
|
||||
response:
|
||||
body: '{"status": "success", "data": {}, "job_id": 4349697755, "msgs": [{"INFO":
|
||||
"logout: Logout successful", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Fri, 22 Dec 2017 17:43:52 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
101
vendor/github.com/nesv/go-dynect/dynect/fixtures/convenient_delete_zone.yaml
generated
vendored
Normal file
101
vendor/github.com/nesv/go-dynect/dynect/fixtures/convenient_delete_zone.yaml
generated
vendored
Normal file
@ -0,0 +1,101 @@
|
||||
---
|
||||
version: 1
|
||||
rwmutex: {}
|
||||
interactions:
|
||||
- request:
|
||||
body: '{"user_name":"dynect-user","password":"p@55w0rd","customer_name":"go-dynect"}'
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- ""
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Session
|
||||
method: POST
|
||||
response:
|
||||
body: '{"status": "success", "data": {"token": "ehqnDu44eQcNVPhHf+iyRd8/Ilgx5SpF0uR7OCPbjNGMA131GlouJtqLN5VS8flT+cChPirW9NEbjo3PfJOJmCasbumDfEg7PdAyd2rOvhKG4/XHze/FRv7bAnsFFafZHL5wfSoGgqdZlv+vZRJctWpDkXLHt9RHM8UejSS0/Qo=",
|
||||
"version": "3.7.9"}, "job_id": 4349699356, "msgs": [{"INFO": "login: Login successful",
|
||||
"SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Fri, 22 Dec 2017 17:44:40 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- ehqnDu44eQcNVPhHf+iyRd8/Ilgx5SpF0uR7OCPbjNGMA131GlouJtqLN5VS8flT+cChPirW9NEbjo3PfJOJmCasbumDfEg7PdAyd2rOvhKG4/XHze/FRv7bAnsFFafZHL5wfSoGgqdZlv+vZRJctWpDkXLHt9RHM8UejSS0/Qo=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Zone/zone-go-dynect.test/
|
||||
method: DELETE
|
||||
response:
|
||||
body: '{"status": "success", "data": {}, "job_id": 4349699362, "msgs": [{"INFO":
|
||||
"remove: Zone removed", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Fri, 22 Dec 2017 17:44:41 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- ehqnDu44eQcNVPhHf+iyRd8/Ilgx5SpF0uR7OCPbjNGMA131GlouJtqLN5VS8flT+cChPirW9NEbjo3PfJOJmCasbumDfEg7PdAyd2rOvhKG4/XHze/FRv7bAnsFFafZHL5wfSoGgqdZlv+vZRJctWpDkXLHt9RHM8UejSS0/Qo=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Zone/zone-go-dynect.test
|
||||
method: GET
|
||||
response:
|
||||
body: '{"status": "failure", "data": {}, "job_id": 4349699368, "msgs": [{"INFO":
|
||||
"zone: No such zone", "SOURCE": "API-B", "ERR_CD": "NOT_FOUND", "LVL": "ERROR"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Fri, 22 Dec 2017 17:44:41 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 404 Not Found
|
||||
code: 404
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- ehqnDu44eQcNVPhHf+iyRd8/Ilgx5SpF0uR7OCPbjNGMA131GlouJtqLN5VS8flT+cChPirW9NEbjo3PfJOJmCasbumDfEg7PdAyd2rOvhKG4/XHze/FRv7bAnsFFafZHL5wfSoGgqdZlv+vZRJctWpDkXLHt9RHM8UejSS0/Qo=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Session
|
||||
method: DELETE
|
||||
response:
|
||||
body: '{"status": "success", "data": {}, "job_id": 4349699370, "msgs": [{"INFO":
|
||||
"logout: Logout successful", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Fri, 22 Dec 2017 17:44:41 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
104
vendor/github.com/nesv/go-dynect/dynect/fixtures/convenient_get_a.yaml
generated
vendored
Normal file
104
vendor/github.com/nesv/go-dynect/dynect/fixtures/convenient_get_a.yaml
generated
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
---
|
||||
version: 1
|
||||
rwmutex: {}
|
||||
interactions:
|
||||
- request:
|
||||
body: '{"user_name":"dynect-user","password":"p@55w0rd","customer_name":"go-dynect"}'
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- ""
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Session
|
||||
method: POST
|
||||
response:
|
||||
body: '{"status": "success", "data": {"token": "S7uWFq5OnRrL0divNfQgijM1gPTh8aIa3qHvoH+t1GVF84hwfMF8e9BD5ty09DuMprfDW1pDMgG45mEYNJE+KT2Xow8s5tfcA9mijaNemE+7gQ4DlkVd7PHggpUckUFN+faA5vPOTfSEn6T+MEux5ZoTnncnawkgqtu40DhzVV8=",
|
||||
"version": "3.7.9"}, "job_id": 4342164998, "msgs": [{"INFO": "login: Login successful",
|
||||
"SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 11:22:46 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- S7uWFq5OnRrL0divNfQgijM1gPTh8aIa3qHvoH+t1GVF84hwfMF8e9BD5ty09DuMprfDW1pDMgG45mEYNJE+KT2Xow8s5tfcA9mijaNemE+7gQ4DlkVd7PHggpUckUFN+faA5vPOTfSEn6T+MEux5ZoTnncnawkgqtu40DhzVV8=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/AllRecord/go-dynect.test/foobar.go-dynect.test
|
||||
method: GET
|
||||
response:
|
||||
body: '{"status": "success", "data": ["/REST/ARecord/go-dynect.test/foobar.go-dynect.test/318905321"],
|
||||
"job_id": 4342165004, "msgs": [{"INFO": "get_tree: Here is your zone tree",
|
||||
"SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 11:22:46 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- S7uWFq5OnRrL0divNfQgijM1gPTh8aIa3qHvoH+t1GVF84hwfMF8e9BD5ty09DuMprfDW1pDMgG45mEYNJE+KT2Xow8s5tfcA9mijaNemE+7gQ4DlkVd7PHggpUckUFN+faA5vPOTfSEn6T+MEux5ZoTnncnawkgqtu40DhzVV8=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/ARecord/go-dynect.test/foobar.go-dynect.test/318905321
|
||||
method: GET
|
||||
response:
|
||||
body: '{"status": "success", "data": {"zone": "go-dynect.test", "ttl": 3600, "fqdn":
|
||||
"foobar.go-dynect.test", "record_type": "A", "rdata": {"address": "10.9.8.7"},
|
||||
"record_id": 318905321}, "job_id": 4342165009, "msgs": [{"INFO": "get: Found
|
||||
the record", "SOURCE": "API-B", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 11:22:46 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- S7uWFq5OnRrL0divNfQgijM1gPTh8aIa3qHvoH+t1GVF84hwfMF8e9BD5ty09DuMprfDW1pDMgG45mEYNJE+KT2Xow8s5tfcA9mijaNemE+7gQ4DlkVd7PHggpUckUFN+faA5vPOTfSEn6T+MEux5ZoTnncnawkgqtu40DhzVV8=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Session
|
||||
method: DELETE
|
||||
response:
|
||||
body: '{"status": "success", "data": {}, "job_id": 4342165013, "msgs": [{"INFO":
|
||||
"logout: Logout successful", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 11:22:47 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
79
vendor/github.com/nesv/go-dynect/dynect/fixtures/convenient_get_a_not_found.yaml
generated
vendored
Normal file
79
vendor/github.com/nesv/go-dynect/dynect/fixtures/convenient_get_a_not_found.yaml
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
---
|
||||
version: 1
|
||||
rwmutex: {}
|
||||
interactions:
|
||||
- request:
|
||||
body: '{"user_name":"dynect-user","password":"p@55w0rd","customer_name":"go-dynect"}'
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- ""
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Session
|
||||
method: POST
|
||||
response:
|
||||
body: '{"status": "success", "data": {"token": "l5QZksz8FRhr+DekJ0SHgoeziztmUOyFYVtVhjS/yOLQSqS/fr72nuCtQhtQtUoJLperzxQ6wid9CIg6i5SOlzBBv2iVeYUAr4ilU1jueUcuS/AYNoRU6O6IBegImDB+nP1+Ao7MekShnUZfUr2e3spRYIUg3eUg60hBa61nT70=",
|
||||
"version": "3.7.9"}, "job_id": 4342199438, "msgs": [{"INFO": "login: Login successful",
|
||||
"SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 11:38:50 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- l5QZksz8FRhr+DekJ0SHgoeziztmUOyFYVtVhjS/yOLQSqS/fr72nuCtQhtQtUoJLperzxQ6wid9CIg6i5SOlzBBv2iVeYUAr4ilU1jueUcuS/AYNoRU6O6IBegImDB+nP1+Ao7MekShnUZfUr2e3spRYIUg3eUg60hBa61nT70=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/AllRecord/go-dynect.test/unknown.go-dynect.test
|
||||
method: GET
|
||||
response:
|
||||
body: '{"status": "failure", "data": {}, "job_id": 4342199445, "msgs": [{"INFO":
|
||||
"node: Node is not in the zone", "SOURCE": "BLL", "ERR_CD": "NOT_FOUND", "LVL":
|
||||
"ERROR"}, {"INFO": "get_tree: Node name not found within the zone", "SOURCE":
|
||||
"BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 11:38:50 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 404 Not Found
|
||||
code: 404
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- l5QZksz8FRhr+DekJ0SHgoeziztmUOyFYVtVhjS/yOLQSqS/fr72nuCtQhtQtUoJLperzxQ6wid9CIg6i5SOlzBBv2iVeYUAr4ilU1jueUcuS/AYNoRU6O6IBegImDB+nP1+Ao7MekShnUZfUr2e3spRYIUg3eUg60hBa61nT70=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Session
|
||||
method: DELETE
|
||||
response:
|
||||
body: '{"status": "success", "data": {}, "job_id": 4342199451, "msgs": [{"INFO":
|
||||
"logout: Logout successful", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 11:38:50 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
104
vendor/github.com/nesv/go-dynect/dynect/fixtures/convenient_get_cname.yaml
generated
vendored
Normal file
104
vendor/github.com/nesv/go-dynect/dynect/fixtures/convenient_get_cname.yaml
generated
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
---
|
||||
version: 1
|
||||
rwmutex: {}
|
||||
interactions:
|
||||
- request:
|
||||
body: '{"user_name":"dynect-user","password":"p@55w0rd","customer_name":"go-dynect"}'
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- ""
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Session
|
||||
method: POST
|
||||
response:
|
||||
body: '{"status": "success", "data": {"token": "JhswjAiu7O3gRKuQlCTCuurkwkdZZ0yYOzTZiUa9Fkr5YlzPmQIQJGtqOKV4dGmaYIkldRpIDbH6muKPDSmoa6TMFv0SNH0+vj6MgGeOqmW2H6vahp6ENWlZICR5ra56OTANL4CNuznc8PAp1e6dQI4yAsfZ9J1ZFKjrajm67K4=",
|
||||
"version": "3.7.9"}, "job_id": 4342161224, "msgs": [{"INFO": "login: Login successful",
|
||||
"SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 11:20:42 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- JhswjAiu7O3gRKuQlCTCuurkwkdZZ0yYOzTZiUa9Fkr5YlzPmQIQJGtqOKV4dGmaYIkldRpIDbH6muKPDSmoa6TMFv0SNH0+vj6MgGeOqmW2H6vahp6ENWlZICR5ra56OTANL4CNuznc8PAp1e6dQI4yAsfZ9J1ZFKjrajm67K4=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/AllRecord/go-dynect.test/foo.go-dynect.test
|
||||
method: GET
|
||||
response:
|
||||
body: '{"status": "success", "data": ["/REST/CNAMERecord/go-dynect.test/foo.go-dynect.test/318905322"],
|
||||
"job_id": 4342161229, "msgs": [{"INFO": "get_tree: Here is your zone tree",
|
||||
"SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 11:20:42 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- JhswjAiu7O3gRKuQlCTCuurkwkdZZ0yYOzTZiUa9Fkr5YlzPmQIQJGtqOKV4dGmaYIkldRpIDbH6muKPDSmoa6TMFv0SNH0+vj6MgGeOqmW2H6vahp6ENWlZICR5ra56OTANL4CNuznc8PAp1e6dQI4yAsfZ9J1ZFKjrajm67K4=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/CNAMERecord/go-dynect.test/foo.go-dynect.test/318905322
|
||||
method: GET
|
||||
response:
|
||||
body: '{"status": "success", "data": {"zone": "go-dynect.test", "ttl": 3600, "fqdn":
|
||||
"foo.go-dynect.test", "record_type": "CNAME", "rdata": {"cname": "foobar.go-dynect.test."},
|
||||
"record_id": 318905322}, "job_id": 4342161235, "msgs": [{"INFO": "get: Found
|
||||
the record", "SOURCE": "API-B", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 11:20:42 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- JhswjAiu7O3gRKuQlCTCuurkwkdZZ0yYOzTZiUa9Fkr5YlzPmQIQJGtqOKV4dGmaYIkldRpIDbH6muKPDSmoa6TMFv0SNH0+vj6MgGeOqmW2H6vahp6ENWlZICR5ra56OTANL4CNuznc8PAp1e6dQI4yAsfZ9J1ZFKjrajm67K4=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Session
|
||||
method: DELETE
|
||||
response:
|
||||
body: '{"status": "success", "data": {}, "job_id": 4342161240, "msgs": [{"INFO":
|
||||
"logout: Logout successful", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 11:20:42 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
269
vendor/github.com/nesv/go-dynect/dynect/fixtures/fetching_all_zone_records.yaml
generated
vendored
Normal file
269
vendor/github.com/nesv/go-dynect/dynect/fixtures/fetching_all_zone_records.yaml
generated
vendored
Normal file
@ -0,0 +1,269 @@
|
||||
---
|
||||
version: 1
|
||||
rwmutex: {}
|
||||
interactions:
|
||||
- request:
|
||||
body: '{"user_name":"dynect-user","password":"p@55w0rd","customer_name":"go-dynect"}'
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- ""
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Session
|
||||
method: POST
|
||||
response:
|
||||
body: '{"status": "success", "data": {"token": "/4dfk/aAs9zK0QqVlmx6VHP+3vAvsevOQ6cGM3+KIO9MFiMAEbc52KBi/ayBwkqGP/N1Ou1Kbf7calZZ4tSvIrmH/7EtTox9qGFbgQkvMLXQz7E4GEZSLd7ejFKjxkZh8ttUSBwzkhQZoBPyy0nry1i/jakCgu09P3eAxPiBJ0U=",
|
||||
"version": "3.7.9"}, "job_id": 4341026959, "msgs": [{"INFO": "login: Login successful",
|
||||
"SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 03:08:58 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- /4dfk/aAs9zK0QqVlmx6VHP+3vAvsevOQ6cGM3+KIO9MFiMAEbc52KBi/ayBwkqGP/N1Ou1Kbf7calZZ4tSvIrmH/7EtTox9qGFbgQkvMLXQz7E4GEZSLd7ejFKjxkZh8ttUSBwzkhQZoBPyy0nry1i/jakCgu09P3eAxPiBJ0U=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/AllRecord/go-dynect.test
|
||||
method: GET
|
||||
response:
|
||||
body: '{"status": "success", "data": ["/REST/CNAMERecord/go-dynect.test/foo.go-dynect.test/318905322",
|
||||
"/REST/SOARecord/go-dynect.test/go-dynect.test/318812133", "/REST/NSRecord/go-dynect.test/go-dynect.test/318812135",
|
||||
"/REST/NSRecord/go-dynect.test/go-dynect.test/318812136", "/REST/NSRecord/go-dynect.test/go-dynect.test/318812137",
|
||||
"/REST/NSRecord/go-dynect.test/go-dynect.test/318812138", "/REST/ARecord/go-dynect.test/foobar.go-dynect.test/318905321"],
|
||||
"job_id": 4341026968, "msgs": [{"INFO": "get_tree: Here is your zone tree",
|
||||
"SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 03:08:58 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- /4dfk/aAs9zK0QqVlmx6VHP+3vAvsevOQ6cGM3+KIO9MFiMAEbc52KBi/ayBwkqGP/N1Ou1Kbf7calZZ4tSvIrmH/7EtTox9qGFbgQkvMLXQz7E4GEZSLd7ejFKjxkZh8ttUSBwzkhQZoBPyy0nry1i/jakCgu09P3eAxPiBJ0U=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/CNAMERecord/go-dynect.test/foo.go-dynect.test/318905322
|
||||
method: GET
|
||||
response:
|
||||
body: '{"status": "success", "data": {"zone": "go-dynect.test", "ttl": 3600, "fqdn":
|
||||
"foo.go-dynect.test", "record_type": "CNAME", "rdata": {"cname": "foobar.go-dynect.test."},
|
||||
"record_id": 318905322}, "job_id": 4341026976, "msgs": [{"INFO": "get: Found
|
||||
the record", "SOURCE": "API-B", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 03:08:58 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- /4dfk/aAs9zK0QqVlmx6VHP+3vAvsevOQ6cGM3+KIO9MFiMAEbc52KBi/ayBwkqGP/N1Ou1Kbf7calZZ4tSvIrmH/7EtTox9qGFbgQkvMLXQz7E4GEZSLd7ejFKjxkZh8ttUSBwzkhQZoBPyy0nry1i/jakCgu09P3eAxPiBJ0U=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/SOARecord/go-dynect.test/go-dynect.test/318812133
|
||||
method: GET
|
||||
response:
|
||||
body: '{"status": "success", "data": {"zone": "go-dynect.test", "ttl": 3600, "fqdn":
|
||||
"go-dynect.test", "record_type": "SOA", "rdata": {"rname": "admin@go-dynect.com.",
|
||||
"retry": 600, "mname": "ns1.p19.dynect.net.", "minimum": 1800, "refresh": 3600,
|
||||
"expire": 604800, "serial": 2017122000}, "record_id": 318812133, "serial_style":
|
||||
"day"}, "job_id": 4341026980, "msgs": [{"INFO": "get: Found the record", "SOURCE":
|
||||
"API-B", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 03:08:58 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- /4dfk/aAs9zK0QqVlmx6VHP+3vAvsevOQ6cGM3+KIO9MFiMAEbc52KBi/ayBwkqGP/N1Ou1Kbf7calZZ4tSvIrmH/7EtTox9qGFbgQkvMLXQz7E4GEZSLd7ejFKjxkZh8ttUSBwzkhQZoBPyy0nry1i/jakCgu09P3eAxPiBJ0U=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/NSRecord/go-dynect.test/go-dynect.test/318812135
|
||||
method: GET
|
||||
response:
|
||||
body: '{"status": "success", "data": {"zone": "go-dynect.test", "service_class":
|
||||
"Primary", "ttl": 86400, "fqdn": "go-dynect.test", "record_type": "NS", "rdata":
|
||||
{"nsdname": "ns1.p19.dynect.net."}, "record_id": 318812135}, "job_id": 4341026990,
|
||||
"msgs": [{"INFO": "get: Found the record", "SOURCE": "API-B", "ERR_CD": null,
|
||||
"LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 03:08:59 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- /4dfk/aAs9zK0QqVlmx6VHP+3vAvsevOQ6cGM3+KIO9MFiMAEbc52KBi/ayBwkqGP/N1Ou1Kbf7calZZ4tSvIrmH/7EtTox9qGFbgQkvMLXQz7E4GEZSLd7ejFKjxkZh8ttUSBwzkhQZoBPyy0nry1i/jakCgu09P3eAxPiBJ0U=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/NSRecord/go-dynect.test/go-dynect.test/318812136
|
||||
method: GET
|
||||
response:
|
||||
body: '{"status": "success", "data": {"zone": "go-dynect.test", "service_class":
|
||||
"Primary", "ttl": 86400, "fqdn": "go-dynect.test", "record_type": "NS", "rdata":
|
||||
{"nsdname": "ns2.p19.dynect.net."}, "record_id": 318812136}, "job_id": 4341026995,
|
||||
"msgs": [{"INFO": "get: Found the record", "SOURCE": "API-B", "ERR_CD": null,
|
||||
"LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 03:08:59 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- /4dfk/aAs9zK0QqVlmx6VHP+3vAvsevOQ6cGM3+KIO9MFiMAEbc52KBi/ayBwkqGP/N1Ou1Kbf7calZZ4tSvIrmH/7EtTox9qGFbgQkvMLXQz7E4GEZSLd7ejFKjxkZh8ttUSBwzkhQZoBPyy0nry1i/jakCgu09P3eAxPiBJ0U=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/NSRecord/go-dynect.test/go-dynect.test/318812137
|
||||
method: GET
|
||||
response:
|
||||
body: '{"status": "success", "data": {"zone": "go-dynect.test", "service_class":
|
||||
"Primary", "ttl": 86400, "fqdn": "go-dynect.test", "record_type": "NS", "rdata":
|
||||
{"nsdname": "ns3.p19.dynect.net."}, "record_id": 318812137}, "job_id": 4341027001,
|
||||
"msgs": [{"INFO": "get: Found the record", "SOURCE": "API-B", "ERR_CD": null,
|
||||
"LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 03:08:59 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- /4dfk/aAs9zK0QqVlmx6VHP+3vAvsevOQ6cGM3+KIO9MFiMAEbc52KBi/ayBwkqGP/N1Ou1Kbf7calZZ4tSvIrmH/7EtTox9qGFbgQkvMLXQz7E4GEZSLd7ejFKjxkZh8ttUSBwzkhQZoBPyy0nry1i/jakCgu09P3eAxPiBJ0U=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/NSRecord/go-dynect.test/go-dynect.test/318812138
|
||||
method: GET
|
||||
response:
|
||||
body: '{"status": "success", "data": {"zone": "go-dynect.test", "service_class":
|
||||
"Primary", "ttl": 86400, "fqdn": "go-dynect.test", "record_type": "NS", "rdata":
|
||||
{"nsdname": "ns4.p19.dynect.net."}, "record_id": 318812138}, "job_id": 4341027006,
|
||||
"msgs": [{"INFO": "get: Found the record", "SOURCE": "API-B", "ERR_CD": null,
|
||||
"LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 03:08:59 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- /4dfk/aAs9zK0QqVlmx6VHP+3vAvsevOQ6cGM3+KIO9MFiMAEbc52KBi/ayBwkqGP/N1Ou1Kbf7calZZ4tSvIrmH/7EtTox9qGFbgQkvMLXQz7E4GEZSLd7ejFKjxkZh8ttUSBwzkhQZoBPyy0nry1i/jakCgu09P3eAxPiBJ0U=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/ARecord/go-dynect.test/foobar.go-dynect.test/318905321
|
||||
method: GET
|
||||
response:
|
||||
body: '{"status": "success", "data": {"zone": "go-dynect.test", "ttl": 3600, "fqdn":
|
||||
"foobar.go-dynect.test", "record_type": "A", "rdata": {"address": "10.9.8.7"},
|
||||
"record_id": 318905321}, "job_id": 4341027017, "msgs": [{"INFO": "get: Found
|
||||
the record", "SOURCE": "API-B", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 03:08:59 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- /4dfk/aAs9zK0QqVlmx6VHP+3vAvsevOQ6cGM3+KIO9MFiMAEbc52KBi/ayBwkqGP/N1Ou1Kbf7calZZ4tSvIrmH/7EtTox9qGFbgQkvMLXQz7E4GEZSLd7ejFKjxkZh8ttUSBwzkhQZoBPyy0nry1i/jakCgu09P3eAxPiBJ0U=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Session
|
||||
method: DELETE
|
||||
response:
|
||||
body: '{"status": "success", "data": {}, "job_id": 4341027020, "msgs": [{"INFO":
|
||||
"logout: Logout successful", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 03:09:00 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
53
vendor/github.com/nesv/go-dynect/dynect/fixtures/login_logout.yaml
generated
vendored
Normal file
53
vendor/github.com/nesv/go-dynect/dynect/fixtures/login_logout.yaml
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
---
|
||||
version: 1
|
||||
rwmutex: {}
|
||||
interactions:
|
||||
- request:
|
||||
body: '{"user_name":"dynect-user","password":"p@55w0rd","customer_name":"go-dynect"}'
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- ""
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Session
|
||||
method: POST
|
||||
response:
|
||||
body: '{"status": "success", "data": {"token": "+cG++GbemK1hoYxrvq2SFGz00mY78zRZhWntTbLxYF42k22o7w/d0Vk+sEvJayq5jSo8ivphahLFmZV8b99TJMRNZFcpFC0NyYeyL/7l8Grsdpplh6l1pMmkInSe3mXVuvgKS5cVSUN5Z8e6DVf9K0Jz/aLZBeL70Qc5VQktaKc=",
|
||||
"version": "3.7.9"}, "job_id": 4340980452, "msgs": [{"INFO": "login: Login successful",
|
||||
"SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 02:46:34 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- +cG++GbemK1hoYxrvq2SFGz00mY78zRZhWntTbLxYF42k22o7w/d0Vk+sEvJayq5jSo8ivphahLFmZV8b99TJMRNZFcpFC0NyYeyL/7l8Grsdpplh6l1pMmkInSe3mXVuvgKS5cVSUN5Z8e6DVf9K0Jz/aLZBeL70Qc5VQktaKc=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Session
|
||||
method: DELETE
|
||||
response:
|
||||
body: '{"status": "success", "data": {}, "job_id": 4340980466, "msgs": [{"INFO":
|
||||
"logout: Logout successful", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 02:46:34 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
79
vendor/github.com/nesv/go-dynect/dynect/fixtures/zones_request.yaml
generated
vendored
Normal file
79
vendor/github.com/nesv/go-dynect/dynect/fixtures/zones_request.yaml
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
---
|
||||
version: 1
|
||||
rwmutex: {}
|
||||
interactions:
|
||||
- request:
|
||||
body: '{"user_name":"dynect-user","password":"p@55w0rd","customer_name":"go-dynect"}'
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- ""
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Session
|
||||
method: POST
|
||||
response:
|
||||
body: '{"status": "success", "data": {"token": "PBz+i35+fKgVUdmzmvGJzcq0F+p+ExJI9Y5fe8VgiJZhFFsY/Vp2KVZb9JBj/CSCewT7rum6IgoBxf8BzK2LuTNzFSgzsWkztKsF+awruRWFdAtl8XfBoG6pIDAcLIgjuE/vUt4WOUH007w6G7FTKt+dojSTK19mw130KtUHik8=",
|
||||
"version": "3.7.9"}, "job_id": 4341009633, "msgs": [{"INFO": "login: Login successful",
|
||||
"SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 03:00:16 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- PBz+i35+fKgVUdmzmvGJzcq0F+p+ExJI9Y5fe8VgiJZhFFsY/Vp2KVZb9JBj/CSCewT7rum6IgoBxf8BzK2LuTNzFSgzsWkztKsF+awruRWFdAtl8XfBoG6pIDAcLIgjuE/vUt4WOUH007w6G7FTKt+dojSTK19mw130KtUHik8=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Zone
|
||||
method: GET
|
||||
response:
|
||||
body: '{"status": "success", "data": ["/REST/Zone/example.com/",
|
||||
"/REST/Zone/example.net", "/REST/Zone/go-dynect.test/"], "job_id": 4341009645,
|
||||
"msgs": [{"INFO": "get: Your 3 zones", "SOURCE": "BLL", "ERR_CD": null,
|
||||
"LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 03:00:18 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
- request:
|
||||
body: ""
|
||||
form: {}
|
||||
headers:
|
||||
Auth-Token:
|
||||
- PBz+i35+fKgVUdmzmvGJzcq0F+p+ExJI9Y5fe8VgiJZhFFsY/Vp2KVZb9JBj/CSCewT7rum6IgoBxf8BzK2LuTNzFSgzsWkztKsF+awruRWFdAtl8XfBoG6pIDAcLIgjuE/vUt4WOUH007w6G7FTKt+dojSTK19mw130KtUHik8=
|
||||
Content-Type:
|
||||
- application/json
|
||||
url: https://api.dynect.net/REST/Session
|
||||
method: DELETE
|
||||
response:
|
||||
body: '{"status": "success", "data": {}, "job_id": 4341009725, "msgs": [{"INFO":
|
||||
"logout: Logout successful", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Wed, 20 Dec 2017 03:00:18 GMT
|
||||
Server:
|
||||
- nginx/1.4.6 (Ubuntu)
|
||||
status: 200 OK
|
||||
code: 200
|
||||
30
vendor/github.com/nesv/go-dynect/dynect/helpers.go
generated
vendored
Normal file
30
vendor/github.com/nesv/go-dynect/dynect/helpers.go
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
package dynect
|
||||
|
||||
import "fmt"
|
||||
|
||||
func GetAllDSFServicesDetailed(c *Client) (error, []DSFService) {
|
||||
var dsfsResponse AllDSFDetailedResponse
|
||||
requestData := struct {
|
||||
Detail string `json:"detail"`
|
||||
}{Detail: "Y"}
|
||||
|
||||
if err := c.Do("GET", "DSF", requestData, &dsfsResponse); err != nil {
|
||||
return err, nil
|
||||
}
|
||||
|
||||
return nil, dsfsResponse.Data
|
||||
}
|
||||
|
||||
func GetDSFServiceDetailed(c *Client, id string) (error, DSFService) {
|
||||
var dsfsResponse DSFResponse
|
||||
requestData := struct {
|
||||
Detail string `json:"detail"`
|
||||
}{Detail: "Y"}
|
||||
|
||||
loc := fmt.Sprintf("DSF/%s", id)
|
||||
|
||||
if err := c.Do("GET", loc, requestData, &dsfsResponse); err != nil {
|
||||
return err, DSFService{}
|
||||
}
|
||||
return nil, dsfsResponse.Data
|
||||
}
|
||||
8
vendor/github.com/nesv/go-dynect/dynect/job.go
generated
vendored
Normal file
8
vendor/github.com/nesv/go-dynect/dynect/job.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
package dynect
|
||||
|
||||
type JobData struct {
|
||||
Status string `json:"status"`
|
||||
Data interface{} `json:"data"`
|
||||
ID int `json:"job_id"`
|
||||
Messages []MessageBlock `json:"msgs"`
|
||||
}
|
||||
65
vendor/github.com/nesv/go-dynect/dynect/json.go
generated
vendored
Normal file
65
vendor/github.com/nesv/go-dynect/dynect/json.go
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
package dynect
|
||||
|
||||
/*
|
||||
This struct represents the request body that would be sent to the DynECT API
|
||||
for logging in and getting a session token for future requests.
|
||||
*/
|
||||
type LoginBlock struct {
|
||||
Username string `json:"user_name"`
|
||||
Password string `json:"password"`
|
||||
CustomerName string `json:"customer_name"`
|
||||
}
|
||||
|
||||
// Type ResponseBlock holds the "header" information returned by any call to
|
||||
// the DynECT API.
|
||||
//
|
||||
// All response-type structs should include this as an anonymous/embedded field.
|
||||
type ResponseBlock struct {
|
||||
Status string `json:"status"`
|
||||
JobId int `json:"job_id,omitempty"`
|
||||
Messages []MessageBlock `json:"msgs,omitempty"`
|
||||
}
|
||||
|
||||
// Type MessageBlock holds the message information from the server, and is
|
||||
// nested within the ResponseBlock type.
|
||||
type MessageBlock struct {
|
||||
Info string `json:"INFO"`
|
||||
Source string `json:"SOURCE"`
|
||||
ErrorCode string `json:"ERR_CD"`
|
||||
Level string `json:"LVL"`
|
||||
}
|
||||
|
||||
// Type LoginResponse holds the data returned by an HTTP POST call to
|
||||
// https://api.dynect.net/REST/Session/.
|
||||
type LoginResponse struct {
|
||||
ResponseBlock
|
||||
Data LoginDataBlock `json:"data"`
|
||||
}
|
||||
|
||||
// Type LoginDataBlock holds the token and API version information from an HTTP
|
||||
// POST call to https://api.dynect.net/REST/Session/.
|
||||
//
|
||||
// It is nested within the LoginResponse struct.
|
||||
type LoginDataBlock struct {
|
||||
Token string `json:"token"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
// RecordRequest holds the request body for a record create/update
|
||||
type RecordRequest struct {
|
||||
RData DataBlock `json:"rdata"`
|
||||
TTL string `json:"ttl,omitempty"`
|
||||
}
|
||||
|
||||
// CreateZoneBlock holds the request body for a zone create
|
||||
type CreateZoneBlock struct {
|
||||
RName string `json:"rname"`
|
||||
SerialStyle string `json:"serial_style,omitempty"`
|
||||
TTL string `json:"ttl"`
|
||||
}
|
||||
|
||||
// PublishZoneBlock holds the request body for a publish zone request
|
||||
// https://help.dyn.com/update-zone-api/
|
||||
type PublishZoneBlock struct {
|
||||
Publish bool `json:"publish"`
|
||||
}
|
||||
12
vendor/github.com/nesv/go-dynect/dynect/record.go
generated
vendored
Normal file
12
vendor/github.com/nesv/go-dynect/dynect/record.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
package dynect
|
||||
|
||||
// Record simple struct to hold record details
|
||||
type Record struct {
|
||||
ID string
|
||||
Zone string
|
||||
Name string
|
||||
Value string
|
||||
Type string
|
||||
FQDN string
|
||||
TTL string
|
||||
}
|
||||
171
vendor/github.com/nesv/go-dynect/dynect/records.go
generated
vendored
Normal file
171
vendor/github.com/nesv/go-dynect/dynect/records.go
generated
vendored
Normal file
@ -0,0 +1,171 @@
|
||||
package dynect
|
||||
|
||||
// Type AllRecordsResponse is a struct for holding a list of all URIs returned
|
||||
// from an HTTP GET call to either https://api.dynect.net/REST/AllRecord/<zone>
|
||||
// or https://api/dynect.net/REST/AllRecord/<zone>/<FQDN>/.
|
||||
type AllRecordsResponse struct {
|
||||
ResponseBlock
|
||||
Data []string `json:"data"`
|
||||
}
|
||||
|
||||
// Type RecordResponse is used to hold the information for a single DNS record
|
||||
// returned from Dyn's DynECT API.
|
||||
type RecordResponse struct {
|
||||
ResponseBlock
|
||||
Data BaseRecord `json:"data"`
|
||||
}
|
||||
|
||||
/*
|
||||
The base struct for record data returned from the Dyn REST API.
|
||||
|
||||
It should never be directly passed to the *Client.Do() function for marshaling
|
||||
response data to. Instead, it should aid in the composition of a more-specific
|
||||
response struct.
|
||||
*/
|
||||
type BaseRecord struct {
|
||||
FQDN string `json:"fqdn"`
|
||||
RecordId int `json:"record_id"`
|
||||
RecordType string `json:"record_type"`
|
||||
TTL int `json:"ttl"`
|
||||
Zone string `json:"zone"`
|
||||
RData DataBlock `json:"rdata"`
|
||||
}
|
||||
|
||||
// Type DataBlock is nested within the BaseRecord struct, and is used for
|
||||
// holding record information.
|
||||
//
|
||||
// The comment above each field indicates which record types you can expect
|
||||
// the information to be provided.
|
||||
type DataBlock struct {
|
||||
// A, AAAA
|
||||
Address string `json:"address,omitempty" bson:"address,omitempty"`
|
||||
|
||||
// ALIAS
|
||||
Alias string `json:"alias,omitempty" bson:"alias,omitempty"`
|
||||
|
||||
// CERT, DNSKEY, DS, IPSECKEY, KEY, SSHFP
|
||||
Algorithm string `json:"algorithm,omitempty" bson:"algorithm,omitempty"`
|
||||
|
||||
// LOC
|
||||
Altitude string `json:"altitude,omitempty" bson:"altitude,omitempty"`
|
||||
|
||||
// CNAME
|
||||
CName string `json:"cname,omitempty" bson:"cname,omitempty"`
|
||||
|
||||
// CERT
|
||||
Certificate string `json:"certificate,omitempty" bson:"algorithm,omitempty"`
|
||||
|
||||
// DNAME
|
||||
DName string `json:"dname,omitempty" bson:"dname,omitempty"`
|
||||
|
||||
// DHCID, DS
|
||||
Digest string `json:"digest,omitempty" bson:"digest,omitempty"`
|
||||
|
||||
// DS
|
||||
DigestType string `json:"digtype,omitempty" bson:"digest_type,omitempty"`
|
||||
|
||||
// KX, MX
|
||||
Exchange string `json:"exchange,omitempty" bson:"exchange,omitempty"`
|
||||
|
||||
// SSHFP
|
||||
FPType string `json:"fptype,omitempty" bson:"fp_type,omitempty"`
|
||||
|
||||
// SSHFP
|
||||
Fingerprint string `json:"fingerprint,omitempty" bson:"fingerprint,omitempty"`
|
||||
|
||||
// DNSKEY, KEY, NAPTR
|
||||
Flags string `json:"flags,omitempty" bson:"flags,omitempty"`
|
||||
|
||||
// CERT
|
||||
Format string `json:"format,omitempty" bson:"format,omitempty"`
|
||||
|
||||
// IPSECKEY
|
||||
GatewayType string `json:"gatetype,omitempty" bson:"gateway_type,omitempty"`
|
||||
|
||||
// LOC
|
||||
HorizPre string `json:"horiz_pre,omitempty" bson:"horiz_pre,omitempty"`
|
||||
|
||||
// DS
|
||||
KeyTag string `json:"keytag,omitempty" bson:"keytag,omitempty"`
|
||||
|
||||
// LOC
|
||||
Latitude string `json:"latitude,omitempty" bson:"latitude,omitempty"`
|
||||
|
||||
// LOC
|
||||
Longitude string `json:"longitude,omitempty" bson:"longitude,omitempty"`
|
||||
|
||||
// PX
|
||||
Map822 string `json:"map822,omitempty" bson:"map_822,omitempty"`
|
||||
|
||||
// PX
|
||||
MapX400 string `json:"mapx400,omitempty" bson:"map_x400,omitempty"`
|
||||
|
||||
// RP
|
||||
Mbox string `json:"mbox,omitempty" bson:"mbox,omitempty"`
|
||||
|
||||
// NS
|
||||
NSDName string `json:"nsdname,omitempty" bson:"nsdname,omitempty"`
|
||||
|
||||
// NSAP
|
||||
NSAP string `json:"nsap,omitempty" bson:"nsap,omitempty"`
|
||||
|
||||
// NAPTR
|
||||
Order string `json:"order,omitempty" bson:"order,omitempty"`
|
||||
|
||||
// SRV
|
||||
Port string `json:"port,omitempty" bson:"port,omitempty"`
|
||||
|
||||
// IPSECKEY
|
||||
Precendence string `json:"precendence,omitempty" bson:"precendence,omitempty"`
|
||||
|
||||
// KX, MX, NAPTR, PX
|
||||
Preference int `json:"preference,omitempty" bson:"preference,omitempty"`
|
||||
|
||||
// SRV
|
||||
Priority int `json:"priority,omitempty" bson:"priority,omitempty"`
|
||||
|
||||
// DNSKEY, KEY
|
||||
Protocol string `json:"protocol,omitempty" bson:"protocol,omitempty"`
|
||||
|
||||
// PTR
|
||||
PTRDname string `json:"ptrdname,omitempty" bson:"ptrdname,omitempty"`
|
||||
|
||||
// DNSKEY, IPSECKEY, KEY
|
||||
PublicKey string `json:"public_key,omitempty" bson:"public_key,omitempty"`
|
||||
|
||||
// NAPTR
|
||||
Regexp string `json:"regexp,omitempty" bson:"regexp,omitempty"`
|
||||
|
||||
// NAPTR
|
||||
Replacement string `json:"replacement,omitempty" bson:"replacement,omitempty"`
|
||||
|
||||
// SOA
|
||||
RName string `json:"rname,omitempty" bson:"rname,omitempty"`
|
||||
|
||||
// NAPTR
|
||||
Services string `json:"services,omitempty" bson:"services,omitempty"`
|
||||
|
||||
// LOC
|
||||
Size string `json:"size,omitempty" bson:"size,omitempty"`
|
||||
|
||||
// CERT
|
||||
Tag string `json:"tag,omitempty" bson:"tag,omitempty"`
|
||||
|
||||
// SRV
|
||||
Target string `json:"target,omitempty" bson:"target,omitempty"`
|
||||
|
||||
// RP
|
||||
TxtDName string `json:"txtdname,omitempty" bson:"txtdname,omitempty"`
|
||||
|
||||
// SPF, TXT
|
||||
TxtData string `json:"txtdata,omitempty" bson:"txtdata,omitempty"`
|
||||
|
||||
// LOC
|
||||
Version string `json:"version,omitempty" bson:"version,omitempty"`
|
||||
|
||||
// LOC
|
||||
VertPre string `json:"vert_pre,omitempty" bson:"vert_pre,omitempty"`
|
||||
|
||||
// SRV
|
||||
Weight string `json:"weight,omitempty" bson:"weight,omitempty"`
|
||||
}
|
||||
9
vendor/github.com/nesv/go-dynect/dynect/zone.go
generated
vendored
Normal file
9
vendor/github.com/nesv/go-dynect/dynect/zone.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
package dynect
|
||||
|
||||
// Zone struct to hold record details
|
||||
type Zone struct {
|
||||
Serial string
|
||||
SerialStyle string
|
||||
Zone string
|
||||
Type string
|
||||
}
|
||||
24
vendor/github.com/nesv/go-dynect/dynect/zones.go
generated
vendored
Normal file
24
vendor/github.com/nesv/go-dynect/dynect/zones.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
package dynect
|
||||
|
||||
// ZonesResponse is used for holding the data returned by a call to
|
||||
// "https://api.dynect.net/REST/Zone/".
|
||||
type ZonesResponse struct {
|
||||
ResponseBlock
|
||||
Data []string `json:"data"`
|
||||
}
|
||||
|
||||
// ZoneResponse is used for holding the data returned by a call to
|
||||
// "https://api.dynect.net/REST/Zone/ZONE_NAME".
|
||||
type ZoneResponse struct {
|
||||
ResponseBlock
|
||||
Data ZoneDataBlock `json:"data"`
|
||||
}
|
||||
|
||||
// Type ZoneDataBlock is used as a nested struct, which holds the data for a
|
||||
// zone returned by a call to "https://api.dynect.net/REST/Zone/ZONE_NAME".
|
||||
type ZoneDataBlock struct {
|
||||
Serial int `json:"serial"`
|
||||
SerialStyle string `json:"serial_style"`
|
||||
Zone string `json:"zone"`
|
||||
ZoneType string `json:"zone_type"`
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user