1
0
mirror of https://github.com/StackExchange/dnscontrol.git synced 2024-05-11 05:55:12 +00:00

Ns1 provider (#63)

* add ns1 libs to vendor

* Create shim and wire into tests

* ns1 provider more working.

* vendor correct files

* comment diff functions

* ns1 docs

* making mx work with ns1

* ?

* refactor tests to make capability blocks easier. fix up ns1
This commit is contained in:
Craig Peterson
2017-09-13 11:49:15 -04:00
committed by GitHub
parent bf85e299e7
commit b0c465c3a9
46 changed files with 3784 additions and 89 deletions

37
docs/_providers/ns1.md Normal file
View File

@ -0,0 +1,37 @@
---
name: NS1
layout: default
jsId: NS1
---
# NS1 Provider
NS1 provides a dns provider implementation for ns1 dns.
## Configuration
In your providers config json file you must provide your ns1 api key:
{% highlight json %}
{
"ns1":{
"api_token": "your-ns1-token"
}
}
{% endhighlight %}
## Metadata
This provider does not recognize any special metadata fields unique to ns1.
## Usage
Example javascript:
{% highlight js %}
var NS1 = NewDnsProvider("ns1", "NS1");
D("example.tld", MY_REGISTRAR, DnsProvider(NS1),
A("test","1.2.3.4")
);
{% endhighlight %}

View File

@ -88,6 +88,7 @@ func runTests(t *testing.T, prv providers.DNSServiceProvider, domainName string,
dc := getDomainConfigWithNameservers(t, prv, domainName)
// run tests one at a time
end := *endIdx
tests := makeTests(t)
if end == 0 || end >= len(tests) {
end = len(tests) - 1
}
@ -97,10 +98,6 @@ func runTests(t *testing.T, prv providers.DNSServiceProvider, domainName string,
break
}
t.Run(fmt.Sprintf("%d: %s", i, tst.Desc), func(t *testing.T) {
if tst.SkipUnless != 0 && !providers.ProviderHasCabability(*providerToRun, tst.SkipUnless) {
t.Log("Skipping because provider does not support test features")
return
}
skipVal := false
if knownFailures[i] {
t.Log("SKIPPING VALIDATION FOR KNOWN FAILURE CASE")
@ -198,9 +195,8 @@ func TestDualProviders(t *testing.T) {
}
type TestCase struct {
Desc string
Records []*rec
SkipUnless providers.Capability
Desc string
Records []*rec
}
type rec models.RecordConfig
@ -275,95 +271,119 @@ func manyA(namePattern, target string, n int) []*rec {
return recs
}
func (tc *TestCase) IfHasCapability(c providers.Capability) *TestCase {
tc.SkipUnless = c
return tc
}
func makeTests(t *testing.T) []*TestCase {
//ALWAYS ADD TO BOTTOM OF LIST. Order and indexes matter.
tests := []*TestCase{
// A
tc("Empty"),
tc("Create an A record", a("@", "1.1.1.1")),
tc("Change it", a("@", "1.2.3.4")),
tc("Add another", a("@", "1.2.3.4"), a("www", "1.2.3.4")),
tc("Add another(same name)", a("@", "1.2.3.4"), a("www", "1.2.3.4"), a("www", "5.6.7.8")),
tc("Change a ttl", a("@", "1.2.3.4").ttl(1000), a("www", "1.2.3.4"), a("www", "5.6.7.8")),
tc("Change single target from set", a("@", "1.2.3.4").ttl(1000), a("www", "2.2.2.2"), a("www", "5.6.7.8")),
tc("Change all ttls", a("@", "1.2.3.4").ttl(500), a("www", "2.2.2.2").ttl(400), a("www", "5.6.7.8").ttl(400)),
tc("Delete one", a("@", "1.2.3.4").ttl(500), a("www", "5.6.7.8").ttl(400)),
tc("Add back and change ttl", a("www", "5.6.7.8").ttl(700), a("www", "1.2.3.4").ttl(700)),
tc("Change targets and ttls", a("www", "1.1.1.1"), a("www", "2.2.2.2")),
//ALWAYS ADD TO BOTTOM OF LIST. Order and indexes matter.
var tests = []*TestCase{
// A
tc("Empty"),
tc("Create an A record", a("@", "1.1.1.1")),
tc("Change it", a("@", "1.2.3.4")),
tc("Add another", a("@", "1.2.3.4"), a("www", "1.2.3.4")),
tc("Add another(same name)", a("@", "1.2.3.4"), a("www", "1.2.3.4"), a("www", "5.6.7.8")),
tc("Change a ttl", a("@", "1.2.3.4").ttl(1000), a("www", "1.2.3.4"), a("www", "5.6.7.8")),
tc("Change single target from set", a("@", "1.2.3.4").ttl(1000), a("www", "2.2.2.2"), a("www", "5.6.7.8")),
tc("Change all ttls", a("@", "1.2.3.4").ttl(500), a("www", "2.2.2.2").ttl(400), a("www", "5.6.7.8").ttl(400)),
tc("Delete one", a("@", "1.2.3.4").ttl(500), a("www", "5.6.7.8").ttl(400)),
tc("Add back and change ttl", a("www", "5.6.7.8").ttl(700), a("www", "1.2.3.4").ttl(700)),
tc("Change targets and ttls", a("www", "1.1.1.1"), a("www", "2.2.2.2")),
// CNAMES
tc("Empty"),
tc("Create a CNAME", cname("foo", "google.com.")),
tc("Change it", cname("foo", "google2.com.")),
tc("Change to A record", a("foo", "1.2.3.4")),
tc("Change back to CNAME", cname("foo", "google.com.")),
tc("Record pointing to @", cname("foo", "**current-domain**")),
// CNAMES
tc("Empty"),
tc("Create a CNAME", cname("foo", "google.com.")),
tc("Change it", cname("foo", "google2.com.")),
tc("Change to A record", a("foo", "1.2.3.4")),
tc("Change back to CNAME", cname("foo", "google.com.")),
tc("Record pointing to @", cname("foo", "**current-domain**")),
//NS
tc("Empty"),
tc("NS for subdomain", ns("xyz", "ns2.foo.com.")),
tc("Dual NS for subdomain", ns("xyz", "ns2.foo.com."), ns("xyz", "ns1.foo.com.")),
tc("Record pointing to @", ns("foo", "**current-domain**")),
//NS
tc("Empty"),
tc("NS for subdomain", ns("xyz", "ns2.foo.com.")),
tc("Dual NS for subdomain", ns("xyz", "ns2.foo.com."), ns("xyz", "ns1.foo.com.")),
tc("Record pointing to @", ns("foo", "**current-domain**")),
//IDNAs
tc("Empty"),
tc("Internationalized name", a("ööö", "1.2.3.4")),
tc("Change IDN", a("ööö", "2.2.2.2")),
tc("Internationalized CNAME Target", cname("a", "ööö.com.")),
tc("IDN CNAME AND Target", cname("öoö", "ööö.企业.")),
//IDNAs
tc("Empty"),
tc("Internationalized name", a("ööö", "1.2.3.4")),
tc("Change IDN", a("ööö", "2.2.2.2")),
tc("Internationalized CNAME Target", cname("a", "ööö.com.")),
tc("IDN CNAME AND Target", cname("öoö", "ööö.企业.")),
//MX
tc("Empty"),
tc("MX record", mx("@", 5, "foo.com.")),
tc("Second MX record, same prio", mx("@", 5, "foo.com."), mx("@", 5, "foo2.com.")),
tc("3 MX", mx("@", 5, "foo.com."), mx("@", 5, "foo2.com."), mx("@", 15, "foo3.com.")),
tc("Delete one", mx("@", 5, "foo2.com."), mx("@", 15, "foo3.com.")),
tc("Change to other name", mx("@", 5, "foo2.com."), mx("mail", 15, "foo3.com.")),
tc("Change Preference", mx("@", 7, "foo2.com."), mx("mail", 15, "foo3.com.")),
tc("Record pointing to @", mx("foo", 8, "**current-domain**")),
}
//MX
tc("Empty"),
tc("MX record", mx("@", 5, "foo.com.")),
tc("Second MX record, same prio", mx("@", 5, "foo.com."), mx("@", 5, "foo2.com.")),
tc("3 MX", mx("@", 5, "foo.com."), mx("@", 5, "foo2.com."), mx("@", 15, "foo3.com.")),
tc("Delete one", mx("@", 5, "foo2.com."), mx("@", 15, "foo3.com.")),
tc("Change to other name", mx("@", 5, "foo2.com."), mx("mail", 15, "foo3.com.")),
tc("Change Preference", mx("@", 7, "foo2.com."), mx("mail", 15, "foo3.com.")),
tc("Record pointing to @", mx("foo", 8, "**current-domain**")),
// PTR
if !providers.ProviderHasCabability(*providerToRun, providers.CanUsePTR) {
t.Log("Skipping PTR Tests because provider does not support them")
} else {
tests = append(tests, tc("Empty"),
tc("Create PTR record", ptr("4", "foo.com.")),
tc("Modify PTR record", ptr("4", "bar.com.")),
)
}
//PTR
tc("Empty").IfHasCapability(providers.CanUsePTR),
tc("Create PTR record", ptr("4", "foo.com.")).IfHasCapability(providers.CanUsePTR),
tc("Modify PTR record", ptr("4", "bar.com.")).IfHasCapability(providers.CanUsePTR),
// ALIAS
if !providers.ProviderHasCabability(*providerToRun, providers.CanUseAlias) {
t.Log("Skipping ALIAS Tests because provider does not support them")
} else {
tests = append(tests, tc("Empty"),
tc("ALIAS at root", alias("@", "foo.com.")),
tc("change it", alias("@", "foo2.com.")),
tc("ALIAS at subdomain", alias("test", "foo.com.")),
)
}
//ALIAS
tc("Empty").IfHasCapability(providers.CanUseAlias),
tc("ALIAS at root", alias("@", "foo.com.")).IfHasCapability(providers.CanUseAlias),
tc("change it", alias("@", "foo2.com.")).IfHasCapability(providers.CanUseAlias),
tc("ALIAS at subdomain", alias("test", "foo.com.")).IfHasCapability(providers.CanUseAlias),
// SRV
if !providers.ProviderHasCabability(*providerToRun, providers.CanUseSRV) {
t.Log("Skipping SRV Tests because provider does not support them")
} else {
tests = append(tests, tc("Empty"),
tc("SRV record", srv("_sip._tcp", 5, 6, 7, "foo.com.")),
tc("Second SRV record, same prio", srv("_sip._tcp", 5, 6, 7, "foo.com."), srv("_sip._tcp", 5, 60, 70, "foo2.com.")),
tc("3 SRV", srv("_sip._tcp", 5, 6, 7, "foo.com."), srv("_sip._tcp", 5, 60, 70, "foo2.com."), srv("_sip._tcp", 15, 65, 75, "foo3.com.")),
tc("Delete one", srv("_sip._tcp", 5, 6, 7, "foo.com."), srv("_sip._tcp", 15, 65, 75, "foo3.com.")),
tc("Change Target", srv("_sip._tcp", 5, 6, 7, "foo.com."), srv("_sip._tcp", 15, 65, 75, "foo4.com.")),
tc("Change Priority", srv("_sip._tcp", 52, 6, 7, "foo.com."), srv("_sip._tcp", 15, 65, 75, "foo4.com.")),
tc("Change Weight", srv("_sip._tcp", 52, 62, 7, "foo.com."), srv("_sip._tcp", 15, 65, 75, "foo4.com.")),
tc("Change Port", srv("_sip._tcp", 52, 62, 72, "foo.com."), srv("_sip._tcp", 15, 65, 75, "foo4.com.")),
)
}
//SRV
tc("Empty").IfHasCapability(providers.CanUseSRV),
tc("SRV record", srv("_sip._tcp", 5, 6, 7, "foo.com.")).IfHasCapability(providers.CanUseSRV),
tc("Second SRV record, same prio", srv("_sip._tcp", 5, 6, 7, "foo.com."), srv("_sip._tcp", 5, 60, 70, "foo2.com.")).IfHasCapability(providers.CanUseSRV),
tc("3 SRV", srv("_sip._tcp", 5, 6, 7, "foo.com."), srv("_sip._tcp", 5, 60, 70, "foo2.com."), srv("_sip._tcp", 15, 65, 75, "foo3.com.")).IfHasCapability(providers.CanUseSRV),
tc("Delete one", srv("_sip._tcp", 5, 6, 7, "foo.com."), srv("_sip._tcp", 15, 65, 75, "foo3.com.")).IfHasCapability(providers.CanUseSRV),
tc("Change Target", srv("_sip._tcp", 5, 6, 7, "foo.com."), srv("_sip._tcp", 15, 65, 75, "foo4.com.")).IfHasCapability(providers.CanUseSRV),
tc("Change Priority", srv("_sip._tcp", 52, 6, 7, "foo.com."), srv("_sip._tcp", 15, 65, 75, "foo4.com.")).IfHasCapability(providers.CanUseSRV),
tc("Change Weight", srv("_sip._tcp", 52, 62, 7, "foo.com."), srv("_sip._tcp", 15, 65, 75, "foo4.com.")).IfHasCapability(providers.CanUseSRV),
tc("Change Port", srv("_sip._tcp", 52, 62, 72, "foo.com."), srv("_sip._tcp", 15, 65, 75, "foo4.com.")).IfHasCapability(providers.CanUseSRV),
//CAA
tc("Empty").IfHasCapability(providers.CanUseCAA),
tc("CAA record", caa("@", "issue", 0, "letsencrypt.org")).IfHasCapability(providers.CanUseCAA),
tc("CAA change tag", caa("@", "issuewild", 0, "letsencrypt.org")).IfHasCapability(providers.CanUseCAA),
tc("CAA change target", caa("@", "issuewild", 0, "example.com")).IfHasCapability(providers.CanUseCAA),
tc("CAA change flag", caa("@", "issuewild", 128, "example.com")).IfHasCapability(providers.CanUseCAA),
tc("CAA many records", caa("@", "issue", 0, "letsencrypt.org"), caa("@", "issuewild", 0, ";"), caa("@", "iodef", 128, "mailto:test@example.com")).IfHasCapability(providers.CanUseCAA),
tc("CAA delete", caa("@", "issue", 0, "letsencrypt.org")).IfHasCapability(providers.CanUseCAA),
// CAA
if !providers.ProviderHasCabability(*providerToRun, providers.CanUseCAA) {
t.Log("Skipping CAA Tests because provider does not support them")
} else {
tests = append(tests, tc("Empty"),
tc("CAA record", caa("@", "issue", 0, "letsencrypt.org")),
tc("CAA change tag", caa("@", "issuewild", 0, "letsencrypt.org")),
tc("CAA change target", caa("@", "issuewild", 0, "example.com")),
tc("CAA change flag", caa("@", "issuewild", 128, "example.com")),
tc("CAA many records", caa("@", "issue", 0, "letsencrypt.org"), caa("@", "issuewild", 0, ";"), caa("@", "iodef", 128, "mailto:test@example.com")),
tc("CAA delete", caa("@", "issue", 0, "letsencrypt.org")),
)
}
// Test large zonefiles.
// Gandi pages 100 items at a time.
tc("Empty"),
tc("99 records", manyA("rec%04d", "1.2.3.4", 99)...),
tc("100 records", manyA("rec%04d", "1.2.3.4", 100)...),
tc("101 records", manyA("rec%04d", "1.2.3.4", 101)...),
// Mostly to test paging. Many providers page at 100
skip := map[string]bool{
"NS1": true, //ns1 free acct only allows 50 records
}
if skip[*providerToRun] {
t.Log("Skipping Large record count Tests because provider does not support them")
} else {
tests = append(tests, tc("Empty"),
tc("99 records", manyA("rec%04d", "1.2.3.4", 99)...),
tc("100 records", manyA("rec%04d", "1.2.3.4", 100)...),
tc("101 records", manyA("rec%04d", "1.2.3.4", 101)...),
)
}
//TODO: in validation, check that everything is given in unicode. This case hurts too much.
//tc("IDN pre-punycoded", cname("xn--o-0gab", "xn--o-0gab.xn--o-0gab.")),
return tests
}

View File

@ -35,6 +35,10 @@
"private_key": "$GCLOUD_PRIVATEKEY",
"project_id": "$GCLOUD_PROJECT"
},
"NS1": {
"domain": "$NS1_DOMAIN",
"api_token": "$NS1_TOKEN"
},
"NAMEDOTCOM": {
"apikey": "$NAMEDOTCOM_KEY",
"apiurl": "$NAMEDOTCOM_URL",
@ -46,4 +50,4 @@
"SecretKey": "$R53_KEY",
"domain": "$R53_DOMAIN"
}
}
}

View File

@ -225,6 +225,25 @@ func atou32(s string) uint32 {
return uint32(i64)
}
type Records []*RecordConfig
func (r Records) Grouped() map[RecordKey]Records {
groups := map[RecordKey]Records{}
for _, rec := range r {
groups[rec.Key()] = append(groups[rec.Key()], rec)
}
return groups
}
type RecordKey struct {
Name string
Type string
}
func (r *RecordConfig) Key() RecordKey {
return RecordKey{r.Name, r.Type}
}
type Nameserver struct {
Name string `json:"name"` // Normalized to a FQDN with NO trailing "."
Target string `json:"target"`
@ -243,7 +262,7 @@ type DomainConfig struct {
Registrar string `json:"registrar"`
DNSProviders map[string]int `json:"dnsProviders"`
Metadata map[string]string `json:"meta,omitempty"`
Records []*RecordConfig `json:"records"`
Records Records `json:"records"`
Nameservers []*Nameserver `json:"nameservers,omitempty"`
KeepUnknown bool `json:"keepunknown,omitempty"`
}

View File

@ -12,5 +12,6 @@ import (
_ "github.com/StackExchange/dnscontrol/providers/google"
_ "github.com/StackExchange/dnscontrol/providers/namecheap"
_ "github.com/StackExchange/dnscontrol/providers/namedotcom"
_ "github.com/StackExchange/dnscontrol/providers/ns1"
_ "github.com/StackExchange/dnscontrol/providers/route53"
)

View File

@ -16,7 +16,11 @@ type Correlation struct {
type Changeset []Correlation
type Differ interface {
//IncrementalDiff performs a diff on a record-by-record basis, and returns a sets for which records need to be created, deleted, or modified.
IncrementalDiff(existing []*models.RecordConfig) (unchanged, create, toDelete, modify Changeset)
// ChangedGroups performs a diff more appropriate for providers with a "RecordSet" model, where all records with the same name and type are grouped.
// Individual record changes are often not useful in such scenarios. Instead we return a map of record keys to a list of change descriptions within that group.
ChangedGroups(existing []*models.RecordConfig) map[models.RecordKey][]string
}
func New(dc *models.DomainConfig, extraValues ...func(*models.RecordConfig) map[string]string) Differ {
@ -154,6 +158,21 @@ func (d *differ) IncrementalDiff(existing []*models.RecordConfig) (unchanged, cr
return
}
func (d *differ) ChangedGroups(existing []*models.RecordConfig) map[models.RecordKey][]string {
changedKeys := map[models.RecordKey][]string{}
_, create, delete, modify := d.IncrementalDiff(existing)
for _, c := range create {
changedKeys[c.Desired.Key()] = append(changedKeys[c.Desired.Key()], c.String())
}
for _, d := range delete {
changedKeys[d.Existing.Key()] = append(changedKeys[d.Existing.Key()], d.String())
}
for _, m := range modify {
changedKeys[m.Desired.Key()] = append(changedKeys[m.Desired.Key()], m.String())
}
return changedKeys
}
func (c Correlation) String() string {
if c.Existing == nil {
return fmt.Sprintf("CREATE %s %s %s", c.Desired.Type, c.Desired.NameFQDN, c.d.content(c.Desired))

View File

@ -0,0 +1,145 @@
package ns1
import (
"encoding/json"
"fmt"
"github.com/StackExchange/dnscontrol/models"
"github.com/StackExchange/dnscontrol/providers"
"net/http"
"strings"
"github.com/StackExchange/dnscontrol/providers/diff"
"github.com/miekg/dns/dnsutil"
"gopkg.in/ns1/ns1-go.v2/rest"
"gopkg.in/ns1/ns1-go.v2/rest/model/dns"
)
func init() {
providers.RegisterDomainServiceProviderType("NS1", newProvider)
}
type nsone struct {
*rest.Client
}
func newProvider(creds map[string]string, meta json.RawMessage) (providers.DNSServiceProvider, error) {
if creds["api_token"] == "" {
return nil, fmt.Errorf("api_token required for ns1")
}
return &nsone{rest.NewClient(http.DefaultClient, rest.SetAPIKey(creds["api_token"]))}, nil
}
func (n *nsone) GetNameservers(domain string) ([]*models.Nameserver, error) {
z, _, err := n.Zones.Get(domain)
if err != nil {
return nil, err
}
return models.StringsToNameservers(z.DNSServers), nil
}
func (n *nsone) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
dc.Punycode()
dc.CombineMXs()
z, _, err := n.Zones.Get(dc.Name)
if err != nil {
return nil, err
}
found := models.Records{}
for _, r := range z.Records {
zrs, err := convert(r, dc.Name)
if err != nil {
return nil, err
}
found = append(found, zrs...)
}
foundGrouped := found.Grouped()
desiredGrouped := dc.Records.Grouped()
differ := diff.New(dc)
changedGroups := differ.ChangedGroups(found)
corrections := []*models.Correction{}
// each name/type is given to the api as a unit.
for k, descs := range changedGroups {
key := k
desc := strings.Join(descs, "\n")
_, current := foundGrouped[k]
recs, wanted := desiredGrouped[k]
if wanted && !current {
// pure addition
corrections = append(corrections, &models.Correction{
Msg: desc,
F: func() error { return n.add(recs, dc.Name) },
})
} else if current && !wanted {
// pure deletion
corrections = append(corrections, &models.Correction{
Msg: desc,
F: func() error { return n.remove(key, dc.Name) },
})
} else {
// modification
corrections = append(corrections, &models.Correction{
Msg: desc,
F: func() error { return n.modify(recs, dc.Name) },
})
}
}
return corrections, nil
}
func (n *nsone) add(recs models.Records, domain string) error {
_, err := n.Records.Create(buildRecord(recs, domain, ""))
return err
}
func (n *nsone) remove(key models.RecordKey, domain string) error {
_, err := n.Records.Delete(domain, dnsutil.AddOrigin(key.Name, domain), key.Type)
return err
}
func (n *nsone) modify(recs models.Records, domain string) error {
_, err := n.Records.Update(buildRecord(recs, domain, ""))
return err
}
func buildRecord(recs models.Records, domain string, id string) *dns.Record {
r := recs[0]
rec := &dns.Record{
Domain: r.NameFQDN,
Type: r.Type,
ID: id,
TTL: int(r.TTL),
Zone: domain,
}
for _, r := range recs {
ans := &dns.Answer{
Rdata: strings.Split(r.Target, " "),
}
rec.AddAnswer(ans)
}
return rec
}
func convert(zr *dns.ZoneRecord, domain string) ([]*models.RecordConfig, error) {
found := []*models.RecordConfig{}
for _, ans := range zr.ShortAns {
rec := &models.RecordConfig{
NameFQDN: zr.Domain,
Name: dnsutil.TrimDomainName(zr.Domain, domain),
TTL: uint32(zr.TTL),
Target: ans,
Original: zr,
Type: zr.Type,
}
if zr.Type == "MX" {
rec.CombinedTarget = true
}
found = append(found, rec)
}
return found, nil
}

678
vendor/gopkg.in/ns1/ns1-go.v2/LICENSE.txt generated vendored Normal file
View File

@ -0,0 +1,678 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
APACHE HTTP SERVER SUBCOMPONENTS:
The Apache HTTP Server includes a number of subcomponents with
separate copyright notices and license terms. Your use of the source
code for the these subcomponents is subject to the terms and
conditions of the following licenses.
For the mod_mime_magic component:
/*
* mod_mime_magic: MIME type lookup via file magic numbers
* Copyright (c) 1996-1997 Cisco Systems, Inc.
*
* This software was submitted by Cisco Systems to the Apache Group in July
* 1997. Future revisions and derivatives of this source code must
* acknowledge Cisco Systems as the original contributor of this module.
* All other licensing and usage conditions are those of the Apache Group.
*
* Some of this code is derived from the free version of the file command
* originally posted to comp.sources.unix. Copyright info for that program
* is included below as required.
* ---------------------------------------------------------------------------
* - Copyright (c) Ian F. Darwin, 1987. Written by Ian F. Darwin.
*
* This software is not subject to any license of the American Telephone and
* Telegraph Company or of the Regents of the University of California.
*
* Permission is granted to anyone to use this software for any purpose on any
* computer system, and to alter it and redistribute it freely, subject to
* the following restrictions:
*
* 1. The author is not responsible for the consequences of use of this
* software, no matter how awful, even if they arise from flaws in it.
*
* 2. The origin of this software must not be misrepresented, either by
* explicit claim or by omission. Since few users ever read sources, credits
* must appear in the documentation.
*
* 3. Altered versions must be plainly marked as such, and must not be
* misrepresented as being the original software. Since few users ever read
* sources, credits must appear in the documentation.
*
* 4. This notice may not be removed or altered.
* -------------------------------------------------------------------------
*
*/
For the modules\mappers\mod_imap.c component:
"macmartinized" polygon code copyright 1992 by Eric Haines, erich@eye.com
For the server\util_md5.c component:
/************************************************************************
* NCSA HTTPd Server
* Software Development Group
* National Center for Supercomputing Applications
* University of Illinois at Urbana-Champaign
* 605 E. Springfield, Champaign, IL 61820
* httpd@ncsa.uiuc.edu
*
* Copyright (C) 1995, Board of Trustees of the University of Illinois
*
************************************************************************
*
* md5.c: NCSA HTTPd code which uses the md5c.c RSA Code
*
* Original Code Copyright (C) 1994, Jeff Hostetler, Spyglass, Inc.
* Portions of Content-MD5 code Copyright (C) 1993, 1994 by Carnegie Mellon
* University (see Copyright below).
* Portions of Content-MD5 code Copyright (C) 1991 Bell Communications
* Research, Inc. (Bellcore) (see Copyright below).
* Portions extracted from mpack, John G. Myers - jgm+@cmu.edu
* Content-MD5 Code contributed by Martin Hamilton (martin@net.lut.ac.uk)
*
*/
/* these portions extracted from mpack, John G. Myers - jgm+@cmu.edu */
/* (C) Copyright 1993,1994 by Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Carnegie
* Mellon University not be used in advertising or publicity
* pertaining to distribution of the software without specific,
* written prior permission. Carnegie Mellon University makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
* CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
/*
* Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
*
* Permission to use, copy, modify, and distribute this material
* for any purpose and without fee is hereby granted, provided
* that the above copyright notice and this permission notice
* appear in all copies, and that the name of Bellcore not be
* used in advertising or publicity pertaining to this
* material without the specific, prior written permission
* of an authorized representative of Bellcore. BELLCORE
* MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY
* OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS",
* WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
*/
For the srclib\apr\include\apr_md5.h component:
/*
* This is work is derived from material Copyright RSA Data Security, Inc.
*
* The RSA copyright statement and Licence for that original material is
* included below. This is followed by the Apache copyright statement and
* licence for the modifications made to that material.
*/
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
For the srclib\apr\passwd\apr_md5.c component:
/*
* This is work is derived from material Copyright RSA Data Security, Inc.
*
* The RSA copyright statement and Licence for that original material is
* included below. This is followed by the Apache copyright statement and
* licence for the modifications made to that material.
*/
/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
*/
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
/*
* The apr_md5_encode() routine uses much code obtained from the FreeBSD 3.0
* MD5 crypt() function, which is licenced as follows:
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
* ----------------------------------------------------------------------------
*/
For the srclib\apr-util\crypto\apr_md4.c component:
* This is derived from material copyright RSA Data Security, Inc.
* Their notice is reproduced below in its entirety.
*
* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
* rights reserved.
*
* License to copy and use this software is granted provided that it
* is identified as the "RSA Data Security, Inc. MD4 Message-Digest
* Algorithm" in all material mentioning or referencing this software
* or this function.
*
* License is also granted to make and use derivative works provided
* that such works are identified as "derived from the RSA Data
* Security, Inc. MD4 Message-Digest Algorithm" in all material
* mentioning or referencing the derived work.
*
* RSA Data Security, Inc. makes no representations concerning either
* the merchantability of this software or the suitability of this
* software for any particular purpose. It is provided "as is"
* without express or implied warranty of any kind.
*
* These notices must be retained in any copies of any part of this
* documentation and/or software.
*/
For the srclib\apr-util\include\apr_md4.h component:
*
* This is derived from material copyright RSA Data Security, Inc.
* Their notice is reproduced below in its entirety.
*
* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
* rights reserved.
*
* License to copy and use this software is granted provided that it
* is identified as the "RSA Data Security, Inc. MD4 Message-Digest
* Algorithm" in all material mentioning or referencing this software
* or this function.
*
* License is also granted to make and use derivative works provided
* that such works are identified as "derived from the RSA Data
* Security, Inc. MD4 Message-Digest Algorithm" in all material
* mentioning or referencing the derived work.
*
* RSA Data Security, Inc. makes no representations concerning either
* the merchantability of this software or the suitability of this
* software for any particular purpose. It is provided "as is"
* without express or implied warranty of any kind.
*
* These notices must be retained in any copies of any part of this
* documentation and/or software.
*/
For the srclib\apr-util\test\testdbm.c component:
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-2002 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* This file came from the SDBM package (written by oz@nexus.yorku.ca).
* That package was under public domain. This file has been ported to
* APR, updated to ANSI C and other, newer idioms, and added to the Apache
* codebase under the above copyright and license.
*/
For the srclib\apr-util\test\testmd4.c component:
*
* This is derived from material copyright RSA Data Security, Inc.
* Their notice is reproduced below in its entirety.
*
* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
* rights reserved.
*
* RSA Data Security, Inc. makes no representations concerning either
* the merchantability of this software or the suitability of this
* software for any particular purpose. It is provided "as is"
* without express or implied warranty of any kind.
*
* These notices must be retained in any copies of any part of this
* documentation and/or software.
*/
For the srclib\apr-util\xml\expat\conftools\install-sh component:
#
# install - install a program, script, or datafile
# This comes from X11R5 (mit/util/scripts/install.sh).
#
# Copyright 1991 by the Massachusetts Institute of Technology
#
# Permission to use, copy, modify, distribute, and sell this software and its
# documentation for any purpose is hereby granted without fee, provided that
# the above copyright notice appear in all copies and that both that
# copyright notice and this permission notice appear in supporting
# documentation, and that the name of M.I.T. not be used in advertising or
# publicity pertaining to distribution of the software without specific,
# written prior permission. M.I.T. makes no representations about the
# suitability of this software for any purpose. It is provided "as is"
# without express or implied warranty.
#
For the srclib\pcre\install-sh component:
#
# Copyright 1991 by the Massachusetts Institute of Technology
#
# Permission to use, copy, modify, distribute, and sell this software and its
# documentation for any purpose is hereby granted without fee, provided that
# the above copyright notice appear in all copies and that both that
# copyright notice and this permission notice appear in supporting
# documentation, and that the name of M.I.T. not be used in advertising or
# publicity pertaining to distribution of the software without specific,
# written prior permission. M.I.T. makes no representations about the
# suitability of this software for any purpose. It is provided "as is"
# without express or implied warranty.
For the pcre component:
PCRE LICENCE
------------
PCRE is a library of functions to support regular expressions whose syntax
and semantics are as close as possible to those of the Perl 5 language.
Written by: Philip Hazel <ph10@cam.ac.uk>
University of Cambridge Computing Service,
Cambridge, England. Phone: +44 1223 334714.
Copyright (c) 1997-2001 University of Cambridge
Permission is granted to anyone to use this software for any purpose on any
computer system, and to redistribute it freely, subject to the following
restrictions:
1. This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
2. The origin of this software must not be misrepresented, either by
explicit claim or by omission. In practice, this means that if you use
PCRE in software which you distribute to others, commercially or
otherwise, you must put a sentence like this
Regular expression support is provided by the PCRE library package,
which is open source software, written by Philip Hazel, and copyright
by the University of Cambridge, England.
somewhere reasonably visible in your documentation and in any relevant
files or online help data or similar. A reference to the ftp site for
the source, that is, to
ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/
should also be given in the documentation.
3. Altered versions must be plainly marked as such, and must not be
misrepresented as being the original software.
4. If PCRE is embedded in any software that is released under the GNU
General Purpose Licence (GPL), or Lesser General Purpose Licence (LGPL),
then the terms of that licence shall supersede any condition above with
which it is incompatible.
The documentation for PCRE, supplied in the "doc" directory, is distributed
under the same terms as the software itself.
End PCRE LICENCE
For the test\zb.c component:
/* ZeusBench V1.01
===============
This program is Copyright (C) Zeus Technology Limited 1996.
This program may be used and copied freely providing this copyright notice
is not removed.
This software is provided "as is" and any express or implied waranties,
including but not limited to, the implied warranties of merchantability and
fitness for a particular purpose are disclaimed. In no event shall
Zeus Technology Ltd. be liable for any direct, indirect, incidental, special,
exemplary, or consequential damaged (including, but not limited to,
procurement of substitute good or services; loss of use, data, or profits;
or business interruption) however caused and on theory of liability. Whether
in contract, strict liability or tort (including negligence or otherwise)
arising in any way out of the use of this software, even if advised of the
possibility of such damage.
Written by Adam Twiss (adam@zeus.co.uk). March 1996
Thanks to the following people for their input:
Mike Belshe (mbelshe@netscape.com)
Michael Campanella (campanella@stevms.enet.dec.com)
*/
For the expat xml parser component:
Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
and Clark Cooper
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.
====================================================================

140
vendor/gopkg.in/ns1/ns1-go.v2/rest/account_apikey.go generated vendored Normal file
View File

@ -0,0 +1,140 @@
package rest
import (
"errors"
"fmt"
"net/http"
"gopkg.in/ns1/ns1-go.v2/rest/model/account"
)
// APIKeysService handles 'account/apikeys' endpoint.
type APIKeysService service
// List returns all api keys in the account.
//
// NS1 API docs: https://ns1.com/api/#apikeys-get
func (s *APIKeysService) List() ([]*account.APIKey, *http.Response, error) {
req, err := s.client.NewRequest("GET", "account/apikeys", nil)
if err != nil {
return nil, nil, err
}
kl := []*account.APIKey{}
resp, err := s.client.Do(req, &kl)
if err != nil {
return nil, resp, err
}
return kl, resp, nil
}
// Get returns details of an api key, including permissions, for a single API Key.
// Note: do not use the API Key itself as the keyid in the URL — use the id of the key.
//
// NS1 API docs: https://ns1.com/api/#apikeys-id-get
func (s *APIKeysService) Get(keyID string) (*account.APIKey, *http.Response, error) {
path := fmt.Sprintf("account/apikeys/%s", keyID)
req, err := s.client.NewRequest("GET", path, nil)
if err != nil {
return nil, nil, err
}
var a account.APIKey
resp, err := s.client.Do(req, &a)
if err != nil {
switch err.(type) {
case *Error:
if err.(*Error).Message == "unknown api key" {
return nil, resp, ErrKeyMissing
}
}
return nil, resp, err
}
return &a, resp, nil
}
// Create takes a *APIKey and creates a new account apikey.
//
// NS1 API docs: https://ns1.com/api/#apikeys-put
func (s *APIKeysService) Create(a *account.APIKey) (*http.Response, error) {
req, err := s.client.NewRequest("PUT", "account/apikeys", &a)
if err != nil {
return nil, err
}
// Update account fields with data from api(ensure consistent)
resp, err := s.client.Do(req, &a)
if err != nil {
switch err.(type) {
case *Error:
if err.(*Error).Message == fmt.Sprintf("api key with name \"%s\" exists", a.Name) {
return resp, ErrKeyExists
}
}
return resp, err
}
return resp, nil
}
// Update changes the name or access rights for an API Key.
//
// NS1 API docs: https://ns1.com/api/#apikeys-id-post
func (s *APIKeysService) Update(a *account.APIKey) (*http.Response, error) {
path := fmt.Sprintf("account/apikeys/%s", a.ID)
req, err := s.client.NewRequest("POST", path, &a)
if err != nil {
return nil, err
}
// Update apikey fields with data from api(ensure consistent)
resp, err := s.client.Do(req, &a)
if err != nil {
switch err.(type) {
case *Error:
if err.(*Error).Message == "unknown api key" {
return resp, ErrKeyMissing
}
}
return resp, err
}
return resp, nil
}
// Delete deletes an apikey.
//
// NS1 API docs: https://ns1.com/api/#apikeys-id-delete
func (s *APIKeysService) Delete(keyID string) (*http.Response, error) {
path := fmt.Sprintf("account/apikeys/%s", keyID)
req, err := s.client.NewRequest("DELETE", path, nil)
if err != nil {
return nil, err
}
resp, err := s.client.Do(req, nil)
if err != nil {
switch err.(type) {
case *Error:
if err.(*Error).Message == "unknown api key" {
return resp, ErrKeyMissing
}
}
return resp, err
}
return resp, nil
}
var (
// ErrKeyExists bundles PUT create error.
ErrKeyExists = errors.New("key already exists")
// ErrKeyMissing bundles GET/POST/DELETE error.
ErrKeyMissing = errors.New("key does not exist")
)

46
vendor/gopkg.in/ns1/ns1-go.v2/rest/account_setting.go generated vendored Normal file
View File

@ -0,0 +1,46 @@
package rest
import (
"net/http"
"gopkg.in/ns1/ns1-go.v2/rest/model/account"
)
// SettingsService handles 'account/settings' endpoint.
type SettingsService service
// Get returns the basic contact details associated with the account.
//
// NS1 API docs: https://ns1.com/api/#settings-get
func (s *SettingsService) Get() (*account.Setting, *http.Response, error) {
req, err := s.client.NewRequest("GET", "account/settings", nil)
if err != nil {
return nil, nil, err
}
var us account.Setting
resp, err := s.client.Do(req, &us)
if err != nil {
return nil, resp, err
}
return &us, resp, nil
}
// Update changes most of the basic contact details, except customerid.
//
// NS1 API docs: https://ns1.com/api/#settings-post
func (s *SettingsService) Update(us *account.Setting) (*http.Response, error) {
req, err := s.client.NewRequest("POST", "account/settings", &us)
if err != nil {
return nil, err
}
// Update usagewarnings fields with data from api(ensure consistent)
resp, err := s.client.Do(req, &us)
if err != nil {
return resp, err
}
return resp, nil
}

138
vendor/gopkg.in/ns1/ns1-go.v2/rest/account_team.go generated vendored Normal file
View File

@ -0,0 +1,138 @@
package rest
import (
"errors"
"fmt"
"net/http"
"gopkg.in/ns1/ns1-go.v2/rest/model/account"
)
// TeamsService handles 'account/teams' endpoint.
type TeamsService service
// List returns all teams in the account.
//
// NS1 API docs: https://ns1.com/api/#teams-get
func (s *TeamsService) List() ([]*account.Team, *http.Response, error) {
req, err := s.client.NewRequest("GET", "account/teams", nil)
if err != nil {
return nil, nil, err
}
tl := []*account.Team{}
resp, err := s.client.Do(req, &tl)
if err != nil {
return nil, resp, err
}
return tl, resp, nil
}
// Get returns details of a single team.
//
// NS1 API docs: https://ns1.com/api/#teams-id-get
func (s *TeamsService) Get(id string) (*account.Team, *http.Response, error) {
path := fmt.Sprintf("account/teams/%s", id)
req, err := s.client.NewRequest("GET", path, nil)
if err != nil {
return nil, nil, err
}
var t account.Team
resp, err := s.client.Do(req, &t)
if err != nil {
switch err.(type) {
case *Error:
if err.(*Error).Message == "Unknown team id" {
return nil, resp, ErrTeamMissing
}
}
return nil, resp, err
}
return &t, resp, nil
}
// Create takes a *Team and creates a new account team.
//
// NS1 API docs: https://ns1.com/api/#teams-put
func (s *TeamsService) Create(t *account.Team) (*http.Response, error) {
req, err := s.client.NewRequest("PUT", "account/teams", &t)
if err != nil {
return nil, err
}
// Update team fields with data from api(ensure consistent)
resp, err := s.client.Do(req, &t)
if err != nil {
switch err.(type) {
case *Error:
if err.(*Error).Message == fmt.Sprintf("team with name \"%s\" exists", t.Name) {
return resp, ErrTeamExists
}
}
return resp, err
}
return resp, nil
}
// Update changes the name or access rights for a team.
//
// NS1 API docs: https://ns1.com/api/#teams-id-post
func (s *TeamsService) Update(t *account.Team) (*http.Response, error) {
path := fmt.Sprintf("account/teams/%s", t.ID)
req, err := s.client.NewRequest("POST", path, &t)
if err != nil {
return nil, err
}
// Update team fields with data from api(ensure consistent)
resp, err := s.client.Do(req, &t)
if err != nil {
switch err.(type) {
case *Error:
if err.(*Error).Message == "unknown team id" {
return resp, ErrTeamMissing
}
}
return resp, err
}
return resp, nil
}
// Delete deletes a team.
//
// NS1 API docs: https://ns1.com/api/#teams-id-delete
func (s *TeamsService) Delete(id string) (*http.Response, error) {
path := fmt.Sprintf("account/teams/%s", id)
req, err := s.client.NewRequest("DELETE", path, nil)
if err != nil {
return nil, err
}
resp, err := s.client.Do(req, nil)
if err != nil {
switch err.(type) {
case *Error:
if err.(*Error).Message == "unknown team id" {
return resp, ErrTeamMissing
}
}
return resp, err
}
return resp, nil
}
var (
// ErrTeamExists bundles PUT create error.
ErrTeamExists = errors.New("team already exists")
// ErrTeamMissing bundles GET/POST/DELETE error.
ErrTeamMissing = errors.New("team does not exist")
)

138
vendor/gopkg.in/ns1/ns1-go.v2/rest/account_user.go generated vendored Normal file
View File

@ -0,0 +1,138 @@
package rest
import (
"errors"
"fmt"
"net/http"
"gopkg.in/ns1/ns1-go.v2/rest/model/account"
)
// UsersService handles 'account/users' endpoint.
type UsersService service
// List returns all users in the account.
//
// NS1 API docs: https://ns1.com/api/#users-get
func (s *UsersService) List() ([]*account.User, *http.Response, error) {
req, err := s.client.NewRequest("GET", "account/users", nil)
if err != nil {
return nil, nil, err
}
ul := []*account.User{}
resp, err := s.client.Do(req, &ul)
if err != nil {
return nil, resp, err
}
return ul, resp, nil
}
// Get returns details of a single user.
//
// NS1 API docs: https://ns1.com/api/#users-user-get
func (s *UsersService) Get(username string) (*account.User, *http.Response, error) {
path := fmt.Sprintf("account/users/%s", username)
req, err := s.client.NewRequest("GET", path, nil)
if err != nil {
return nil, nil, err
}
var u account.User
resp, err := s.client.Do(req, &u)
if err != nil {
switch err.(type) {
case *Error:
if err.(*Error).Message == "Unknown user" {
return nil, resp, ErrUserMissing
}
}
return nil, resp, err
}
return &u, resp, nil
}
// Create takes a *User and creates a new account user.
//
// NS1 API docs: https://ns1.com/api/#users-put
func (s *UsersService) Create(u *account.User) (*http.Response, error) {
req, err := s.client.NewRequest("PUT", "account/users", &u)
if err != nil {
return nil, err
}
// Update user fields with data from api(ensure consistent)
resp, err := s.client.Do(req, &u)
if err != nil {
switch err.(type) {
case *Error:
if err.(*Error).Message == "request failed:Login Name is already in use." {
return resp, ErrUserExists
}
}
return resp, err
}
return resp, nil
}
// Update change contact details, notification settings, or access rights for a user.
//
// NS1 API docs: https://ns1.com/api/#users-user-post
func (s *UsersService) Update(u *account.User) (*http.Response, error) {
path := fmt.Sprintf("account/users/%s", u.Username)
req, err := s.client.NewRequest("POST", path, &u)
if err != nil {
return nil, err
}
// Update user fields with data from api(ensure consistent)
resp, err := s.client.Do(req, &u)
if err != nil {
switch err.(type) {
case *Error:
if err.(*Error).Message == "Unknown user" {
return resp, ErrUserMissing
}
}
return resp, err
}
return resp, nil
}
// Delete deletes a user.
//
// NS1 API docs: https://ns1.com/api/#users-user-delete
func (s *UsersService) Delete(username string) (*http.Response, error) {
path := fmt.Sprintf("account/users/%s", username)
req, err := s.client.NewRequest("DELETE", path, nil)
if err != nil {
return nil, err
}
resp, err := s.client.Do(req, nil)
if err != nil {
switch err.(type) {
case *Error:
if err.(*Error).Message == "Unknown user" {
return resp, ErrUserMissing
}
}
return resp, err
}
return resp, nil
}
var (
// ErrUserExists bundles PUT create error.
ErrUserExists = errors.New("user already exists")
// ErrUserMissing bundles GET/POST/DELETE error.
ErrUserMissing = errors.New("user does not exist")
)

47
vendor/gopkg.in/ns1/ns1-go.v2/rest/account_warning.go generated vendored Normal file
View File

@ -0,0 +1,47 @@
package rest
import (
"net/http"
"gopkg.in/ns1/ns1-go.v2/rest/model/account"
)
// WarningsService handles 'account/usagewarnings' endpoint.
type WarningsService service
// Get returns toggles and thresholds used when sending overage warning
// alert messages to users with billing notifications enabled.
//
// NS1 API docs: https://ns1.com/api/#usagewarnings-get
func (s *WarningsService) Get() (*account.UsageWarning, *http.Response, error) {
req, err := s.client.NewRequest("GET", "account/usagewarnings", nil)
if err != nil {
return nil, nil, err
}
var uw account.UsageWarning
resp, err := s.client.Do(req, &uw)
if err != nil {
return nil, resp, err
}
return &uw, resp, nil
}
// Update changes alerting toggles and thresholds for overage warning alert messages.
//
// NS1 API docs: https://ns1.com/api/#usagewarnings-post
func (s *WarningsService) Update(uw *account.UsageWarning) (*http.Response, error) {
req, err := s.client.NewRequest("POST", "account/usagewarnings", &uw)
if err != nil {
return nil, err
}
// Update usagewarnings fields with data from api(ensure consistent)
resp, err := s.client.Do(req, &uw)
if err != nil {
return resp, err
}
return resp, nil
}

288
vendor/gopkg.in/ns1/ns1-go.v2/rest/client.go generated vendored Normal file
View File

@ -0,0 +1,288 @@
package rest
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strconv"
"time"
)
const (
clientVersion = "2.0.0"
defaultEndpoint = "https://api.nsone.net/v1/"
defaultUserAgent = "go-ns1/" + clientVersion
headerAuth = "X-NSONE-Key"
headerRateLimit = "X-Ratelimit-Limit"
headerRateRemaining = "X-Ratelimit-Remaining"
headerRatePeriod = "X-Ratelimit-Period"
)
// Doer is a single method interface that allows a user to extend/augment an http.Client instance.
// Note: http.Client satisfies the Doer interface.
type Doer interface {
Do(*http.Request) (*http.Response, error)
}
// Client manages communication with the NS1 Rest API.
type Client struct {
// httpClient handles all rest api communication,
// and expects an *http.Client.
httpClient Doer
// NS1 rest endpoint, overrides default if given.
Endpoint *url.URL
// NS1 api key (value for http request header 'X-NSONE-Key').
APIKey string
// NS1 go rest user agent (value for http request header 'User-Agent').
UserAgent string
// Func to call after response is returned in Do
RateLimitFunc func(RateLimit)
// From the excellent github-go client.
common service // Reuse a single struct instead of allocating one for each service on the heap.
// Services used for communicating with different components of the NS1 API.
APIKeys *APIKeysService
DataFeeds *DataFeedsService
DataSources *DataSourcesService
Jobs *JobsService
Notifications *NotificationsService
Records *RecordsService
Settings *SettingsService
Teams *TeamsService
Users *UsersService
Warnings *WarningsService
Zones *ZonesService
}
// NewClient constructs and returns a reference to an instantiated Client.
func NewClient(httpClient Doer, options ...func(*Client)) *Client {
endpoint, _ := url.Parse(defaultEndpoint)
if httpClient == nil {
httpClient = http.DefaultClient
}
c := &Client{
httpClient: httpClient,
Endpoint: endpoint,
RateLimitFunc: defaultRateLimitFunc,
UserAgent: defaultUserAgent,
}
c.common.client = c
c.APIKeys = (*APIKeysService)(&c.common)
c.DataFeeds = (*DataFeedsService)(&c.common)
c.DataSources = (*DataSourcesService)(&c.common)
c.Jobs = (*JobsService)(&c.common)
c.Notifications = (*NotificationsService)(&c.common)
c.Records = (*RecordsService)(&c.common)
c.Settings = (*SettingsService)(&c.common)
c.Teams = (*TeamsService)(&c.common)
c.Users = (*UsersService)(&c.common)
c.Warnings = (*WarningsService)(&c.common)
c.Zones = (*ZonesService)(&c.common)
for _, option := range options {
option(c)
}
return c
}
type service struct {
client *Client
}
// SetHTTPClient sets a Client instances' httpClient.
func SetHTTPClient(httpClient Doer) func(*Client) {
return func(c *Client) { c.httpClient = httpClient }
}
// SetAPIKey sets a Client instances' APIKey.
func SetAPIKey(key string) func(*Client) {
return func(c *Client) { c.APIKey = key }
}
// SetEndpoint sets a Client instances' Endpoint.
func SetEndpoint(endpoint string) func(*Client) {
return func(c *Client) { c.Endpoint, _ = url.Parse(endpoint) }
}
// SetUserAgent sets a Client instances' user agent.
func SetUserAgent(ua string) func(*Client) {
return func(c *Client) { c.UserAgent = ua }
}
// SetRateLimitFunc sets a Client instances' RateLimitFunc.
func SetRateLimitFunc(ratefunc func(rl RateLimit)) func(*Client) {
return func(c *Client) { c.RateLimitFunc = ratefunc }
}
// Do satisfies the Doer interface.
func (c Client) Do(req *http.Request, v interface{}) (*http.Response, error) {
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
err = CheckResponse(resp)
if err != nil {
return resp, err
}
rl := parseRate(resp)
c.RateLimitFunc(rl)
if v != nil {
// Try to unmarshal body into given type using streaming decoder.
if err := json.NewDecoder(resp.Body).Decode(&v); err != nil {
return nil, err
}
}
return resp, err
}
// NewRequest constructs and returns a http.Request.
func (c *Client) NewRequest(method, path string, body interface{}) (*http.Request, error) {
rel, err := url.Parse(path)
if err != nil {
return nil, err
}
uri := c.Endpoint.ResolveReference(rel)
// Encode body as json
buf := new(bytes.Buffer)
if body != nil {
err := json.NewEncoder(buf).Encode(body)
if err != nil {
return nil, err
}
}
req, err := http.NewRequest(method, uri.String(), buf)
if err != nil {
return nil, err
}
req.Header.Add(headerAuth, c.APIKey)
req.Header.Add("User-Agent", c.UserAgent)
return req, nil
}
// Response wraps stdlib http response.
type Response struct {
*http.Response
}
// Error contains all http responses outside the 2xx range.
type Error struct {
Resp *http.Response
Message string
}
// Satisfy std lib error interface.
func (re *Error) Error() string {
return fmt.Sprintf("%v %v: %d %v", re.Resp.Request.Method, re.Resp.Request.URL, re.Resp.StatusCode, re.Message)
}
// CheckResponse handles parsing of rest api errors. Returns nil if no error.
func CheckResponse(resp *http.Response) error {
if c := resp.StatusCode; c >= 200 && c <= 299 {
return nil
}
restErr := &Error{Resp: resp}
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
if len(b) == 0 {
return restErr
}
err = json.Unmarshal(b, restErr)
if err != nil {
return err
}
return restErr
}
// RateLimitFunc is rate limiting strategy for the Client instance.
type RateLimitFunc func(RateLimit)
// RateLimit stores X-Ratelimit-* headers
type RateLimit struct {
Limit int
Remaining int
Period int
}
var defaultRateLimitFunc = func(rl RateLimit) {}
// PercentageLeft returns the ratio of Remaining to Limit as a percentage
func (rl RateLimit) PercentageLeft() int {
return rl.Remaining * 100 / rl.Limit
}
// WaitTime returns the time.Duration ratio of Period to Limit
func (rl RateLimit) WaitTime() time.Duration {
return (time.Second * time.Duration(rl.Period)) / time.Duration(rl.Limit)
}
// WaitTimeRemaining returns the time.Duration ratio of Period to Remaining
func (rl RateLimit) WaitTimeRemaining() time.Duration {
return (time.Second * time.Duration(rl.Period)) / time.Duration(rl.Remaining)
}
// RateLimitStrategySleep sets RateLimitFunc to sleep by WaitTimeRemaining
func (c *Client) RateLimitStrategySleep() {
c.RateLimitFunc = func(rl RateLimit) {
remaining := rl.WaitTimeRemaining()
time.Sleep(remaining)
}
}
// parseRate parses rate related headers from http response.
func parseRate(resp *http.Response) RateLimit {
var rl RateLimit
if limit := resp.Header.Get(headerRateLimit); limit != "" {
rl.Limit, _ = strconv.Atoi(limit)
}
if remaining := resp.Header.Get(headerRateRemaining); remaining != "" {
rl.Remaining, _ = strconv.Atoi(remaining)
}
if period := resp.Header.Get(headerRatePeriod); period != "" {
rl.Period, _ = strconv.Atoi(period)
}
return rl
}
// SetTimeParam sets a url timestamp query param given the parameters name.
func SetTimeParam(key string, t time.Time) func(*url.Values) {
return func(v *url.Values) { v.Set(key, strconv.Itoa(int(t.Unix()))) }
}
// SetBoolParam sets a url boolean query param given the parameters name.
func SetBoolParam(key string, b bool) func(*url.Values) {
return func(v *url.Values) { v.Set(key, strconv.FormatBool(b)) }
}
// SetStringParam sets a url string query param given the parameters name.
func SetStringParam(key, val string) func(*url.Values) {
return func(v *url.Values) { v.Set(key, val) }
}

116
vendor/gopkg.in/ns1/ns1-go.v2/rest/data_feed.go generated vendored Normal file
View File

@ -0,0 +1,116 @@
package rest
import (
"fmt"
"net/http"
"gopkg.in/ns1/ns1-go.v2/rest/model/data"
)
// DataFeedsService handles 'data/feeds' endpoint.
type DataFeedsService service
// List returns all data feeds connected to a given data source.
//
// NS1 API docs: https://ns1.com/api/#feeds-get
func (s *DataFeedsService) List(sourceID string) ([]*data.Feed, *http.Response, error) {
path := fmt.Sprintf("data/feeds/%s", sourceID)
req, err := s.client.NewRequest("GET", path, nil)
if err != nil {
return nil, nil, err
}
dfl := []*data.Feed{}
resp, err := s.client.Do(req, &dfl)
if err != nil {
return nil, resp, err
}
return dfl, resp, nil
}
// Get takes a data source ID and a data feed ID and returns the details of a single data feed
//
// NS1 API docs: https://ns1.com/api/#feeds-feed-get
func (s *DataFeedsService) Get(sourceID string, feedID string) (*data.Feed, *http.Response, error) {
path := fmt.Sprintf("data/feeds/%s/%s", sourceID, feedID)
req, err := s.client.NewRequest("GET", path, nil)
if err != nil {
return nil, nil, err
}
var df data.Feed
resp, err := s.client.Do(req, &df)
if err != nil {
return nil, resp, err
}
return &df, resp, nil
}
// Create takes a *DataFeed and connects a new data feed to an existing data source.
//
// NS1 API docs: https://ns1.com/api/#feeds-put
func (s *DataFeedsService) Create(sourceID string, df *data.Feed) (*http.Response, error) {
path := fmt.Sprintf("data/feeds/%s", sourceID)
req, err := s.client.NewRequest("PUT", path, &df)
if err != nil {
return nil, err
}
// Update datafeeds' fields with data from api(ensure consistent)
resp, err := s.client.Do(req, &df)
if err != nil {
return resp, err
}
return resp, nil
}
// Update takes a *Feed and modifies and existing data feed.
// Note:
// - The 'data' portion of a feed does not actually
// get updated during a POST. In order to update a feeds'
// 'data' attribute, one must use the Publish method.
// - Both the 'destinations' and 'networks' attributes are
// not updated during a POST.
//
// NS1 API docs: https://ns1.com/api/#feeds-post
func (s *DataFeedsService) Update(sourceID string, df *data.Feed) (*http.Response, error) {
path := fmt.Sprintf("data/feeds/%s/%s", sourceID, df.ID)
req, err := s.client.NewRequest("POST", path, &df)
if err != nil {
return nil, err
}
// Update df instance fields with data from api(ensure consistent)
resp, err := s.client.Do(req, &df)
if err != nil {
return resp, err
}
return resp, nil
}
// Delete takes a data source ID and a data feed ID and disconnects the feed from the data source and all attached destination metadata tables.
//
// NS1 API docs: https://ns1.com/api/#feeds-delete
func (s *DataFeedsService) Delete(sourceID string, feedID string) (*http.Response, error) {
path := fmt.Sprintf("data/feeds/%s/%s", sourceID, feedID)
req, err := s.client.NewRequest("DELETE", path, nil)
if err != nil {
return nil, err
}
resp, err := s.client.Do(req, nil)
if err != nil {
return resp, err
}
return resp, nil
}

126
vendor/gopkg.in/ns1/ns1-go.v2/rest/data_source.go generated vendored Normal file
View File

@ -0,0 +1,126 @@
package rest
import (
"fmt"
"net/http"
"gopkg.in/ns1/ns1-go.v2/rest/model/data"
)
// DataSourcesService handles 'data/sources' endpoint.
type DataSourcesService service
// List returns all connected data sources.
//
// NS1 API docs: https://ns1.com/api/#sources-get
func (s *DataSourcesService) List() ([]*data.Source, *http.Response, error) {
req, err := s.client.NewRequest("GET", "data/sources", nil)
if err != nil {
return nil, nil, err
}
dsl := []*data.Source{}
resp, err := s.client.Do(req, &dsl)
if err != nil {
return nil, resp, err
}
return dsl, resp, nil
}
// Get takes an ID returns the details for a single data source.
//
// NS1 API docs: https://ns1.com/api/#sources-source-get
func (s *DataSourcesService) Get(id string) (*data.Source, *http.Response, error) {
path := fmt.Sprintf("data/sources/%s", id)
req, err := s.client.NewRequest("GET", path, nil)
if err != nil {
return nil, nil, err
}
var ds data.Source
resp, err := s.client.Do(req, &ds)
if err != nil {
return nil, resp, err
}
return &ds, resp, nil
}
// Create takes a *DataSource and creates a new data source.
//
// NS1 API docs: https://ns1.com/api/#sources-put
func (s *DataSourcesService) Create(ds *data.Source) (*http.Response, error) {
req, err := s.client.NewRequest("PUT", "data/sources", &ds)
if err != nil {
return nil, err
}
// Update data sources' fields with data from api(ensure consistent)
resp, err := s.client.Do(req, &ds)
if err != nil {
return resp, err
}
return resp, nil
}
// Update takes a *DataSource modifies basic details of a data source.
// NOTE: This does not 'publish' data. See the Publish method.
//
// NS1 API docs: https://ns1.com/api/#sources-post
func (s *DataSourcesService) Update(ds *data.Source) (*http.Response, error) {
path := fmt.Sprintf("data/sources/%s", ds.ID)
req, err := s.client.NewRequest("POST", path, &ds)
if err != nil {
return nil, err
}
// Update data sources' instance fields with data from api(ensure consistent)
resp, err := s.client.Do(req, &ds)
if err != nil {
return resp, err
}
return resp, nil
}
// Delete takes an ID and removes an existing data source and all connected feeds from the source.
//
// NS1 API docs: https://ns1.com/api/#sources-delete
func (s *DataSourcesService) Delete(id string) (*http.Response, error) {
path := fmt.Sprintf("data/sources/%s", id)
req, err := s.client.NewRequest("DELETE", path, nil)
if err != nil {
return nil, err
}
resp, err := s.client.Do(req, nil)
if err != nil {
return resp, err
}
return resp, nil
}
// Publish takes a datasources' id and data to publish.
//
// NS1 API docs: https://ns1.com/api/#feed-post
func (s *DataSourcesService) Publish(dsID string, data interface{}) (*http.Response, error) {
path := fmt.Sprintf("feed/%s", dsID)
req, err := s.client.NewRequest("POST", path, &data)
if err != nil {
return nil, err
}
resp, err := s.client.Do(req, nil)
if err != nil {
return resp, err
}
return resp, nil
}

2
vendor/gopkg.in/ns1/ns1-go.v2/rest/doc.go generated vendored Normal file
View File

@ -0,0 +1,2 @@
// Package rest defines the api services used to communicate with NS1.
package rest

View File

@ -0,0 +1,13 @@
package account
// APIKey wraps an NS1 /account/apikeys resource
type APIKey struct {
// Read-only fields
ID string `json:"id,omitempty"`
Key string `json:"key,omitempty"`
LastAccess int `json:"last_access,omitempty"`
Name string `json:"name"`
TeamIDs []string `json:"teams"`
Permissions PermissionsMap `json:"permissions"`
}

View File

@ -0,0 +1,2 @@
// Package account contains definitions for NS1 apikeys/teams/users/etc.
package account

View File

@ -0,0 +1,44 @@
package account
// PermissionsMap wraps a User's "permissions" attribute
type PermissionsMap struct {
DNS PermissionsDNS `json:"dns"`
Data PermissionsData `json:"data"`
Account PermissionsAccount `json:"account"`
Monitoring PermissionsMonitoring `json:"monitoring"`
}
// PermissionsDNS wraps a User's "permissions.dns" attribute
type PermissionsDNS struct {
ViewZones bool `json:"view_zones"`
ManageZones bool `json:"manage_zones"`
ZonesAllowByDefault bool `json:"zones_allow_by_default"`
ZonesDeny []string `json:"zones_deny"`
ZonesAllow []string `json:"zones_allow"`
}
// PermissionsData wraps a User's "permissions.data" attribute
type PermissionsData struct {
PushToDatafeeds bool `json:"push_to_datafeeds"`
ManageDatasources bool `json:"manage_datasources"`
ManageDatafeeds bool `json:"manage_datafeeds"`
}
// PermissionsAccount wraps a User's "permissions.account" attribute
type PermissionsAccount struct {
ManageUsers bool `json:"manage_users"`
ManagePaymentMethods bool `json:"manage_payment_methods"`
ManagePlan bool `json:"manage_plan"`
ManageTeams bool `json:"manage_teams"`
ManageApikeys bool `json:"manage_apikeys"`
ManageAccountSettings bool `json:"manage_account_settings"`
ViewActivityLog bool `json:"view_activity_log"`
ViewInvoices bool `json:"view_invoices"`
}
// PermissionsMonitoring wraps a User's "permissions.monitoring" attribute
type PermissionsMonitoring struct {
ManageLists bool `json:"manage_lists"`
ManageJobs bool `json:"manage_jobs"`
ViewJobs bool `json:"view_jobs"`
}

View File

@ -0,0 +1,21 @@
package account
// Setting represents an accounts' contact info.
type Setting struct {
CustomerID int `json:"customerid,omitempty"`
FirstName string `json:"firstname,omitempty"`
LastName string `json:"lastname,omitempty"`
Company string `json:"company,omitempty"`
Phone string `json:"phone,omitempty"`
Email string `json:"email,omitempty"`
Address Address `json:"address,omitempty"`
}
// Address for Setting struct.
type Address struct {
Country string `json:"country,omitempty"`
Street string `json:"street,omitempty"`
State string `json:"state,omitempty"`
City string `json:"city,omitempty"`
Postal string `json:"postalcode,omitempty"`
}

View File

@ -0,0 +1,8 @@
package account
// Team wraps an NS1 /accounts/teams resource
type Team struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
Permissions PermissionsMap `json:"permissions"`
}

View File

@ -0,0 +1,19 @@
package account
// User wraps an NS1 /account/users resource
type User struct {
// Read-only fields
LastAccess float64 `json:"last_access"`
Name string `json:"name"`
Username string `json:"username"`
Email string `json:"email"`
TeamIDs []string `json:"teams"`
Notify NotificationSettings `json:"notify"`
Permissions PermissionsMap `json:"permissions"`
}
// NotificationSettings wraps a User's "notify" attribute
type NotificationSettings struct {
Billing bool `json:"billing"`
}

View File

@ -0,0 +1,17 @@
package account
// UsageWarning wraps an NS1 /account/usagewarnings resource
type UsageWarning struct {
Records Warning `json:"records"`
Queries Warning `json:"queries"`
}
// Warning contains alerting toggles and thresholds for overage warning alert messages.
// First thresholds must be smaller than Second ones and all thresholds
// must be percentages between 0 and 100.
type Warning struct {
Send bool `json:"send_warnings"`
First int `json:"warning_1"`
Second int `json:"warning_2"`
}

2
vendor/gopkg.in/ns1/ns1-go.v2/rest/model/data/doc.go generated vendored Normal file
View File

@ -0,0 +1,2 @@
// Package data contains definitions for NS1 metadata/sources/feeds/etc.
package data

38
vendor/gopkg.in/ns1/ns1-go.v2/rest/model/data/feed.go generated vendored Normal file
View File

@ -0,0 +1,38 @@
package data
// Destination is the target resource the receives data from a feed/source.
type Destination struct {
ID string `json:"destid"`
// All destinations must point to a record.
RecordID string `json:"record"`
// Type is the 'level' at which to apply the filters(on the targeted record).
// Options:
// - answer (highest precedence)
// - region
// - record (lowest precendence)
Type string `json:"desttype"`
SourceID string `json:"-"`
}
// NewDestination returns an empty feed destination.
func NewDestination() *Destination {
return &Destination{}
}
// Feed wraps an NS1 /data/feeds resource
type Feed struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
Config Config `json:"config,omitempty"`
Data Meta `json:"data,omitempty"`
SourceID string
}
// NewFeed returns a data feed with given name and config.
func NewFeed(name string, cfg Config) *Feed {
return &Feed{Name: name, Config: cfg}
}

127
vendor/gopkg.in/ns1/ns1-go.v2/rest/model/data/meta.go generated vendored Normal file
View File

@ -0,0 +1,127 @@
package data
// FeedPtr represents the dynamic metadata value in which a feed is providing the value.
type FeedPtr struct {
FeedID string `json:"feed,omitempty"`
}
// Meta contains information on an entities metadata table. Metadata key/value
// pairs are used by a records' filter pipeline during a dns query.
// All values can be a feed id as well, indicating real-time updates of these values.
// Structure/Precendence of metadata tables:
// - Record
// - Meta <- lowest precendence in filter
// - Region(s)
// - Meta <- middle precedence in filter chain
// - ...
// - Answer(s)
// - Meta <- highest precedence in filter chain
// - ...
// - ...
type Meta struct {
// STATUS
// Indicates whether or not entity is considered 'up'
// bool or FeedPtr.
Up interface{} `json:"up,omitempty"`
// Indicates the number of active connections.
// Values must be positive.
// int or FeedPtr.
Connections interface{} `json:"connections,omitempty"`
// Indicates the number of active requests (HTTP or otherwise).
// Values must be positive.
// int or FeedPtr.
Requests interface{} `json:"requests,omitempty"`
// Indicates the "load average".
// Values must be positive, and will be rounded to the nearest tenth.
// float64 or FeedPtr.
LoadAvg interface{} `json:"loadavg,omitempty"`
// The Job ID of a Pulsar telemetry gathering job and routing granularities
// to associate with.
// string or FeedPtr.
Pulsar interface{} `json:"pulsar,omitempty"`
// GEOGRAPHICAL
// Must be between -180.0 and +180.0 where negative
// indicates South and positive indicates North.
// e.g., the longitude of the datacenter where a server resides.
// float64 or FeedPtr.
Latitude interface{} `json:"latitude,omitempty"`
// Must be between -180.0 and +180.0 where negative
// indicates West and positive indicates East.
// e.g., the longitude of the datacenter where a server resides.
// float64 or FeedPtr.
Longitude interface{} `json:"longitude,omitempty"`
// Valid geographic regions are: 'US-EAST', 'US-CENTRAL', 'US-WEST',
// 'EUROPE', 'ASIAPAC', 'SOUTH-AMERICA', 'AFRICA'.
// e.g., the rough geographic location of the Datacenter where a server resides.
// []string or FeedPtr.
Georegion interface{} `json:"georegion,omitempty"`
// Countr(ies) must be specified as ISO3166 2-character country code(s).
// []string or FeedPtr.
Country interface{} `json:"country,omitempty"`
// State(s) must be specified as standard 2-character state code(s).
// []string or FeedPtr.
USState interface{} `json:"us_state,omitempty"`
// Canadian Province(s) must be specified as standard 2-character province
// code(s).
// []string or FeedPtr.
CAProvince interface{} `json:"ca_province,omitempty"`
// INFORMATIONAL
// Notes to indicate any necessary details for operators.
// Up to 256 characters in length.
// string or FeedPtr.
Note interface{} `json:"note,omitempty"`
// NETWORK
// IP (v4 and v6) prefixes in CIDR format ("a.b.c.d/mask").
// May include up to 1000 prefixes.
// e.g., "1.2.3.4/24"
// []string or FeedPtr.
IPPrefixes interface{} `json:"ip_prefixes,omitempty"`
// Autonomous System (AS) number(s).
// May include up to 1000 AS numbers.
// []string or FeedPtr.
ASN interface{} `json:"asn,omitempty"`
// TRAFFIC
// Indicates the "priority tier".
// Lower values indicate higher priority.
// Values must be positive.
// int or FeedPtr.
Priority interface{} `json:"priority,omitempty"`
// Indicates a weight.
// Filters that use weights normalize them.
// Any positive values are allowed.
// Values between 0 and 100 are recommended for simplicity's sake.
// float64 or FeedPtr.
Weight interface{} `json:"weight,omitempty"`
// Indicates a "low watermark" to use for load shedding.
// The value should depend on the metric used to determine
// load (e.g., loadavg, connections, etc).
// int or FeedPtr.
LowWatermark interface{} `json:"low_watermark,omitempty"`
// Indicates a "high watermark" to use for load shedding.
// The value should depend on the metric used to determine
// load (e.g., loadavg, connections, etc).
// int or FeedPtr.
HighWatermark interface{} `json:"high_watermark,omitempty"`
}

View File

@ -0,0 +1,10 @@
package data
// Region is a metadata table with a name/key.
// Can be thought of as metadata groupings.
type Region struct {
Meta Meta `json:"meta,omitempty"`
}
// Regions is simply a mapping of Regions inside a record.
type Regions map[string]Region

View File

@ -0,0 +1,28 @@
package data
// Config is a flat mapping where values are simple (no slices/maps).
type Config map[string]interface{}
// Source wraps an NS1 /data/sources resource
type Source struct {
ID string `json:"id,omitempty"`
// Human readable name of the source.
Name string `json:"name"`
Type string `json:"sourcetype"`
Config Config `json:"config,omitempty"`
Status string `json:"status,omitempty"`
Feeds []*Feed `json:"feeds,omitempty"`
}
// NewSource takes a name and type t.
func NewSource(name string, t string) *Source {
return &Source{
Name: name,
Type: t,
Config: Config{},
Feeds: []*Feed{},
}
}

101
vendor/gopkg.in/ns1/ns1-go.v2/rest/model/dns/answer.go generated vendored Normal file
View File

@ -0,0 +1,101 @@
package dns
import (
"fmt"
"strconv"
"strings"
"gopkg.in/ns1/ns1-go.v2/rest/model/data"
)
// Answer wraps the values of a Record's "filters" attribute
type Answer struct {
Meta *data.Meta `json:"meta,omitempty"`
// Answer response data. eg:
// Av4: ["1.1.1.1"]
// Av6: ["2001:db8:85a3::8a2e:370:7334"]
// MX: [10, "2.2.2.2"]
Rdata []string `json:"answer"`
// Region(grouping) that answer belongs to.
RegionName string `json:"region,omitempty"`
}
func (a Answer) String() string {
return strings.Trim(fmt.Sprint(a.Rdata), "[]")
}
// SetRegion associates a region with this answer.
func (a *Answer) SetRegion(name string) {
a.RegionName = name
}
// NewAnswer creates a generic Answer with given rdata.
func NewAnswer(rdata []string) *Answer {
return &Answer{
Meta: &data.Meta{},
Rdata: rdata,
}
}
// NewAv4Answer creates an Answer for A record.
func NewAv4Answer(host string) *Answer {
return &Answer{
Meta: &data.Meta{},
Rdata: []string{host},
}
}
// NewAv6Answer creates an Answer for AAAA record.
func NewAv6Answer(host string) *Answer {
return &Answer{
Meta: &data.Meta{},
Rdata: []string{host},
}
}
// NewALIASAnswer creates an Answer for ALIAS record.
func NewALIASAnswer(host string) *Answer {
return &Answer{
Meta: &data.Meta{},
Rdata: []string{host},
}
}
// NewCNAMEAnswer creates an Answer for CNAME record.
func NewCNAMEAnswer(name string) *Answer {
return &Answer{
Meta: &data.Meta{},
Rdata: []string{name},
}
}
// NewTXTAnswer creates an Answer for TXT record.
func NewTXTAnswer(text string) *Answer {
return &Answer{
Meta: &data.Meta{},
Rdata: []string{text},
}
}
// NewMXAnswer creates an Answer for MX record.
func NewMXAnswer(pri int, host string) *Answer {
return &Answer{
Meta: &data.Meta{},
Rdata: []string{strconv.Itoa(pri), host},
}
}
// NewSRVAnswer creates an Answer for SRV record.
func NewSRVAnswer(priority, weight, port int, target string) *Answer {
return &Answer{
Meta: &data.Meta{},
Rdata: []string{
strconv.Itoa(priority),
strconv.Itoa(weight),
strconv.Itoa(port),
target,
},
}
}

2
vendor/gopkg.in/ns1/ns1-go.v2/rest/model/dns/doc.go generated vendored Normal file
View File

@ -0,0 +1,2 @@
// Package dns contains definitions for NS1 zones/records/answers/etc.
package dns

76
vendor/gopkg.in/ns1/ns1-go.v2/rest/model/dns/record.go generated vendored Normal file
View File

@ -0,0 +1,76 @@
package dns
import (
"fmt"
"strings"
"gopkg.in/ns1/ns1-go.v2/rest/model/data"
"gopkg.in/ns1/ns1-go.v2/rest/model/filter"
)
// Record wraps an NS1 /zone/{zone}/{domain}/{type} resource
type Record struct {
Meta *data.Meta `json:"meta,omitempty"`
ID string `json:"id,omitempty"`
Zone string `json:"zone"`
Domain string `json:"domain"`
Type string `json:"type"`
Link string `json:"link,omitempty"`
TTL int `json:"ttl,omitempty"`
UseClientSubnet *bool `json:"use_client_subnet,omitempty"`
// Answers must all be of the same type as the record.
Answers []*Answer `json:"answers"`
// The records' filter chain.
Filters []*filter.Filter `json:"filters,omitempty"`
// The records' regions.
Regions data.Regions `json:"regions,omitempty"`
}
func (r Record) String() string {
return fmt.Sprintf("%s %s", r.Domain, r.Type)
}
// NewRecord takes a zone, domain and record type t and creates a *Record with
// UseClientSubnet: true & empty Answers.
func NewRecord(zone string, domain string, t string) *Record {
if !strings.HasSuffix(domain, zone) {
domain = fmt.Sprintf("%s.%s", domain, zone)
}
return &Record{
Meta: &data.Meta{},
Zone: zone,
Domain: domain,
Type: t,
Answers: []*Answer{},
Regions: data.Regions{},
}
}
// LinkTo sets a Record Link to an FQDN.
// to is the FQDN of the target record whose config should be used. Does
// not have to be in the same zone.
func (r *Record) LinkTo(to string) {
r.Meta = nil
r.Answers = []*Answer{}
r.Link = to
}
// AddAnswer adds an answer to the record.
func (r *Record) AddAnswer(ans *Answer) {
if r.Answers == nil {
r.Answers = []*Answer{}
}
r.Answers = append(r.Answers, ans)
}
// AddFilter adds a filter to the records' filter chain(ordering of filters matters).
func (r *Record) AddFilter(fil *filter.Filter) {
if r.Filters == nil {
r.Filters = []*filter.Filter{}
}
r.Filters = append(r.Filters, fil)
}

157
vendor/gopkg.in/ns1/ns1-go.v2/rest/model/dns/zone.go generated vendored Normal file
View File

@ -0,0 +1,157 @@
package dns
import "gopkg.in/ns1/ns1-go.v2/rest/model/data"
// Zone wraps an NS1 /zone resource
type Zone struct {
// Zones have metadata tables, but no filters act on 'zone-level' meta.
Meta *data.Meta `json:"meta,omitempty"`
// Read-only fields
DNSServers []string `json:"dns_servers,omitempty"`
NetworkPools []string `json:"network_pools,omitempty"`
Pool string `json:"pool,omitempty"` // Deprecated
ID string `json:"id,omitempty"`
Zone string `json:"zone,omitempty"`
TTL int `json:"ttl,omitempty"`
NxTTL int `json:"nx_ttl,omitempty"`
Retry int `json:"retry,omitempty"`
Serial int `json:"serial,omitempty"`
Refresh int `json:"refresh,omitempty"`
Expiry int `json:"expiry,omitempty"`
Hostmaster string `json:"hostmaster,omitempty"`
// If this is a linked zone, Link points to an existing standard zone,
// reusing its configuration and records. Link is a zones' domain name.
Link *string `json:"link,omitempty"`
// Networks contains the network ids the zone is available. Most zones
// will be in the NSONE Global Network(which is id 0).
NetworkIDs []int `json:"networks,omitempty"`
Records []*ZoneRecord `json:"records,omitempty"`
// Primary contains info to enable slaving of the zone by third party dns servers.
Primary *ZonePrimary `json:"primary,omitempty"`
// Secondary contains info for slaving the zone to a primary dns server.
Secondary *ZoneSecondary `json:"secondary,omitempty"`
}
func (z Zone) String() string {
return z.Zone
}
// ZoneRecord wraps Zone's "records" attribute
type ZoneRecord struct {
Domain string `json:"Domain,omitempty"`
ID string `json:"id,omitempty"`
Link string `json:"link,omitempty"`
ShortAns []string `json:"short_answers,omitempty"`
Tier int `json:"tier,omitempty"`
TTL int `json:"ttl,omitempty"`
Type string `json:"type,omitempty"`
}
// ZonePrimary wraps a Zone's "primary" attribute
type ZonePrimary struct {
// Enabled determines whether AXFR queries (and optionally NOTIFY messages)
// will be enabled for the zone.
Enabled bool `json:"enabled"`
Secondaries []ZoneSecondaryServer `json:"secondaries"`
}
// ZoneSecondaryServer wraps elements of a Zone's "primary.secondary" attribute
type ZoneSecondaryServer struct {
// Read-Only
NetworkIDs []int `json:"networks,omitempty"`
IP string `json:"ip"`
Port int `json:"port,omitempty"`
Notify bool `json:"notify"`
}
// ZoneSecondary wraps a Zone's "secondary" attribute
type ZoneSecondary struct {
// Read-Only fields
Expired bool `json:"expired,omitempty"`
LastXfr int `json:"last_xfr,omitempty"`
Status string `json:"status,omitempty"`
Error *string `json:"error"`
PrimaryIP string `json:"primary_ip,omitempty"`
PrimaryPort int `json:"primary_port,omitempty"`
Enabled bool `json:"enabled"`
TSIG *TSIG `json:"tsig"`
}
// TSIG is a zones transaction signature.
type TSIG struct {
// Key is the encrypted TSIG key(read-only)
Key string `json:"key,omitempty"`
// Whether TSIG is enabled for a secondary zone.
Enabled bool `json:"enabled,omitempty"`
// Which hashing algorithm
Hash string `json:"hash,omitempty"`
// Name of the TSIG key
Name string `json:"name,omitempty"`
}
// NewZone takes a zone domain name and creates a new zone.
func NewZone(zone string) *Zone {
z := Zone{
Zone: zone,
}
return &z
}
// MakePrimary enables Primary, disables Secondary, and sets primary's
// Secondaries to all provided ZoneSecondaryServers
func (z *Zone) MakePrimary(secondaries ...ZoneSecondaryServer) {
z.Secondary = nil
z.Primary = &ZonePrimary{
Enabled: true,
Secondaries: secondaries,
}
if z.Primary.Secondaries == nil {
z.Primary.Secondaries = make([]ZoneSecondaryServer, 0)
}
}
// MakeSecondary enables Secondary, disables Primary, and sets secondary's
// Primary_ip to provided ip.
func (z *Zone) MakeSecondary(ip string) {
z.Secondary = &ZoneSecondary{
Enabled: true,
PrimaryIP: ip,
PrimaryPort: 53,
}
z.Primary = &ZonePrimary{
Enabled: false,
Secondaries: make([]ZoneSecondaryServer, 0),
}
}
// LinkTo sets Link to a target zone domain name and unsets all other configuration properties.
// No other zone configuration properties (such as refresh, retry, etc) may be specified,
// since they are all pulled from the target zone. Linked zones, once created, cannot be
// configured at all and cannot have records added to them. They may only be deleted, which
// does not affect the target zone at all.
func (z *Zone) LinkTo(to string) {
z.Meta = nil
z.TTL = 0
z.NxTTL = 0
z.Retry = 0
z.Refresh = 0
z.Expiry = 0
z.Primary = nil
z.DNSServers = nil
z.NetworkIDs = nil
z.NetworkPools = nil
z.Hostmaster = ""
z.Pool = ""
z.Secondary = nil
z.Link = &to
}

View File

@ -0,0 +1,2 @@
// Package filter contains definitions for NS1 filter chains.
package filter

View File

@ -0,0 +1,182 @@
package filter
// Filter wraps the values of a Record's "filters" attribute
type Filter struct {
Type string `json:"filter"`
Disabled bool `json:"disabled,omitempty"`
Config Config `json:"config"`
}
// Enable a filter.
func (f *Filter) Enable() {
f.Disabled = false
}
// Disable a filter.
func (f *Filter) Disable() {
f.Disabled = true
}
// Config is a flat mapping where values are simple (no slices/maps).
type Config map[string]interface{}
// NewSelFirstN returns a filter that eliminates all but the
// first N answers from the list.
func NewSelFirstN(n int) *Filter {
return &Filter{
Type: "select_first_n",
Config: Config{"N": n},
}
}
// NewShuffle returns a filter that randomly sorts the answers.
func NewShuffle() *Filter {
return &Filter{Type: "shuffle", Config: Config{}}
}
// GEOGRAPHICAL FILTERS
// NewSelFirstRegion returns a filter that keeps only the answers
// that are in the same region as the first answer.
func NewSelFirstRegion() *Filter {
return &Filter{Type: "select_first_n", Config: Config{}}
}
// NewStickyRegion first sorts regions uniquely depending on the IP
// address of the requester, and then groups all answers together by
// region. The same requester always gets the same ordering of regions,
// but answers within each region may be in any order. byNetwork indicates
// whether to apply the 'stickyness' by subnet(not individual IP).
func NewStickyRegion(byNetwork bool) *Filter {
return &Filter{
Type: "sticky_region",
Config: Config{"sticky_by_network": byNetwork},
}
}
// NewGeofenceCountry returns a filter that fences using "country",
// "us_state", and "ca_province" metadata fields in answers. Only
// answers in the same country/state/province as the user (or
// answers with no specified location) are returned. rmNoLoc determines
// whether to remove answers without location on any match.
func NewGeofenceCountry(rmNoLoc bool) *Filter {
return &Filter{
Type: "geofence_country",
Config: Config{"remove_no_location": rmNoLoc},
}
}
// NewGeofenceRegional returns a filter that restricts to answers in
// same geographical region as requester. rmNoGeo determines whether
// to remove answers without georegion on any match.
func NewGeofenceRegional(rmNoGeo bool) *Filter {
return &Filter{
Type: "geofence_regional",
Config: Config{"remove_no_georegion": rmNoGeo},
}
}
// NewGeotargetCountry returns a filter that sorts answers by distance
// to requester by country, US state, and/or Canadian province.
func NewGeotargetCountry() *Filter {
return &Filter{Type: "geofence_country", Config: Config{}}
}
// NewGeotargetLatLong returns a filter that sorts answers by distance
// to user using lat/long.
func NewGeotargetLatLong() *Filter {
return &Filter{Type: "geotarget_latlong", Config: Config{}}
}
// NewGeotargetRegional returns a filter that sorts answers by distance
// to user by geographical region.
func NewGeotargetRegional() *Filter {
return &Filter{Type: "geotarget_regional", Config: Config{}}
}
// NETWORK FILTERS
// NewSticky returns a filter that sorts answers uniquely depending
// on the IP address of the requester. The same requester always
// gets the same ordering of answers. byNetwork indicates whether
// to apply the 'stickyness' by subnet(not individual IP).
func NewSticky(byNetwork bool) *Filter {
return &Filter{
Type: "sticky",
Config: Config{"sticky_by_network": byNetwork},
}
}
// NewWeightedSticky returns a filter that shuffles answers randomly
// per-requester based on weight. byNetwork indicates whether to
// apply the 'stickyness' by subnet(not individual IP).
func NewWeightedSticky(byNetwork bool) *Filter {
return &Filter{
Type: "weighted_sticky",
Config: Config{"sticky_by_network": byNetwork},
}
}
// NewIPv4PrefixShuffle returns a filter that randomly selects
// IPv4 addresses from prefix list. This filter can only be used
// A records. n is the number of IPs to randomly select per answer.
func NewIPv4PrefixShuffle(n int) *Filter {
return &Filter{
Type: "ipv4_prefix_shuffle",
Config: Config{"N": n},
}
}
// NewNetfenceASN returns a filter that restricts to answers where
// the ASN of requester IP matches ASN list. rmNoASN determines
// whether to remove answers without asn list on any match.
func NewNetfenceASN(rmNoASN bool) *Filter {
return &Filter{
Type: "netfence_asn",
Config: Config{"remove_no_asn": rmNoASN},
}
}
// NewNetfencePrefix returns a filter that restricts to answers where
// requester IP matches prefix list. rmNoIPPrefix determines
// whether to remove answers without ip prefixes on any match.
func NewNetfencePrefix(rmNoIPPrefix bool) *Filter {
return &Filter{
Type: "netfence_prefix",
Config: Config{"remove_no_ip_prefixes": rmNoIPPrefix},
}
}
// STATUS FILTERS
// NewUp returns a filter that eliminates all answers where
// the 'up' metadata field is not true.
func NewUp() *Filter {
return &Filter{Type: "up", Config: Config{}}
}
// NewPriority returns a filter that fails over according to
// prioritized answer tiers.
func NewPriority() *Filter {
return &Filter{Type: "priority", Config: Config{}}
}
// NewShedLoad returns a filter that "sheds" traffic to answers
// based on load, using one of several load metrics. You must set
// values for low_watermark, high_watermark, and the configured
// load metric, for each answer you intend to subject to load
// shedding.
func NewShedLoad(metric string) *Filter {
return &Filter{
Type: "shed_load",
Config: Config{"metric": metric},
}
}
// TRAFFIC FILTERS
// NewWeightedShuffle returns a filter that shuffles answers
// randomly based on their weight.
func NewWeightedShuffle() *Filter {
return &Filter{Type: "weighted_shuffle", Config: Config{}}
}

View File

@ -0,0 +1,4 @@
package monitor
// Config is a flat mapping where values are simple (no slices/maps).
type Config map[string]interface{}

View File

@ -0,0 +1,2 @@
// Package monitor contains definitions for NS1 monitoring jobs.
package monitor

181
vendor/gopkg.in/ns1/ns1-go.v2/rest/model/monitor/job.go generated vendored Normal file
View File

@ -0,0 +1,181 @@
package monitor
// Job wraps an NS1 /monitoring/jobs resource
type Job struct {
ID string `json:"id,omitempty"`
// The id of the notification list to send notifications to.
NotifyListID string `json:"notify_list"`
// Type of monitor to be run.
// Available job types:
// - http: Do an HTTP request against a webserver
// - dns: Do a DNS lookup against a nameserver
// - tcp: Connect to a TCP port on a host
// - ping: Ping a host using ICMP packets
Type string `json:"job_type"`
// Configuration dictionary(key/vals depend on the jobs' type).
Config Config `json:"config"`
// The current status of the monitor.
Status map[string]*Status `json:"status,omitempty"`
// Rules for determining failure conditions.
Rules []*Rule `json:"rules,omitempty"`
// List of regions in which to run the monitor.
// eg, ["dal", "sin", "sjc", "lga", "ams"]
Regions []string `json:"regions"`
// Indicates if the job is active or temporarily disabled.
Active bool `json:"active"`
// Frequency(in seconds), at which to run the monitor.
Frequency int `json:"frequency"`
// The policy for determining the monitor's global status based
// on the status of the job in all regions.
// Available policies:
// - quorum: Status change when majority status
// - all: Status change only when all regions are in agreement
// - one: Status change if any region changes
Policy string `json:"policy"`
// Controls behavior of how the job is assigned to monitoring regions.
// Currently this must be fixed — indicating monitoring regions are explicitly chosen.
RegionScope string `json:"region_scope"`
// Freeform notes to be included in any notifications about this job,
// e.g., instructions for operators who will receive the notifications.
Notes string `json:"notes,omitempty"`
// A free-form display name for the monitoring job.
Name string `json:"name"`
// Time(in seconds) between repeat notifications of a failed job.
// Set to 0 to disable repeating notifications.
NotifyRepeat int `json:"notify_repeat"`
// If true, on any apparent state change, the job is quickly re-run after
// one second to confirm the state change before notification.
RapidRecheck bool `json:"rapid_recheck"`
// Time(in seconds) after a failure to wait before sending a notification.
NotifyDelay int `json:"notify_delay"`
// If true, notifications are sent for any regional failure (and failback if desired),
// in addition to global state notifications.
NotifyRegional bool `json:"notify_regional"`
// If true, a notification is sent when a job returns to an "up" state.
NotifyFailback bool `json:"notify_failback"`
}
// Activate a monitoring job.
func (j *Job) Activate() {
j.Active = true
}
// Deactivate a monitoring job.
func (j *Job) Deactivate() {
j.Active = false
}
// Result wraps an element of a JobType's "results" attribute
type Result struct {
Comparators []string `json:"comparators"`
Metric bool `json:"metric"`
Validator string `json:"validator"`
ShortDesc string `json:"shortdesc"`
Type string `json:"type"`
Desc string `json:"desc"`
}
// Status wraps an value of a Job's "status" attribute
type Status struct {
Since int `json:"since"`
Status string `json:"status"`
}
// StatusLog wraps an NS1 /monitoring/history resource
type StatusLog struct {
Job string `json:"job"`
Region string `json:"region"`
Status string `json:"status"`
Since int `json:"since"`
Until int `json:"until"`
}
// Rule wraps an element of a Job's "rules" attribute
type Rule struct {
Key string `json:"key"`
Value interface{} `json:"value"`
Comparison string `json:"comparison"`
}
// NewHTTPConfig constructs/returns a job configuration for HTTP type jobs.
// url is the URL to query. (Required)
// method is the HTTP method(valid methods are HEAD, GET, and POST).
// ua is the user agent text in the request header.
// auth is the authorization header to use in request.
// connTimeout is the timeout(in sec) to wait for query output.
func NewHTTPConfig(url, method, ua, auth string, connTimeout int) *Config {
return &Config{
"url": url, // Required
"method": method,
"user_agent": ua,
"auth": auth,
"connection_timeout": connTimeout,
}
}
// NewDNSConfig constructs/returns a job configuration for DNS type jobs.
// host is the IP address or hostname of the nameserver to query. (Required)
// domain name to query. (Required)
// port is the dns port to query on host.
// t is the type of the DNS record type to query.
// respTimeout is the timeout(in ms) after sending query to wait for the output.
func NewDNSConfig(host, domain string, port int, t string, respTimeout int) *Config {
return &Config{
"host": host, // Required
"domain": domain, // Required
"port": port,
"type": t,
"response_timeout": respTimeout,
}
}
// NewTCPConfig constructs/returns a job configuration for TCP type jobs.
// host is the IP address or hostname to connect to. (Required)
// port is the tcp port to connect to on host. (Required)
// connTimeout is the timeout(in ms) before giving up on trying to connect.
// respTimeout is the timeout(in sec) after connecting to wait for output.
// send is the string to send to the host upon connecting.
// ssl determines whether to attempt negotiating an SSL connection.
func NewTCPConfig(host string, port, connTimeout, respTimeout int, send string, ssl bool) *Config {
return &Config{
"host": host, // Required
"port": port, // Required
"connection_timeout": connTimeout,
"response_timeout": respTimeout,
"send": send,
"ssl": ssl,
}
}
// NewPINGConfig constructs/returns a job configuration for PING type jobs.
// host is the IP address or hostname to ping. (Required)
// timeout is the timeout(in ms) before marking the host as failed.
// count is the number of packets to send.
// interval is the minimum time(in ms) to wait between sending each packet.
func NewPINGConfig(host string, timeout, count, interval int) *Config {
return &Config{
"host": host, // Required
"timeout": timeout,
"count": count,
"interval": interval,
}
}

View File

@ -0,0 +1,72 @@
package monitor
// NotifyList wraps notifications.
type NotifyList struct {
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Notifications []*Notification `json:"notify_list,omitempty"`
}
// Notification represents endpoint to alert to.
type Notification struct {
Type string `json:"type,omitempty"`
Config Config `json:"config,omitempty"`
}
// NewNotifyList returns a notify list that alerts via the given notifications.
func NewNotifyList(name string, nl ...*Notification) *NotifyList {
if nl == nil {
nl = []*Notification{}
}
return &NotifyList{Name: name, Notifications: nl}
}
// NewUserNotification returns a notification that alerts via user.
func NewUserNotification(username string) *Notification {
return &Notification{
Type: "user",
Config: Config{"user": username}}
}
// NewEmailNotification returns a notification that alerts via email.
func NewEmailNotification(email string) *Notification {
return &Notification{
Type: "email",
Config: Config{"email": email}}
}
// NewFeedNotification returns a notification that alerts via datafeed.
func NewFeedNotification(sourceID string) *Notification {
return &Notification{
Type: "datafeed",
Config: Config{"sourceid": sourceID}}
}
// NewWebNotification returns a notification that alerts via webhook.
func NewWebNotification(url string) *Notification {
return &Notification{
Type: "webhook",
Config: Config{"url": url}}
}
// NewPagerDutyNotification returns a notification that alerts via pagerduty.
func NewPagerDutyNotification(key string) *Notification {
return &Notification{
Type: "pagerduty",
Config: Config{"service_key": key}}
}
// NewHipChatNotification returns a notification that alerts via hipchat.
func NewHipChatNotification(token, room string) *Notification {
return &Notification{
Type: "hipchat",
Config: Config{"token": token, "room": room}}
}
// NewSlackNotification returns a notification that alerts via slack.
func NewSlackNotification(url, username, channel string) *Notification {
return &Notification{
Type: "slack",
Config: Config{"url": url, "username": username, "channel": channel}}
}

134
vendor/gopkg.in/ns1/ns1-go.v2/rest/monitor_job.go generated vendored Normal file
View File

@ -0,0 +1,134 @@
package rest
import (
"fmt"
"net/http"
"net/url"
"gopkg.in/ns1/ns1-go.v2/rest/model/monitor"
)
// JobsService handles 'monitoring/jobs' endpoint.
type JobsService service
// List returns all monitoring jobs for the account.
//
// NS1 API docs: https://ns1.com/api/#jobs-get
func (s *JobsService) List() ([]*monitor.Job, *http.Response, error) {
req, err := s.client.NewRequest("GET", "monitoring/jobs", nil)
if err != nil {
return nil, nil, err
}
mjl := []*monitor.Job{}
resp, err := s.client.Do(req, &mjl)
if err != nil {
return nil, resp, err
}
return mjl, resp, nil
}
// Get takes an ID and returns details for a specific monitoring job.
//
// NS1 API docs: https://ns1.com/api/#jobs-jobid-get
func (s *JobsService) Get(id string) (*monitor.Job, *http.Response, error) {
path := fmt.Sprintf("%s/%s", "monitoring/jobs", id)
req, err := s.client.NewRequest("GET", path, nil)
if err != nil {
return nil, nil, err
}
var mj monitor.Job
resp, err := s.client.Do(req, &mj)
if err != nil {
return nil, resp, err
}
return &mj, resp, nil
}
// Create takes a *MonitoringJob and creates a new monitoring job.
//
// NS1 API docs: https://ns1.com/api/#jobs-put
func (s *JobsService) Create(mj *monitor.Job) (*http.Response, error) {
path := fmt.Sprintf("%s/%s", "monitoring/jobs", mj.ID)
req, err := s.client.NewRequest("PUT", path, &mj)
if err != nil {
return nil, err
}
// Update mon jobs' fields with data from api(ensure consistent)
resp, err := s.client.Do(req, &mj)
if err != nil {
return resp, err
}
return resp, nil
}
// Update takes a *MonitoringJob and change the configuration details of an existing monitoring job.
//
// NS1 API docs: https://ns1.com/api/#jobs-jobid-post
func (s *JobsService) Update(mj *monitor.Job) (*http.Response, error) {
path := fmt.Sprintf("%s/%s", "monitoring/jobs", mj.ID)
req, err := s.client.NewRequest("POST", path, &mj)
if err != nil {
return nil, err
}
// Update mon jobs' fields with data from api(ensure consistent)
resp, err := s.client.Do(req, &mj)
if err != nil {
return resp, err
}
return resp, nil
}
// Delete takes an ID and immediately terminates and deletes and existing monitoring job.
//
// NS1 API docs: https://ns1.com/api/#jobs-jobid-delete
func (s *JobsService) Delete(id string) (*http.Response, error) {
path := fmt.Sprintf("%s/%s", "monitoring/jobs", id)
req, err := s.client.NewRequest("DELETE", path, nil)
if err != nil {
return nil, err
}
resp, err := s.client.Do(req, nil)
if err != nil {
return resp, err
}
return resp, nil
}
// History takes an ID and returns status log history for a specific monitoring job.
//
// NS1 API docs: https://ns1.com/api/#history-get
func (s *JobsService) History(id string, opts ...func(*url.Values)) ([]*monitor.StatusLog, *http.Response, error) {
v := url.Values{}
for _, opt := range opts {
opt(&v)
}
path := fmt.Sprintf("%s/%s?%s", "monitoring/history", id, v.Encode())
req, err := s.client.NewRequest("GET", path, nil)
if err != nil {
return nil, nil, err
}
var slgs []*monitor.StatusLog
resp, err := s.client.Do(req, &slgs)
if err != nil {
return nil, resp, err
}
return slgs, resp, nil
}

126
vendor/gopkg.in/ns1/ns1-go.v2/rest/monitor_notify.go generated vendored Normal file
View File

@ -0,0 +1,126 @@
package rest
import (
"errors"
"fmt"
"net/http"
"gopkg.in/ns1/ns1-go.v2/rest/model/monitor"
)
// NotificationsService handles 'monitoring/lists' endpoint.
type NotificationsService service
// List returns all configured notification lists.
//
// NS1 API docs: https://ns1.com/api/#lists-get
func (s *NotificationsService) List() ([]*monitor.NotifyList, *http.Response, error) {
req, err := s.client.NewRequest("GET", "lists", nil)
if err != nil {
return nil, nil, err
}
nl := []*monitor.NotifyList{}
resp, err := s.client.Do(req, &nl)
if err != nil {
return nil, resp, err
}
return nl, resp, nil
}
// Get returns the details and notifiers associated with a specific notification list.
//
// NS1 API docs: https://ns1.com/api/#lists-listid-get
func (s *NotificationsService) Get(listID string) (*monitor.NotifyList, *http.Response, error) {
path := fmt.Sprintf("%s/%s", "lists", listID)
req, err := s.client.NewRequest("GET", path, nil)
if err != nil {
return nil, nil, err
}
var nl monitor.NotifyList
resp, err := s.client.Do(req, &nl)
if err != nil {
switch err.(type) {
case *Error:
if err.(*Error).Message == "unknown notification list" {
return nil, resp, ErrListMissing
}
}
return nil, resp, err
}
return &nl, resp, nil
}
// Create takes a *NotifyList and creates a new notify list.
//
// NS1 API docs: https://ns1.com/api/#lists-put
func (s *NotificationsService) Create(nl *monitor.NotifyList) (*http.Response, error) {
req, err := s.client.NewRequest("PUT", "lists", &nl)
if err != nil {
return nil, err
}
// Update notify list fields with data from api(ensure consistent)
resp, err := s.client.Do(req, &nl)
if err != nil {
switch err.(type) {
case *Error:
if err.(*Error).Message == fmt.Sprintf("notification list with name \"%s\" exists", nl.Name) {
return resp, ErrListExists
}
}
return resp, err
}
return resp, nil
}
// Update adds or removes entries or otherwise update a notification list.
//
// NS1 API docs: https://ns1.com/api/#list-listid-post
func (s *NotificationsService) Update(nl *monitor.NotifyList) (*http.Response, error) {
path := fmt.Sprintf("%s/%s", "lists", nl.ID)
req, err := s.client.NewRequest("POST", path, &nl)
if err != nil {
return nil, err
}
// Update mon lists' fields with data from api(ensure consistent)
resp, err := s.client.Do(req, &nl)
if err != nil {
return resp, err
}
return resp, nil
}
// Delete immediately deletes an existing notification list.
//
// NS1 API docs: https://ns1.com/api/#lists-listid-delete
func (s *NotificationsService) Delete(listID string) (*http.Response, error) {
path := fmt.Sprintf("%s/%s", "lists", listID)
req, err := s.client.NewRequest("DELETE", path, nil)
if err != nil {
return nil, err
}
resp, err := s.client.Do(req, nil)
if err != nil {
return resp, err
}
return resp, nil
}
var (
// ErrListExists bundles PUT create error.
ErrListExists = errors.New("notify List already exists")
// ErrListMissing bundles GET/POST/DELETE error.
ErrListMissing = errors.New("notify List does not exist")
)

130
vendor/gopkg.in/ns1/ns1-go.v2/rest/record.go generated vendored Normal file
View File

@ -0,0 +1,130 @@
package rest
import (
"errors"
"fmt"
"net/http"
"gopkg.in/ns1/ns1-go.v2/rest/model/dns"
)
// RecordsService handles 'zones/ZONE/DOMAIN/TYPE' endpoint.
type RecordsService service
// Get takes a zone, domain and record type t and returns full configuration for a DNS record.
//
// NS1 API docs: https://ns1.com/api/#record-get
func (s *RecordsService) Get(zone, domain, t string) (*dns.Record, *http.Response, error) {
path := fmt.Sprintf("zones/%s/%s/%s", zone, domain, t)
req, err := s.client.NewRequest("GET", path, nil)
if err != nil {
return nil, nil, err
}
var r dns.Record
resp, err := s.client.Do(req, &r)
if err != nil {
switch err.(type) {
case *Error:
if err.(*Error).Message == "record not found" {
return nil, resp, ErrRecordMissing
}
}
return nil, resp, err
}
return &r, resp, nil
}
// Create takes a *Record and creates a new DNS record in the specified zone, for the specified domain, of the given record type.
//
// The given record must have at least one answer.
// NS1 API docs: https://ns1.com/api/#record-put
func (s *RecordsService) Create(r *dns.Record) (*http.Response, error) {
path := fmt.Sprintf("zones/%s/%s/%s", r.Zone, r.Domain, r.Type)
req, err := s.client.NewRequest("PUT", path, &r)
if err != nil {
return nil, err
}
// Update record fields with data from api(ensure consistent)
resp, err := s.client.Do(req, &r)
if err != nil {
switch err.(type) {
case *Error:
switch err.(*Error).Message {
case "zone not found":
return resp, ErrZoneMissing
case "record already exists":
return resp, ErrRecordExists
}
}
return resp, err
}
return resp, nil
}
// Update takes a *Record and modifies configuration details for an existing DNS record.
//
// Only the fields to be updated are required in the given record.
// NS1 API docs: https://ns1.com/api/#record-post
func (s *RecordsService) Update(r *dns.Record) (*http.Response, error) {
path := fmt.Sprintf("zones/%s/%s/%s", r.Zone, r.Domain, r.Type)
req, err := s.client.NewRequest("POST", path, &r)
if err != nil {
return nil, err
}
// Update records fields with data from api(ensure consistent)
resp, err := s.client.Do(req, &r)
if err != nil {
switch err.(type) {
case *Error:
switch err.(*Error).Message {
case "zone not found":
return resp, ErrZoneMissing
case "record already exists":
return resp, ErrRecordExists
}
}
return resp, err
}
return resp, nil
}
// Delete takes a zone, domain and record type t and removes an existing record and all associated answers and configuration details.
//
// NS1 API docs: https://ns1.com/api/#record-delete
func (s *RecordsService) Delete(zone string, domain string, t string) (*http.Response, error) {
path := fmt.Sprintf("zones/%s/%s/%s", zone, domain, t)
req, err := s.client.NewRequest("DELETE", path, nil)
if err != nil {
return nil, err
}
resp, err := s.client.Do(req, nil)
if err != nil {
switch err.(type) {
case *Error:
if err.(*Error).Message == "record not found" {
return resp, ErrRecordMissing
}
}
return resp, err
}
return resp, nil
}
var (
// ErrRecordExists bundles PUT create error.
ErrRecordExists = errors.New("record already exists")
// ErrRecordMissing bundles GET/POST/DELETE error.
ErrRecordMissing = errors.New("record does not exist")
)

15
vendor/gopkg.in/ns1/ns1-go.v2/rest/stat.go generated vendored Normal file
View File

@ -0,0 +1,15 @@
package rest
// // GetQPSStats returns current queries per second (QPS) for the account
// func (c APIClient) GetQPSStats() (v float64, err error) {
// var s map[string]float64
// _, err = c.doHTTPUnmarshal("GET", "https://api.nsone.net/v1/stats/qps", nil, &s)
// if err != nil {
// return v, err
// }
// v, found := s["qps"]
// if !found {
// return v, errors.New("Could not find 'qps' key in returned data")
// }
// return v, nil
// }

42
vendor/gopkg.in/ns1/ns1-go.v2/rest/util.go generated vendored Normal file
View File

@ -0,0 +1,42 @@
package rest
import (
"log"
"net/http"
)
// DoerFunc satisfies Interface. DoerFuncs are useful for adding
// logging/instrumentation to the http.Client that is used
// within the rest.APIClient.
type DoerFunc func(*http.Request) (*http.Response, error)
// Do is implementation of rest.Doer interface. Calls itself on the
// given http.Request.
func (f DoerFunc) Do(r *http.Request) (*http.Response, error) {
return f(r)
}
// A Decorator wraps a Doer with extra behavior, and doesnt
// affect the behavior of other instances of the same type.
type Decorator func(Doer) Doer
// Decorate decorates a Doer c with all the given Decorators, in order.
// Core object(Doer instance) that we want to apply layers(Decorator slice) to.
func Decorate(d Doer, ds ...Decorator) Doer {
decorated := d
for _, decorate := range ds {
decorated = decorate(decorated)
}
return decorated
}
// Logging returns a Decorator that logs a Doer's requests.
// Dependency injection for the logger instance(inside the closures environment).
func Logging(l *log.Logger) Decorator {
return func(d Doer) Doer {
return DoerFunc(func(r *http.Request) (*http.Response, error) {
l.Printf("%s: %s %s", r.UserAgent(), r.Method, r.URL)
return d.Do(r)
})
}
}

140
vendor/gopkg.in/ns1/ns1-go.v2/rest/zone.go generated vendored Normal file
View File

@ -0,0 +1,140 @@
package rest
import (
"errors"
"fmt"
"net/http"
"gopkg.in/ns1/ns1-go.v2/rest/model/dns"
)
// ZonesService handles 'zones' endpoint.
type ZonesService service
// List returns all active zones and basic zone configuration details for each.
//
// NS1 API docs: https://ns1.com/api/#zones-get
func (s *ZonesService) List() ([]*dns.Zone, *http.Response, error) {
req, err := s.client.NewRequest("GET", "zones", nil)
if err != nil {
return nil, nil, err
}
zl := []*dns.Zone{}
resp, err := s.client.Do(req, &zl)
if err != nil {
return nil, resp, err
}
return zl, resp, nil
}
// Get takes a zone name and returns a single active zone and its basic configuration details.
//
// NS1 API docs: https://ns1.com/api/#zones-zone-get
func (s *ZonesService) Get(zone string) (*dns.Zone, *http.Response, error) {
path := fmt.Sprintf("zones/%s", zone)
req, err := s.client.NewRequest("GET", path, nil)
if err != nil {
return nil, nil, err
}
var z dns.Zone
resp, err := s.client.Do(req, &z)
if err != nil {
switch err.(type) {
case *Error:
if err.(*Error).Message == "zone not found" {
return nil, resp, ErrZoneMissing
}
}
return nil, resp, err
}
return &z, resp, nil
}
// Create takes a *Zone and creates a new DNS zone.
//
// NS1 API docs: https://ns1.com/api/#zones-put
func (s *ZonesService) Create(z *dns.Zone) (*http.Response, error) {
path := fmt.Sprintf("zones/%s", z.Zone)
req, err := s.client.NewRequest("PUT", path, &z)
if err != nil {
return nil, err
}
// Update zones fields with data from api(ensure consistent)
resp, err := s.client.Do(req, &z)
if err != nil {
switch err.(type) {
case *Error:
if err.(*Error).Message == "zone already exists" {
return resp, ErrZoneExists
}
}
return resp, err
}
return resp, nil
}
// Update takes a *Zone and modifies basic details of a DNS zone.
//
// NS1 API docs: https://ns1.com/api/#zones-post
func (s *ZonesService) Update(z *dns.Zone) (*http.Response, error) {
path := fmt.Sprintf("zones/%s", z.Zone)
req, err := s.client.NewRequest("POST", path, &z)
if err != nil {
return nil, err
}
// Update zones fields with data from api(ensure consistent)
resp, err := s.client.Do(req, &z)
if err != nil {
switch err.(type) {
case *Error:
if err.(*Error).Message == "zone not found" {
return resp, ErrZoneMissing
}
}
return resp, err
}
return resp, nil
}
// Delete takes a zone and destroys an existing DNS zone and all records in the zone.
//
// NS1 API docs: https://ns1.com/api/#zones-delete
func (s *ZonesService) Delete(zone string) (*http.Response, error) {
path := fmt.Sprintf("zones/%s", zone)
req, err := s.client.NewRequest("DELETE", path, nil)
if err != nil {
return nil, err
}
resp, err := s.client.Do(req, nil)
if err != nil {
switch err.(type) {
case *Error:
if err.(*Error).Message == "zone not found" {
return resp, ErrZoneMissing
}
}
return resp, err
}
return resp, nil
}
var (
// ErrZoneExists bundles PUT create error.
ErrZoneExists = errors.New("zone already exists")
// ErrZoneMissing bundles GET/POST/DELETE error.
ErrZoneMissing = errors.New("zone does not exist")
)

36
vendor/vendor.json vendored
View File

@ -626,6 +626,42 @@
"revision": "c7b8227c83007befd67b324a64c969ebc1d7475d",
"revisionTime": "2016-11-07T22:51:02Z"
},
{
"checksumSHA1": "e7eKqt/2RnmGPYJtcJd4IY2M/DU=",
"path": "gopkg.in/ns1/ns1-go.v2/rest",
"revision": "e2aebc8e980e326990999e4351c1c026c9d00c4a",
"revisionTime": "2017-03-21T06:31:15Z"
},
{
"checksumSHA1": "tdMxXKsUHn3yZpur14ZNLMVyQJM=",
"path": "gopkg.in/ns1/ns1-go.v2/rest/model/account",
"revision": "e2aebc8e980e326990999e4351c1c026c9d00c4a",
"revisionTime": "2017-03-21T06:31:15Z"
},
{
"checksumSHA1": "gBVND8veklEQV0gxF3lERV6mSZk=",
"path": "gopkg.in/ns1/ns1-go.v2/rest/model/data",
"revision": "e2aebc8e980e326990999e4351c1c026c9d00c4a",
"revisionTime": "2017-03-21T06:31:15Z"
},
{
"checksumSHA1": "GbL7ThrBZfKs1lhzguxzscIynac=",
"path": "gopkg.in/ns1/ns1-go.v2/rest/model/dns",
"revision": "e2aebc8e980e326990999e4351c1c026c9d00c4a",
"revisionTime": "2017-03-21T06:31:15Z"
},
{
"checksumSHA1": "CuurmNep8iMdYFodxRxAeewowsQ=",
"path": "gopkg.in/ns1/ns1-go.v2/rest/model/filter",
"revision": "e2aebc8e980e326990999e4351c1c026c9d00c4a",
"revisionTime": "2017-03-21T06:31:15Z"
},
{
"checksumSHA1": "B0C8F5th11AHl1fo8k0I8+DvrjE=",
"path": "gopkg.in/ns1/ns1-go.v2/rest/model/monitor",
"revision": "e2aebc8e980e326990999e4351c1c026c9d00c4a",
"revisionTime": "2017-03-21T06:31:15Z"
},
{
"checksumSHA1": "XvQ3McEKtKXKcU4lL447qeKi1RM=",
"path": "gopkg.in/sourcemap.v1",