From c5e0227180662890b227fe4512c8fc81e95f594f Mon Sep 17 00:00:00 2001 From: Enrique Gonzalez Date: Thu, 9 Apr 2020 14:37:45 +0200 Subject: [PATCH 001/175] feat: add regex domain filters Signed-off-by: Enrique Gonzalez --- endpoint/domain_filter.go | 48 ++++++++++++++++++++++++++++-- main.go | 8 ++++- pkg/apis/externaldns/types.go | 6 ++++ pkg/apis/externaldns/types_test.go | 8 +++++ 4 files changed, 66 insertions(+), 4 deletions(-) diff --git a/endpoint/domain_filter.go b/endpoint/domain_filter.go index ced496d0d..4678aa9ee 100644 --- a/endpoint/domain_filter.go +++ b/endpoint/domain_filter.go @@ -17,7 +17,10 @@ limitations under the License. package endpoint import ( + "regexp" "strings" + + log "github.com/sirupsen/logrus" ) // DomainFilter holds a lists of valid domain names @@ -26,6 +29,10 @@ type DomainFilter struct { Filters []string // exclude define what domains not to match exclude []string + // regex defines a regular expression to match the domains + regex string + // regexExclusion defines a regular expression to exclude the domains matched + regexExclusion string } // prepareFilters provides consistent trimming for filters/exclude params @@ -39,16 +46,26 @@ func prepareFilters(filters []string) []string { // NewDomainFilterWithExclusions returns a new DomainFilter, given a list of matches and exclusions func NewDomainFilterWithExclusions(domainFilters []string, excludeDomains []string) DomainFilter { - return DomainFilter{prepareFilters(domainFilters), prepareFilters(excludeDomains)} + return DomainFilter{prepareFilters(domainFilters), prepareFilters(excludeDomains), "", ""} } // NewDomainFilter returns a new DomainFilter given a comma separated list of domains func NewDomainFilter(domainFilters []string) DomainFilter { - return DomainFilter{prepareFilters(domainFilters), []string{}} + return DomainFilter{prepareFilters(domainFilters), []string{}, "", ""} +} + +// NewRegexDomainFilter returns a new DomainFilter given a regular expression +func NewRegexDomainFilter(regexDomainFilter string, regexDomainExclusion string) DomainFilter { + return DomainFilter{[]string{}, []string{}, regexDomainFilter, regexDomainExclusion} } // Match checks whether a domain can be found in the DomainFilter. +// RegexFilter takes precedence over Filters func (df DomainFilter) Match(domain string) bool { + if df.regex != "" { + return matchRegex(df.regex, df.regexExclusion, domain) + } + return matchFilter(df.Filters, domain, true) && !matchFilter(df.exclude, domain, false) } @@ -78,9 +95,34 @@ func matchFilter(filters []string, domain string, emptyval bool) bool { return false } +// matchRegex determines if a domain matches the configured regular expressions in the DomainFilter. +// The negativeRegex, if set, takes precedence over regex. Therefore, +// matchRegex returns true when only regex regular expression matches the domain. +// Otherwise, if either negativeRegex matches or regex does not match the domain, it will return false. +func matchRegex(regex string, negativeRegex string, domain string) bool { + strippedDomain := strings.ToLower(strings.TrimSuffix(domain, ".")) + + if negativeRegex != "" { + match, err := regexp.MatchString(negativeRegex, strippedDomain) + if err != nil { + log.Errorf("Failed to filter domain %s with the regex-exclusion filter: %v", domain, err) + } + if match { + return false + } + } + match, err := regexp.MatchString(regex, strippedDomain) + if err != nil { + log.Errorf("Failed to filter domain %s with the regex filter: %v", domain, err) + } + return match +} + // IsConfigured returns true if DomainFilter is configured, false otherwise func (df DomainFilter) IsConfigured() bool { - if len(df.Filters) == 1 { + if df.regex != "" { + return true + } else if len(df.Filters) == 1 { return df.Filters[0] != "" } return len(df.Filters) > 0 diff --git a/main.go b/main.go index b31b0884c..ddb51ee0c 100644 --- a/main.go +++ b/main.go @@ -115,7 +115,13 @@ func main() { // Combine multiple sources into a single, deduplicated source. endpointsSource := source.NewDedupSource(source.NewMultiSource(sources)) - domainFilter := endpoint.NewDomainFilterWithExclusions(cfg.DomainFilter, cfg.ExcludeDomains) + // RegexDomainFilter overrides DomainFilter + var domainFilter endpoint.DomainFilter + if cfg.RegexDomainFilter != "" { + domainFilter = endpoint.NewRegexDomainFilter(cfg.RegexDomainFilter, cfg.RegexDomainExclusion) + } else { + domainFilter = endpoint.NewDomainFilterWithExclusions(cfg.DomainFilter, cfg.ExcludeDomains) + } zoneIDFilter := provider.NewZoneIDFilter(cfg.ZoneIDFilter) zoneTypeFilter := provider.NewZoneTypeFilter(cfg.AWSZoneType) zoneTagFilter := provider.NewZoneTagFilter(cfg.AWSZoneTagFilter) diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index c567a68ea..854a6711d 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -61,6 +61,8 @@ type Config struct { GoogleBatchChangeInterval time.Duration DomainFilter []string ExcludeDomains []string + RegexDomainFilter string + RegexDomainExclusion string ZoneIDFilter []string AlibabaCloudConfigFile string AlibabaCloudZoneType string @@ -164,6 +166,8 @@ var defaultConfig = &Config{ GoogleBatchChangeInterval: time.Second, DomainFilter: []string{}, ExcludeDomains: []string{}, + RegexDomainFilter: "", + RegexDomainExclusion: "", AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json", AWSZoneType: "", AWSZoneTagFilter: []string{}, @@ -315,6 +319,8 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, aws-sd, google, azure, azure-dns, azure-private-dns, cloudflare, rcodezero, digitalocean, dnsimple, akamai, infoblox, dyn, designate, coredns, skydns, inmemory, ovh, pdns, oci, exoscale, linode, rfc2136, ns1, transip, vinyldns, rdns)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "aws-sd", "google", "azure", "azure-dns", "azure-private-dns", "alibabacloud", "cloudflare", "rcodezero", "digitalocean", "dnsimple", "akamai", "infoblox", "dyn", "designate", "coredns", "skydns", "inmemory", "ovh", "pdns", "oci", "exoscale", "linode", "rfc2136", "ns1", "transip", "vinyldns", "rdns") app.Flag("domain-filter", "Limit possible target zones by a domain suffix; specify multiple times for multiple domains (optional)").Default("").StringsVar(&cfg.DomainFilter) app.Flag("exclude-domains", "Exclude subdomains (optional)").Default("").StringsVar(&cfg.ExcludeDomains) + app.Flag("regex-domain-filter", "Limit possible domains and target zones by a Regex filter; Overrides domain-filter (optional)").Default("").StringVar(&cfg.RegexDomainFilter) + app.Flag("regex-domain-exclusion", "Regex filter that excludes domains and target zones matched by regex-domain-filter (optional)").Default("").StringVar(&cfg.RegexDomainExclusion) app.Flag("zone-id-filter", "Filter target zones by hosted zone id; specify multiple times for multiple zones (optional)").Default("").StringsVar(&cfg.ZoneIDFilter) app.Flag("google-project", "When using the Google provider, current project is auto-detected, when running on GCP. Specify other project with this. Must be specified when running outside GCP.").Default(defaultConfig.GoogleProject).StringVar(&cfg.GoogleProject) app.Flag("google-batch-change-size", "When using the Google provider, set the maximum number of changes that will be applied in each batch.").Default(strconv.Itoa(defaultConfig.GoogleBatchChangeSize)).IntVar(&cfg.GoogleBatchChangeSize) diff --git a/pkg/apis/externaldns/types_test.go b/pkg/apis/externaldns/types_test.go index 2257f410f..dba88e74e 100644 --- a/pkg/apis/externaldns/types_test.go +++ b/pkg/apis/externaldns/types_test.go @@ -44,6 +44,8 @@ var ( GoogleBatchChangeInterval: time.Second, DomainFilter: []string{""}, ExcludeDomains: []string{""}, + RegexDomainFilter: "", + RegexDomainExclusion: "", ZoneIDFilter: []string{""}, AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json", AWSZoneType: "", @@ -117,6 +119,8 @@ var ( GoogleBatchChangeInterval: time.Second * 2, DomainFilter: []string{"example.org", "company.com"}, ExcludeDomains: []string{"xapi.example.org", "xapi.company.com"}, + RegexDomainFilter: "(example\\.org|company\\.com)$", + RegexDomainExclusion: "xapi\\.(example\\.org|company\\.com)$", ZoneIDFilter: []string{"/hostedzone/ZTST1", "/hostedzone/ZTST2"}, AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json", AWSZoneType: "private", @@ -247,6 +251,8 @@ func TestParseFlags(t *testing.T) { "--domain-filter=company.com", "--exclude-domains=xapi.example.org", "--exclude-domains=xapi.company.com", + "--regex-domain-filter=(example\\.org|company\\.com)$", + "--regex-domain-exclusion=xapi\\.(example\\.org|company\\.com)$", "--zone-id-filter=/hostedzone/ZTST1", "--zone-id-filter=/hostedzone/ZTST2", "--aws-zone-type=private", @@ -325,6 +331,8 @@ func TestParseFlags(t *testing.T) { "EXTERNAL_DNS_OVH_ENDPOINT": "ovh-ca", "EXTERNAL_DNS_DOMAIN_FILTER": "example.org\ncompany.com", "EXTERNAL_DNS_EXCLUDE_DOMAINS": "xapi.example.org\nxapi.company.com", + "EXTERNAL_DNS_REGEX_DOMAIN_FILTER": "(example\\.org|company\\.com)$", + "EXTERNAL_DNS_REGEX_DOMAIN_EXCLUSION": "xapi\\.(example\\.org|company\\.com)$", "EXTERNAL_DNS_PDNS_SERVER": "http://ns.example.com:8081", "EXTERNAL_DNS_PDNS_API_KEY": "some-secret-key", "EXTERNAL_DNS_PDNS_TLS_ENABLED": "1", From 26274bd685d6892ad8e9bc8ed43073b9e0870139 Mon Sep 17 00:00:00 2001 From: "dan.simone@oracle.com" Date: Wed, 29 Jul 2020 11:42:45 -0700 Subject: [PATCH 002/175] First pass - based on global flag --- main.go | 43 ++++---- pkg/apis/externaldns/types.go | 193 +++++++++++++++++----------------- source/ingress.go | 20 +++- source/ingress_test.go | 93 +++++++++++++++- source/store.go | 45 ++++---- 5 files changed, 250 insertions(+), 144 deletions(-) diff --git a/main.go b/main.go index 50f4e0451..fc7b91b98 100644 --- a/main.go +++ b/main.go @@ -97,27 +97,28 @@ func main() { // Create a source.Config from the flags passed by the user. sourceCfg := &source.Config{ - Namespace: cfg.Namespace, - AnnotationFilter: cfg.AnnotationFilter, - FQDNTemplate: cfg.FQDNTemplate, - CombineFQDNAndAnnotation: cfg.CombineFQDNAndAnnotation, - IgnoreHostnameAnnotation: cfg.IgnoreHostnameAnnotation, - Compatibility: cfg.Compatibility, - PublishInternal: cfg.PublishInternal, - PublishHostIP: cfg.PublishHostIP, - AlwaysPublishNotReadyAddresses: cfg.AlwaysPublishNotReadyAddresses, - ConnectorServer: cfg.ConnectorSourceServer, - CRDSourceAPIVersion: cfg.CRDSourceAPIVersion, - CRDSourceKind: cfg.CRDSourceKind, - KubeConfig: cfg.KubeConfig, - APIServerURL: cfg.APIServerURL, - ServiceTypeFilter: cfg.ServiceTypeFilter, - CFAPIEndpoint: cfg.CFAPIEndpoint, - CFUsername: cfg.CFUsername, - CFPassword: cfg.CFPassword, - ContourLoadBalancerService: cfg.ContourLoadBalancerService, - SkipperRouteGroupVersion: cfg.SkipperRouteGroupVersion, - RequestTimeout: cfg.RequestTimeout, + Namespace: cfg.Namespace, + AnnotationFilter: cfg.AnnotationFilter, + FQDNTemplate: cfg.FQDNTemplate, + CombineFQDNAndAnnotation: cfg.CombineFQDNAndAnnotation, + IgnoreHostnameAnnotation: cfg.IgnoreHostnameAnnotation, + PreferIngressHostnameAnnotation: cfg.PreferIngressHostnameAnnotation, + Compatibility: cfg.Compatibility, + PublishInternal: cfg.PublishInternal, + PublishHostIP: cfg.PublishHostIP, + AlwaysPublishNotReadyAddresses: cfg.AlwaysPublishNotReadyAddresses, + ConnectorServer: cfg.ConnectorSourceServer, + CRDSourceAPIVersion: cfg.CRDSourceAPIVersion, + CRDSourceKind: cfg.CRDSourceKind, + KubeConfig: cfg.KubeConfig, + APIServerURL: cfg.APIServerURL, + ServiceTypeFilter: cfg.ServiceTypeFilter, + CFAPIEndpoint: cfg.CFAPIEndpoint, + CFUsername: cfg.CFUsername, + CFPassword: cfg.CFPassword, + ContourLoadBalancerService: cfg.ContourLoadBalancerService, + SkipperRouteGroupVersion: cfg.SkipperRouteGroupVersion, + RequestTimeout: cfg.RequestTimeout, } // Lookup all the selected sources by names and pass them the desired configuration. diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 7d718d670..675de13b9 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -50,6 +50,7 @@ type Config struct { FQDNTemplate string CombineFQDNAndAnnotation bool IgnoreHostnameAnnotation bool + PreferIngressHostnameAnnotation bool Compatibility string PublishInternal bool PublishHostIP bool @@ -145,101 +146,102 @@ type Config struct { } var defaultConfig = &Config{ - APIServerURL: "", - KubeConfig: "", - RequestTimeout: time.Second * 30, - ContourLoadBalancerService: "heptio-contour/contour", - SkipperRouteGroupVersion: "zalando.org/v1", - Sources: nil, - Namespace: "", - AnnotationFilter: "", - FQDNTemplate: "", - CombineFQDNAndAnnotation: false, - IgnoreHostnameAnnotation: false, - Compatibility: "", - PublishInternal: false, - PublishHostIP: false, - ConnectorSourceServer: "localhost:8080", - Provider: "", - GoogleProject: "", - GoogleBatchChangeSize: 1000, - GoogleBatchChangeInterval: time.Second, - DomainFilter: []string{}, - ExcludeDomains: []string{}, - AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json", - AWSZoneType: "", - AWSZoneTagFilter: []string{}, - AWSAssumeRole: "", - AWSBatchChangeSize: 1000, - AWSBatchChangeInterval: time.Second, - AWSEvaluateTargetHealth: true, - AWSAPIRetries: 3, - AWSPreferCNAME: false, - AzureConfigFile: "/etc/kubernetes/azure.json", - AzureResourceGroup: "", - AzureSubscriptionID: "", - CloudflareProxied: false, - CloudflareZonesPerPage: 50, - CoreDNSPrefix: "/skydns/", - RcodezeroTXTEncrypt: false, - AkamaiServiceConsumerDomain: "", - AkamaiClientToken: "", - AkamaiClientSecret: "", - AkamaiAccessToken: "", - InfobloxGridHost: "", - InfobloxWapiPort: 443, - InfobloxWapiUsername: "admin", - InfobloxWapiPassword: "", - InfobloxWapiVersion: "2.3.1", - InfobloxSSLVerify: true, - InfobloxView: "", - InfobloxMaxResults: 0, - OCIConfigFile: "/etc/kubernetes/oci.yaml", - InMemoryZones: []string{}, - OVHEndpoint: "ovh-eu", - OVHApiRateLimit: 20, - PDNSServer: "http://localhost:8081", - PDNSAPIKey: "", - PDNSTLSEnabled: false, - TLSCA: "", - TLSClientCert: "", - TLSClientCertKey: "", - Policy: "sync", - Registry: "txt", - TXTOwnerID: "default", - TXTPrefix: "", - TXTSuffix: "", - TXTCacheInterval: 0, - Interval: time.Minute, - Once: false, - DryRun: false, - UpdateEvents: false, - LogFormat: "text", - MetricsAddress: ":7979", - LogLevel: logrus.InfoLevel.String(), - ExoscaleEndpoint: "https://api.exoscale.ch/dns", - ExoscaleAPIKey: "", - ExoscaleAPISecret: "", - CRDSourceAPIVersion: "externaldns.k8s.io/v1alpha1", - CRDSourceKind: "DNSEndpoint", - ServiceTypeFilter: []string{}, - CFAPIEndpoint: "", - CFUsername: "", - CFPassword: "", - RFC2136Host: "", - RFC2136Port: 0, - RFC2136Zone: "", - RFC2136Insecure: false, - RFC2136TSIGKeyName: "", - RFC2136TSIGSecret: "", - RFC2136TSIGSecretAlg: "", - RFC2136TAXFR: true, - RFC2136MinTTL: 0, - NS1Endpoint: "", - NS1IgnoreSSL: false, - TransIPAccountName: "", - TransIPPrivateKeyFile: "", - DigitalOceanAPIPageSize: 50, + APIServerURL: "", + KubeConfig: "", + RequestTimeout: time.Second * 30, + ContourLoadBalancerService: "heptio-contour/contour", + SkipperRouteGroupVersion: "zalando.org/v1", + Sources: nil, + Namespace: "", + AnnotationFilter: "", + FQDNTemplate: "", + CombineFQDNAndAnnotation: false, + IgnoreHostnameAnnotation: false, + PreferIngressHostnameAnnotation: false, + Compatibility: "", + PublishInternal: false, + PublishHostIP: false, + ConnectorSourceServer: "localhost:8080", + Provider: "", + GoogleProject: "", + GoogleBatchChangeSize: 1000, + GoogleBatchChangeInterval: time.Second, + DomainFilter: []string{}, + ExcludeDomains: []string{}, + AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json", + AWSZoneType: "", + AWSZoneTagFilter: []string{}, + AWSAssumeRole: "", + AWSBatchChangeSize: 1000, + AWSBatchChangeInterval: time.Second, + AWSEvaluateTargetHealth: true, + AWSAPIRetries: 3, + AWSPreferCNAME: false, + AzureConfigFile: "/etc/kubernetes/azure.json", + AzureResourceGroup: "", + AzureSubscriptionID: "", + CloudflareProxied: false, + CloudflareZonesPerPage: 50, + CoreDNSPrefix: "/skydns/", + RcodezeroTXTEncrypt: false, + AkamaiServiceConsumerDomain: "", + AkamaiClientToken: "", + AkamaiClientSecret: "", + AkamaiAccessToken: "", + InfobloxGridHost: "", + InfobloxWapiPort: 443, + InfobloxWapiUsername: "admin", + InfobloxWapiPassword: "", + InfobloxWapiVersion: "2.3.1", + InfobloxSSLVerify: true, + InfobloxView: "", + InfobloxMaxResults: 0, + OCIConfigFile: "/etc/kubernetes/oci.yaml", + InMemoryZones: []string{}, + OVHEndpoint: "ovh-eu", + OVHApiRateLimit: 20, + PDNSServer: "http://localhost:8081", + PDNSAPIKey: "", + PDNSTLSEnabled: false, + TLSCA: "", + TLSClientCert: "", + TLSClientCertKey: "", + Policy: "sync", + Registry: "txt", + TXTOwnerID: "default", + TXTPrefix: "", + TXTSuffix: "", + TXTCacheInterval: 0, + Interval: time.Minute, + Once: false, + DryRun: false, + UpdateEvents: false, + LogFormat: "text", + MetricsAddress: ":7979", + LogLevel: logrus.InfoLevel.String(), + ExoscaleEndpoint: "https://api.exoscale.ch/dns", + ExoscaleAPIKey: "", + ExoscaleAPISecret: "", + CRDSourceAPIVersion: "externaldns.k8s.io/v1alpha1", + CRDSourceKind: "DNSEndpoint", + ServiceTypeFilter: []string{}, + CFAPIEndpoint: "", + CFUsername: "", + CFPassword: "", + RFC2136Host: "", + RFC2136Port: 0, + RFC2136Zone: "", + RFC2136Insecure: false, + RFC2136TSIGKeyName: "", + RFC2136TSIGSecret: "", + RFC2136TSIGSecretAlg: "", + RFC2136TAXFR: true, + RFC2136MinTTL: 0, + NS1Endpoint: "", + NS1IgnoreSSL: false, + TransIPAccountName: "", + TransIPPrivateKeyFile: "", + DigitalOceanAPIPageSize: 50, } // NewConfig returns new Config object @@ -307,6 +309,7 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("fqdn-template", "A templated string that's used to generate DNS names from sources that don't define a hostname themselves, or to add a hostname suffix when paired with the fake source (optional). Accepts comma separated list for multiple global FQDN.").Default(defaultConfig.FQDNTemplate).StringVar(&cfg.FQDNTemplate) app.Flag("combine-fqdn-annotation", "Combine FQDN template and Annotations instead of overwriting").BoolVar(&cfg.CombineFQDNAndAnnotation) app.Flag("ignore-hostname-annotation", "Ignore hostname annotation when generating DNS names, valid only when using fqdn-template is set (optional, default: false)").BoolVar(&cfg.IgnoreHostnameAnnotation) + app.Flag("prefer-ingress-hostname-annotation", "Whether to use host names set on ingress annotations *instead* of those defined in the hosts section (optional, default: false)").BoolVar(&cfg.PreferIngressHostnameAnnotation) app.Flag("compatibility", "Process annotation semantics from legacy implementations (optional, options: mate, molecule)").Default(defaultConfig.Compatibility).EnumVar(&cfg.Compatibility, "", "mate", "molecule") app.Flag("publish-internal-services", "Allow external-dns to publish DNS records for ClusterIP services (optional)").BoolVar(&cfg.PublishInternal) app.Flag("publish-host-ip", "Allow external-dns to publish host-ip for headless services (optional)").BoolVar(&cfg.PublishHostIP) diff --git a/source/ingress.go b/source/ingress.go index 89775f90a..be5646a29 100644 --- a/source/ingress.go +++ b/source/ingress.go @@ -55,11 +55,12 @@ type ingressSource struct { fqdnTemplate *template.Template combineFQDNAnnotation bool ignoreHostnameAnnotation bool + preferHostnameAnnotation bool ingressInformer extinformers.IngressInformer } // NewIngressSource creates a new ingressSource with the given config. -func NewIngressSource(kubeClient kubernetes.Interface, namespace, annotationFilter string, fqdnTemplate string, combineFqdnAnnotation bool, ignoreHostnameAnnotation bool) (Source, error) { +func NewIngressSource(kubeClient kubernetes.Interface, namespace, annotationFilter string, fqdnTemplate string, combineFqdnAnnotation bool, ignoreHostnameAnnotation bool, preferHostnameAnnotation bool) (Source, error) { var ( tmpl *template.Template err error @@ -104,6 +105,7 @@ func NewIngressSource(kubeClient kubernetes.Interface, namespace, annotationFilt fqdnTemplate: tmpl, combineFQDNAnnotation: combineFqdnAnnotation, ignoreHostnameAnnotation: ignoreHostnameAnnotation, + preferHostnameAnnotation: preferHostnameAnnotation, ingressInformer: ingressInformer, } return sc, nil @@ -132,7 +134,7 @@ func (sc *ingressSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, e continue } - ingEndpoints := endpointsFromIngress(ing, sc.ignoreHostnameAnnotation) + ingEndpoints := endpointsFromIngress(ing, sc.ignoreHostnameAnnotation, sc.preferHostnameAnnotation) // apply template if host is missing on ingress if (sc.combineFQDNAnnotation || len(ingEndpoints) == 0) && sc.fqdnTemplate != nil { @@ -240,7 +242,7 @@ func (sc *ingressSource) setDualstackLabel(ingress *v1beta1.Ingress, endpoints [ } // endpointsFromIngress extracts the endpoints from ingress object -func endpointsFromIngress(ing *v1beta1.Ingress, ignoreHostnameAnnotation bool) []*endpoint.Endpoint { +func endpointsFromIngress(ing *v1beta1.Ingress, ignoreHostnameAnnotation bool, preferHostnameAnnotation bool) []*endpoint.Endpoint { var endpoints []*endpoint.Endpoint ttl, err := getTTLFromAnnotations(ing.Annotations) @@ -272,10 +274,18 @@ func endpointsFromIngress(ing *v1beta1.Ingress, ignoreHostnameAnnotation bool) [ } } + annotationHostnameList := getHostnamesFromAnnotations(ing.Annotations) + // Skip endpoints if we do not want entries from annotations if !ignoreHostnameAnnotation { - hostnameList := getHostnamesFromAnnotations(ing.Annotations) - for _, hostname := range hostnameList { + for _, hostname := range annotationHostnameList { + endpoints = append(endpoints, endpointsForHostname(hostname, targets, ttl, providerSpecific, setIdentifier)...) + } + } + // If specified, only take annotation hostnames + if preferHostnameAnnotation && len(annotationHostnameList) > 0 { + endpoints = []*endpoint.Endpoint{} + for _, hostname := range annotationHostnameList { endpoints = append(endpoints, endpointsForHostname(hostname, targets, ttl, providerSpecific, setIdentifier)...) } } diff --git a/source/ingress_test.go b/source/ingress_test.go index f30060250..bd236a52f 100644 --- a/source/ingress_test.go +++ b/source/ingress_test.go @@ -52,6 +52,7 @@ func (suite *IngressSuite) SetupTest() { "{{.Name}}", false, false, + false, ) suite.NoError(err, "should initialize ingress source") @@ -84,6 +85,7 @@ func (suite *IngressSuite) TestDualstackLabelIsSet() { func TestIngress(t *testing.T) { suite.Run(t, new(IngressSuite)) t.Run("endpointsFromIngress", testEndpointsFromIngress) + t.Run("endpointsFromIngressPreferHostnameAnnotations", testEndpointsFromIngressPreferHostnameAnnotations) t.Run("Endpoints", testIngressEndpoints) } @@ -134,6 +136,7 @@ func TestNewIngressSource(t *testing.T) { ti.fqdnTemplate, ti.combineFQDNAndAnnotation, false, + false, ) if ti.expectError { assert.Error(t, err) @@ -221,7 +224,94 @@ func testEndpointsFromIngress(t *testing.T) { } { t.Run(ti.title, func(t *testing.T) { realIngress := ti.ingress.Ingress() - validateEndpoints(t, endpointsFromIngress(realIngress, false), ti.expected) + validateEndpoints(t, endpointsFromIngress(realIngress, false, false), ti.expected) + }) + } +} + +func testEndpointsFromIngressPreferHostnameAnnotations(t *testing.T) { + // Host names and host name annotation provided, without preferHostnameAnnotation specified + for _, ti := range []struct { + title string + ingress fakeIngress + expected []*endpoint.Endpoint + }{ + { + title: "one rule.host, one annotation host", + ingress: fakeIngress{ + dnsnames: []string{"foo.bar"}, + annotations: map[string]string{hostnameAnnotationKey: "foo.baz"}, + hostnames: []string{"lb.com"}, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "foo.bar", + Targets: endpoint.Targets{"lb.com"}, + }, + { + DNSName: "foo.baz", + Targets: endpoint.Targets{"lb.com"}, + }, + }, + }, + { + title: "one rule.host no annotation host", + ingress: fakeIngress{ + dnsnames: []string{"foo.bar"}, + annotations: map[string]string{}, + hostnames: []string{"lb.com"}, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "foo.bar", + Targets: endpoint.Targets{"lb.com"}, + }, + }, + }, + } { + t.Run(ti.title, func(t *testing.T) { + realIngress := ti.ingress.Ingress() + validateEndpoints(t, endpointsFromIngress(realIngress, false, false), ti.expected) + }) + } + // Host names and host name annotation provided, with preferHostnameAnnotation specified + for _, ti := range []struct { + title string + ingress fakeIngress + expected []*endpoint.Endpoint + }{ + { + title: "one rule.host, one annotation host", + ingress: fakeIngress{ + dnsnames: []string{"foo.bar"}, + annotations: map[string]string{hostnameAnnotationKey: "foo.baz"}, + hostnames: []string{"lb.com"}, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "foo.baz", + Targets: endpoint.Targets{"lb.com"}, + }, + }, + }, + { + title: "one rule.host no annotation host", + ingress: fakeIngress{ + dnsnames: []string{"foo.bar"}, + annotations: map[string]string{}, + hostnames: []string{"lb.com"}, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "foo.bar", + Targets: endpoint.Targets{"lb.com"}, + }, + }, + }, + } { + t.Run(ti.title, func(t *testing.T) { + realIngress := ti.ingress.Ingress() + validateEndpoints(t, endpointsFromIngress(realIngress, false, true), ti.expected) }) } } @@ -1008,6 +1098,7 @@ func testIngressEndpoints(t *testing.T) { ti.fqdnTemplate, ti.combineFQDNAndAnnotation, ti.ignoreHostnameAnnotation, + false, ) for _, ingress := range ingresses { _, err := fakeClient.ExtensionsV1beta1().Ingresses(ingress.Namespace).Create(context.Background(), ingress, metav1.CreateOptions{}) diff --git a/source/store.go b/source/store.go index 3b7ba9742..27972bea7 100644 --- a/source/store.go +++ b/source/store.go @@ -40,27 +40,28 @@ var ErrSourceNotFound = errors.New("source not found") // Config holds shared configuration options for all Sources. type Config struct { - Namespace string - AnnotationFilter string - FQDNTemplate string - CombineFQDNAndAnnotation bool - IgnoreHostnameAnnotation bool - Compatibility string - PublishInternal bool - PublishHostIP bool - AlwaysPublishNotReadyAddresses bool - ConnectorServer string - CRDSourceAPIVersion string - CRDSourceKind string - KubeConfig string - APIServerURL string - ServiceTypeFilter []string - CFAPIEndpoint string - CFUsername string - CFPassword string - ContourLoadBalancerService string - SkipperRouteGroupVersion string - RequestTimeout time.Duration + Namespace string + AnnotationFilter string + FQDNTemplate string + CombineFQDNAndAnnotation bool + IgnoreHostnameAnnotation bool + PreferIngressHostnameAnnotation bool + Compatibility string + PublishInternal bool + PublishHostIP bool + AlwaysPublishNotReadyAddresses bool + ConnectorServer string + CRDSourceAPIVersion string + CRDSourceKind string + KubeConfig string + APIServerURL string + ServiceTypeFilter []string + CFAPIEndpoint string + CFUsername string + CFPassword string + ContourLoadBalancerService string + SkipperRouteGroupVersion string + RequestTimeout time.Duration } // ClientGenerator provides clients @@ -184,7 +185,7 @@ func BuildWithConfig(source string, p ClientGenerator, cfg *Config) (Source, err if err != nil { return nil, err } - return NewIngressSource(client, cfg.Namespace, cfg.AnnotationFilter, cfg.FQDNTemplate, cfg.CombineFQDNAndAnnotation, cfg.IgnoreHostnameAnnotation) + return NewIngressSource(client, cfg.Namespace, cfg.AnnotationFilter, cfg.FQDNTemplate, cfg.CombineFQDNAndAnnotation, cfg.IgnoreHostnameAnnotation, cfg.PreferIngressHostnameAnnotation) case "istio-gateway": kubernetesClient, err := p.KubeClient() if err != nil { From f85cddab58826da45c7f17a5c9fff0e5d9bb3a76 Mon Sep 17 00:00:00 2001 From: "dan.simone@oracle.com" Date: Wed, 29 Jul 2020 11:51:27 -0700 Subject: [PATCH 003/175] Change to an annotation-based approach, based on feedback --- docs/faq.md | 6 +- main.go | 43 ++++---- pkg/apis/externaldns/types.go | 193 +++++++++++++++++----------------- source/ingress.go | 48 +++++---- source/ingress_test.go | 80 +++++++------- source/source.go | 3 + source/store.go | 45 ++++---- 7 files changed, 212 insertions(+), 206 deletions(-) diff --git a/docs/faq.md b/docs/faq.md index 32eee328c..5a6bef2f2 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -57,8 +57,10 @@ Services exposed via `type=LoadBalancer`, `type=ExternalName` and for the hostna There are three sources of information for ExternalDNS to decide on DNS name. ExternalDNS will pick one in order as listed below: -1. For ingress objects ExternalDNS will create a DNS record based on the host specified for the ingress object. For services ExternalDNS will look for the annotation `external-dns.alpha.kubernetes.io/hostname` on the service and use the corresponding value. - +1. For ingress objects ExternalDNS will create a DNS record based on the hosts specified for the ingress object, as well as the `external-dns.alpha.kubernetes.io/hostname` annotation. For services ExternalDNS will look for the annotation `external-dns.alpha.kubernetes.io/hostname` on the service and use the corresponding value. + - For ingresses, you can optionally force ExternalDNS to create records based on _either_ the hosts specified or the `external-dns.alpha.kubernetes.io/hostname` annotation. This behavior is controlled by + setting the `external-dns.alpha.kubernetes.io/ingress-hostname-source` annotation on that ingress to either `defined-hosts-only` or `annotation-only`. + 2. If compatibility mode is enabled (e.g. `--compatibility={mate,molecule}` flag), External DNS will parse annotations used by Zalando/Mate, wearemolecule/route53-kubernetes. Compatibility mode with Kops DNS Controller is planned to be added in the future. 3. If `--fqdn-template` flag is specified, e.g. `--fqdn-template={{.Name}}.my-org.com`, ExternalDNS will use service/ingress specifications for the provided template to generate DNS name. diff --git a/main.go b/main.go index fc7b91b98..50f4e0451 100644 --- a/main.go +++ b/main.go @@ -97,28 +97,27 @@ func main() { // Create a source.Config from the flags passed by the user. sourceCfg := &source.Config{ - Namespace: cfg.Namespace, - AnnotationFilter: cfg.AnnotationFilter, - FQDNTemplate: cfg.FQDNTemplate, - CombineFQDNAndAnnotation: cfg.CombineFQDNAndAnnotation, - IgnoreHostnameAnnotation: cfg.IgnoreHostnameAnnotation, - PreferIngressHostnameAnnotation: cfg.PreferIngressHostnameAnnotation, - Compatibility: cfg.Compatibility, - PublishInternal: cfg.PublishInternal, - PublishHostIP: cfg.PublishHostIP, - AlwaysPublishNotReadyAddresses: cfg.AlwaysPublishNotReadyAddresses, - ConnectorServer: cfg.ConnectorSourceServer, - CRDSourceAPIVersion: cfg.CRDSourceAPIVersion, - CRDSourceKind: cfg.CRDSourceKind, - KubeConfig: cfg.KubeConfig, - APIServerURL: cfg.APIServerURL, - ServiceTypeFilter: cfg.ServiceTypeFilter, - CFAPIEndpoint: cfg.CFAPIEndpoint, - CFUsername: cfg.CFUsername, - CFPassword: cfg.CFPassword, - ContourLoadBalancerService: cfg.ContourLoadBalancerService, - SkipperRouteGroupVersion: cfg.SkipperRouteGroupVersion, - RequestTimeout: cfg.RequestTimeout, + Namespace: cfg.Namespace, + AnnotationFilter: cfg.AnnotationFilter, + FQDNTemplate: cfg.FQDNTemplate, + CombineFQDNAndAnnotation: cfg.CombineFQDNAndAnnotation, + IgnoreHostnameAnnotation: cfg.IgnoreHostnameAnnotation, + Compatibility: cfg.Compatibility, + PublishInternal: cfg.PublishInternal, + PublishHostIP: cfg.PublishHostIP, + AlwaysPublishNotReadyAddresses: cfg.AlwaysPublishNotReadyAddresses, + ConnectorServer: cfg.ConnectorSourceServer, + CRDSourceAPIVersion: cfg.CRDSourceAPIVersion, + CRDSourceKind: cfg.CRDSourceKind, + KubeConfig: cfg.KubeConfig, + APIServerURL: cfg.APIServerURL, + ServiceTypeFilter: cfg.ServiceTypeFilter, + CFAPIEndpoint: cfg.CFAPIEndpoint, + CFUsername: cfg.CFUsername, + CFPassword: cfg.CFPassword, + ContourLoadBalancerService: cfg.ContourLoadBalancerService, + SkipperRouteGroupVersion: cfg.SkipperRouteGroupVersion, + RequestTimeout: cfg.RequestTimeout, } // Lookup all the selected sources by names and pass them the desired configuration. diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 675de13b9..7d718d670 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -50,7 +50,6 @@ type Config struct { FQDNTemplate string CombineFQDNAndAnnotation bool IgnoreHostnameAnnotation bool - PreferIngressHostnameAnnotation bool Compatibility string PublishInternal bool PublishHostIP bool @@ -146,102 +145,101 @@ type Config struct { } var defaultConfig = &Config{ - APIServerURL: "", - KubeConfig: "", - RequestTimeout: time.Second * 30, - ContourLoadBalancerService: "heptio-contour/contour", - SkipperRouteGroupVersion: "zalando.org/v1", - Sources: nil, - Namespace: "", - AnnotationFilter: "", - FQDNTemplate: "", - CombineFQDNAndAnnotation: false, - IgnoreHostnameAnnotation: false, - PreferIngressHostnameAnnotation: false, - Compatibility: "", - PublishInternal: false, - PublishHostIP: false, - ConnectorSourceServer: "localhost:8080", - Provider: "", - GoogleProject: "", - GoogleBatchChangeSize: 1000, - GoogleBatchChangeInterval: time.Second, - DomainFilter: []string{}, - ExcludeDomains: []string{}, - AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json", - AWSZoneType: "", - AWSZoneTagFilter: []string{}, - AWSAssumeRole: "", - AWSBatchChangeSize: 1000, - AWSBatchChangeInterval: time.Second, - AWSEvaluateTargetHealth: true, - AWSAPIRetries: 3, - AWSPreferCNAME: false, - AzureConfigFile: "/etc/kubernetes/azure.json", - AzureResourceGroup: "", - AzureSubscriptionID: "", - CloudflareProxied: false, - CloudflareZonesPerPage: 50, - CoreDNSPrefix: "/skydns/", - RcodezeroTXTEncrypt: false, - AkamaiServiceConsumerDomain: "", - AkamaiClientToken: "", - AkamaiClientSecret: "", - AkamaiAccessToken: "", - InfobloxGridHost: "", - InfobloxWapiPort: 443, - InfobloxWapiUsername: "admin", - InfobloxWapiPassword: "", - InfobloxWapiVersion: "2.3.1", - InfobloxSSLVerify: true, - InfobloxView: "", - InfobloxMaxResults: 0, - OCIConfigFile: "/etc/kubernetes/oci.yaml", - InMemoryZones: []string{}, - OVHEndpoint: "ovh-eu", - OVHApiRateLimit: 20, - PDNSServer: "http://localhost:8081", - PDNSAPIKey: "", - PDNSTLSEnabled: false, - TLSCA: "", - TLSClientCert: "", - TLSClientCertKey: "", - Policy: "sync", - Registry: "txt", - TXTOwnerID: "default", - TXTPrefix: "", - TXTSuffix: "", - TXTCacheInterval: 0, - Interval: time.Minute, - Once: false, - DryRun: false, - UpdateEvents: false, - LogFormat: "text", - MetricsAddress: ":7979", - LogLevel: logrus.InfoLevel.String(), - ExoscaleEndpoint: "https://api.exoscale.ch/dns", - ExoscaleAPIKey: "", - ExoscaleAPISecret: "", - CRDSourceAPIVersion: "externaldns.k8s.io/v1alpha1", - CRDSourceKind: "DNSEndpoint", - ServiceTypeFilter: []string{}, - CFAPIEndpoint: "", - CFUsername: "", - CFPassword: "", - RFC2136Host: "", - RFC2136Port: 0, - RFC2136Zone: "", - RFC2136Insecure: false, - RFC2136TSIGKeyName: "", - RFC2136TSIGSecret: "", - RFC2136TSIGSecretAlg: "", - RFC2136TAXFR: true, - RFC2136MinTTL: 0, - NS1Endpoint: "", - NS1IgnoreSSL: false, - TransIPAccountName: "", - TransIPPrivateKeyFile: "", - DigitalOceanAPIPageSize: 50, + APIServerURL: "", + KubeConfig: "", + RequestTimeout: time.Second * 30, + ContourLoadBalancerService: "heptio-contour/contour", + SkipperRouteGroupVersion: "zalando.org/v1", + Sources: nil, + Namespace: "", + AnnotationFilter: "", + FQDNTemplate: "", + CombineFQDNAndAnnotation: false, + IgnoreHostnameAnnotation: false, + Compatibility: "", + PublishInternal: false, + PublishHostIP: false, + ConnectorSourceServer: "localhost:8080", + Provider: "", + GoogleProject: "", + GoogleBatchChangeSize: 1000, + GoogleBatchChangeInterval: time.Second, + DomainFilter: []string{}, + ExcludeDomains: []string{}, + AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json", + AWSZoneType: "", + AWSZoneTagFilter: []string{}, + AWSAssumeRole: "", + AWSBatchChangeSize: 1000, + AWSBatchChangeInterval: time.Second, + AWSEvaluateTargetHealth: true, + AWSAPIRetries: 3, + AWSPreferCNAME: false, + AzureConfigFile: "/etc/kubernetes/azure.json", + AzureResourceGroup: "", + AzureSubscriptionID: "", + CloudflareProxied: false, + CloudflareZonesPerPage: 50, + CoreDNSPrefix: "/skydns/", + RcodezeroTXTEncrypt: false, + AkamaiServiceConsumerDomain: "", + AkamaiClientToken: "", + AkamaiClientSecret: "", + AkamaiAccessToken: "", + InfobloxGridHost: "", + InfobloxWapiPort: 443, + InfobloxWapiUsername: "admin", + InfobloxWapiPassword: "", + InfobloxWapiVersion: "2.3.1", + InfobloxSSLVerify: true, + InfobloxView: "", + InfobloxMaxResults: 0, + OCIConfigFile: "/etc/kubernetes/oci.yaml", + InMemoryZones: []string{}, + OVHEndpoint: "ovh-eu", + OVHApiRateLimit: 20, + PDNSServer: "http://localhost:8081", + PDNSAPIKey: "", + PDNSTLSEnabled: false, + TLSCA: "", + TLSClientCert: "", + TLSClientCertKey: "", + Policy: "sync", + Registry: "txt", + TXTOwnerID: "default", + TXTPrefix: "", + TXTSuffix: "", + TXTCacheInterval: 0, + Interval: time.Minute, + Once: false, + DryRun: false, + UpdateEvents: false, + LogFormat: "text", + MetricsAddress: ":7979", + LogLevel: logrus.InfoLevel.String(), + ExoscaleEndpoint: "https://api.exoscale.ch/dns", + ExoscaleAPIKey: "", + ExoscaleAPISecret: "", + CRDSourceAPIVersion: "externaldns.k8s.io/v1alpha1", + CRDSourceKind: "DNSEndpoint", + ServiceTypeFilter: []string{}, + CFAPIEndpoint: "", + CFUsername: "", + CFPassword: "", + RFC2136Host: "", + RFC2136Port: 0, + RFC2136Zone: "", + RFC2136Insecure: false, + RFC2136TSIGKeyName: "", + RFC2136TSIGSecret: "", + RFC2136TSIGSecretAlg: "", + RFC2136TAXFR: true, + RFC2136MinTTL: 0, + NS1Endpoint: "", + NS1IgnoreSSL: false, + TransIPAccountName: "", + TransIPPrivateKeyFile: "", + DigitalOceanAPIPageSize: 50, } // NewConfig returns new Config object @@ -309,7 +307,6 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("fqdn-template", "A templated string that's used to generate DNS names from sources that don't define a hostname themselves, or to add a hostname suffix when paired with the fake source (optional). Accepts comma separated list for multiple global FQDN.").Default(defaultConfig.FQDNTemplate).StringVar(&cfg.FQDNTemplate) app.Flag("combine-fqdn-annotation", "Combine FQDN template and Annotations instead of overwriting").BoolVar(&cfg.CombineFQDNAndAnnotation) app.Flag("ignore-hostname-annotation", "Ignore hostname annotation when generating DNS names, valid only when using fqdn-template is set (optional, default: false)").BoolVar(&cfg.IgnoreHostnameAnnotation) - app.Flag("prefer-ingress-hostname-annotation", "Whether to use host names set on ingress annotations *instead* of those defined in the hosts section (optional, default: false)").BoolVar(&cfg.PreferIngressHostnameAnnotation) app.Flag("compatibility", "Process annotation semantics from legacy implementations (optional, options: mate, molecule)").Default(defaultConfig.Compatibility).EnumVar(&cfg.Compatibility, "", "mate", "molecule") app.Flag("publish-internal-services", "Allow external-dns to publish DNS records for ClusterIP services (optional)").BoolVar(&cfg.PublishInternal) app.Flag("publish-host-ip", "Allow external-dns to publish host-ip for headless services (optional)").BoolVar(&cfg.PublishHostIP) diff --git a/source/ingress.go b/source/ingress.go index be5646a29..7325e1db2 100644 --- a/source/ingress.go +++ b/source/ingress.go @@ -42,6 +42,10 @@ const ( ALBDualstackAnnotationKey = "alb.ingress.kubernetes.io/ip-address-type" // ALBDualstackAnnotationValue is the value of the ALB dualstack annotation that indicates it is dualstack ALBDualstackAnnotationValue = "dualstack" + + // Possible values for the ingress-hostname-source annotation + IngressHostnameSourceAnnotationOnlyValue = "annotation-only" + IngressHostnameSourceDefinedHostsOnlyValue = "defined-hosts-only" ) // ingressSource is an implementation of Source for Kubernetes ingress objects. @@ -55,12 +59,11 @@ type ingressSource struct { fqdnTemplate *template.Template combineFQDNAnnotation bool ignoreHostnameAnnotation bool - preferHostnameAnnotation bool ingressInformer extinformers.IngressInformer } // NewIngressSource creates a new ingressSource with the given config. -func NewIngressSource(kubeClient kubernetes.Interface, namespace, annotationFilter string, fqdnTemplate string, combineFqdnAnnotation bool, ignoreHostnameAnnotation bool, preferHostnameAnnotation bool) (Source, error) { +func NewIngressSource(kubeClient kubernetes.Interface, namespace, annotationFilter string, fqdnTemplate string, combineFqdnAnnotation bool, ignoreHostnameAnnotation bool) (Source, error) { var ( tmpl *template.Template err error @@ -105,7 +108,6 @@ func NewIngressSource(kubeClient kubernetes.Interface, namespace, annotationFilt fqdnTemplate: tmpl, combineFQDNAnnotation: combineFqdnAnnotation, ignoreHostnameAnnotation: ignoreHostnameAnnotation, - preferHostnameAnnotation: preferHostnameAnnotation, ingressInformer: ingressInformer, } return sc, nil @@ -134,7 +136,7 @@ func (sc *ingressSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, e continue } - ingEndpoints := endpointsFromIngress(ing, sc.ignoreHostnameAnnotation, sc.preferHostnameAnnotation) + ingEndpoints := endpointsFromIngress(ing, sc.ignoreHostnameAnnotation) // apply template if host is missing on ingress if (sc.combineFQDNAnnotation || len(ingEndpoints) == 0) && sc.fqdnTemplate != nil { @@ -242,9 +244,7 @@ func (sc *ingressSource) setDualstackLabel(ingress *v1beta1.Ingress, endpoints [ } // endpointsFromIngress extracts the endpoints from ingress object -func endpointsFromIngress(ing *v1beta1.Ingress, ignoreHostnameAnnotation bool, preferHostnameAnnotation bool) []*endpoint.Endpoint { - var endpoints []*endpoint.Endpoint - +func endpointsFromIngress(ing *v1beta1.Ingress, ignoreHostnameAnnotation bool) []*endpoint.Endpoint { ttl, err := getTTLFromAnnotations(ing.Annotations) if err != nil { log.Warn(err) @@ -258,11 +258,13 @@ func endpointsFromIngress(ing *v1beta1.Ingress, ignoreHostnameAnnotation bool, p providerSpecific, setIdentifier := getProviderSpecificAnnotations(ing.Annotations) + // Gather endpoints defined on hosts sections of the ingress + var definedHostsEndpoints []*endpoint.Endpoint for _, rule := range ing.Spec.Rules { if rule.Host == "" { continue } - endpoints = append(endpoints, endpointsForHostname(rule.Host, targets, ttl, providerSpecific, setIdentifier)...) + definedHostsEndpoints = append(definedHostsEndpoints, endpointsForHostname(rule.Host, targets, ttl, providerSpecific, setIdentifier)...) } for _, tls := range ing.Spec.TLS { @@ -270,24 +272,26 @@ func endpointsFromIngress(ing *v1beta1.Ingress, ignoreHostnameAnnotation bool, p if host == "" { continue } - endpoints = append(endpoints, endpointsForHostname(host, targets, ttl, providerSpecific, setIdentifier)...) + definedHostsEndpoints = append(definedHostsEndpoints, endpointsForHostname(host, targets, ttl, providerSpecific, setIdentifier)...) } } - annotationHostnameList := getHostnamesFromAnnotations(ing.Annotations) - - // Skip endpoints if we do not want entries from annotations - if !ignoreHostnameAnnotation { - for _, hostname := range annotationHostnameList { - endpoints = append(endpoints, endpointsForHostname(hostname, targets, ttl, providerSpecific, setIdentifier)...) - } + // Gather endpoints defined on annotations in the ingress + var annotationEndpoints []*endpoint.Endpoint + for _, hostname := range getHostnamesFromAnnotations(ing.Annotations) { + annotationEndpoints = append(annotationEndpoints, endpointsForHostname(hostname, targets, ttl, providerSpecific, setIdentifier)...) } - // If specified, only take annotation hostnames - if preferHostnameAnnotation && len(annotationHostnameList) > 0 { - endpoints = []*endpoint.Endpoint{} - for _, hostname := range annotationHostnameList { - endpoints = append(endpoints, endpointsForHostname(hostname, targets, ttl, providerSpecific, setIdentifier)...) - } + + // Determine which hostnames to consider in our final list + var endpoints []*endpoint.Endpoint + hostnameSourceAnnotation, exists := ing.Annotations[ingressHostnameSourceKey] + useDefinedHosts := !exists || strings.ToLower(hostnameSourceAnnotation) != IngressHostnameSourceAnnotationOnlyValue + useAnnotationHosts := !exists || strings.ToLower(hostnameSourceAnnotation) != IngressHostnameSourceDefinedHostsOnlyValue + if useDefinedHosts { + endpoints = append(endpoints, definedHostsEndpoints...) + } + if !ignoreHostnameAnnotation && useAnnotationHosts { + endpoints = append(endpoints, annotationEndpoints...) } return endpoints } diff --git a/source/ingress_test.go b/source/ingress_test.go index bd236a52f..f4ea03d11 100644 --- a/source/ingress_test.go +++ b/source/ingress_test.go @@ -52,7 +52,6 @@ func (suite *IngressSuite) SetupTest() { "{{.Name}}", false, false, - false, ) suite.NoError(err, "should initialize ingress source") @@ -85,7 +84,7 @@ func (suite *IngressSuite) TestDualstackLabelIsSet() { func TestIngress(t *testing.T) { suite.Run(t, new(IngressSuite)) t.Run("endpointsFromIngress", testEndpointsFromIngress) - t.Run("endpointsFromIngressPreferHostnameAnnotations", testEndpointsFromIngressPreferHostnameAnnotations) + t.Run("endpointsFromIngressHostnameSourceAnnotation", testEndpointsFromIngressHostnameSourceAnnotation) t.Run("Endpoints", testIngressEndpoints) } @@ -136,7 +135,6 @@ func TestNewIngressSource(t *testing.T) { ti.fqdnTemplate, ti.combineFQDNAndAnnotation, false, - false, ) if ti.expectError { assert.Error(t, err) @@ -224,20 +222,20 @@ func testEndpointsFromIngress(t *testing.T) { } { t.Run(ti.title, func(t *testing.T) { realIngress := ti.ingress.Ingress() - validateEndpoints(t, endpointsFromIngress(realIngress, false, false), ti.expected) + validateEndpoints(t, endpointsFromIngress(realIngress, false), ti.expected) }) } } -func testEndpointsFromIngressPreferHostnameAnnotations(t *testing.T) { - // Host names and host name annotation provided, without preferHostnameAnnotation specified +func testEndpointsFromIngressHostnameSourceAnnotation(t *testing.T) { + // Host names and host name annotation provided, with various values of the ingress-hostname-source annotation for _, ti := range []struct { title string ingress fakeIngress expected []*endpoint.Endpoint }{ { - title: "one rule.host, one annotation host", + title: "No ingress-hostname-source annotation, one rule.host, one annotation host", ingress: fakeIngress{ dnsnames: []string{"foo.bar"}, annotations: map[string]string{hostnameAnnotationKey: "foo.baz"}, @@ -255,10 +253,9 @@ func testEndpointsFromIngressPreferHostnameAnnotations(t *testing.T) { }, }, { - title: "one rule.host no annotation host", + title: "No ingress-hostname-source annotation, one rule.host", ingress: fakeIngress{ dnsnames: []string{"foo.bar"}, - annotations: map[string]string{}, hostnames: []string{"lb.com"}, }, expected: []*endpoint.Endpoint{ @@ -268,23 +265,43 @@ func testEndpointsFromIngressPreferHostnameAnnotations(t *testing.T) { }, }, }, - } { - t.Run(ti.title, func(t *testing.T) { - realIngress := ti.ingress.Ingress() - validateEndpoints(t, endpointsFromIngress(realIngress, false, false), ti.expected) - }) - } - // Host names and host name annotation provided, with preferHostnameAnnotation specified - for _, ti := range []struct { - title string - ingress fakeIngress - expected []*endpoint.Endpoint - }{ { - title: "one rule.host, one annotation host", + title: "Ingress-hostname-source=all, one rule.host, one annotation host", ingress: fakeIngress{ dnsnames: []string{"foo.bar"}, - annotations: map[string]string{hostnameAnnotationKey: "foo.baz"}, + annotations: map[string]string{hostnameAnnotationKey: "foo.baz", ingressHostnameSourceKey: "all"}, + hostnames: []string{"lb.com"}, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "foo.bar", + Targets: endpoint.Targets{"lb.com"}, + }, + { + DNSName: "foo.baz", + Targets: endpoint.Targets{"lb.com"}, + }, + }, + }, + { + title: "Ingress-hostname-source=defined-hosts-only, one rule.host, one annotation host", + ingress: fakeIngress{ + dnsnames: []string{"foo.bar"}, + annotations: map[string]string{hostnameAnnotationKey: "foo.baz", ingressHostnameSourceKey: "defined-hosts-only"}, + hostnames: []string{"lb.com"}, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "foo.bar", + Targets: endpoint.Targets{"lb.com"}, + }, + }, + }, + { + title: "Ingress-hostname-source=annotation-only, one rule.host, one annotation host", + ingress: fakeIngress{ + dnsnames: []string{"foo.bar"}, + annotations: map[string]string{hostnameAnnotationKey: "foo.baz", ingressHostnameSourceKey: "annotation-only"}, hostnames: []string{"lb.com"}, }, expected: []*endpoint.Endpoint{ @@ -294,24 +311,10 @@ func testEndpointsFromIngressPreferHostnameAnnotations(t *testing.T) { }, }, }, - { - title: "one rule.host no annotation host", - ingress: fakeIngress{ - dnsnames: []string{"foo.bar"}, - annotations: map[string]string{}, - hostnames: []string{"lb.com"}, - }, - expected: []*endpoint.Endpoint{ - { - DNSName: "foo.bar", - Targets: endpoint.Targets{"lb.com"}, - }, - }, - }, } { t.Run(ti.title, func(t *testing.T) { realIngress := ti.ingress.Ingress() - validateEndpoints(t, endpointsFromIngress(realIngress, false, true), ti.expected) + validateEndpoints(t, endpointsFromIngress(realIngress, false), ti.expected) }) } } @@ -1098,7 +1101,6 @@ func testIngressEndpoints(t *testing.T) { ti.fqdnTemplate, ti.combineFQDNAndAnnotation, ti.ignoreHostnameAnnotation, - false, ) for _, ingress := range ingresses { _, err := fakeClient.ExtensionsV1beta1().Ingresses(ingress.Namespace).Create(context.Background(), ingress, metav1.CreateOptions{}) diff --git a/source/source.go b/source/source.go index a050d3832..4844f312e 100644 --- a/source/source.go +++ b/source/source.go @@ -43,6 +43,9 @@ const ( ttlAnnotationKey = "external-dns.alpha.kubernetes.io/ttl" // The annotation used for switching to the alias record types e. g. AWS Alias records instead of a normal CNAME aliasAnnotationKey = "external-dns.alpha.kubernetes.io/alias" + // The annotation used to determine the source of hostnames for ingresses + ingressHostnameSourceKey = "external-dns.alpha.kubernetes.io/ingress-hostname-source" + // The value of the controller annotation so that we feel responsible // The value of the controller annotation so that we feel responsible controllerAnnotationValue = "dns-controller" ) diff --git a/source/store.go b/source/store.go index 27972bea7..3b7ba9742 100644 --- a/source/store.go +++ b/source/store.go @@ -40,28 +40,27 @@ var ErrSourceNotFound = errors.New("source not found") // Config holds shared configuration options for all Sources. type Config struct { - Namespace string - AnnotationFilter string - FQDNTemplate string - CombineFQDNAndAnnotation bool - IgnoreHostnameAnnotation bool - PreferIngressHostnameAnnotation bool - Compatibility string - PublishInternal bool - PublishHostIP bool - AlwaysPublishNotReadyAddresses bool - ConnectorServer string - CRDSourceAPIVersion string - CRDSourceKind string - KubeConfig string - APIServerURL string - ServiceTypeFilter []string - CFAPIEndpoint string - CFUsername string - CFPassword string - ContourLoadBalancerService string - SkipperRouteGroupVersion string - RequestTimeout time.Duration + Namespace string + AnnotationFilter string + FQDNTemplate string + CombineFQDNAndAnnotation bool + IgnoreHostnameAnnotation bool + Compatibility string + PublishInternal bool + PublishHostIP bool + AlwaysPublishNotReadyAddresses bool + ConnectorServer string + CRDSourceAPIVersion string + CRDSourceKind string + KubeConfig string + APIServerURL string + ServiceTypeFilter []string + CFAPIEndpoint string + CFUsername string + CFPassword string + ContourLoadBalancerService string + SkipperRouteGroupVersion string + RequestTimeout time.Duration } // ClientGenerator provides clients @@ -185,7 +184,7 @@ func BuildWithConfig(source string, p ClientGenerator, cfg *Config) (Source, err if err != nil { return nil, err } - return NewIngressSource(client, cfg.Namespace, cfg.AnnotationFilter, cfg.FQDNTemplate, cfg.CombineFQDNAndAnnotation, cfg.IgnoreHostnameAnnotation, cfg.PreferIngressHostnameAnnotation) + return NewIngressSource(client, cfg.Namespace, cfg.AnnotationFilter, cfg.FQDNTemplate, cfg.CombineFQDNAndAnnotation, cfg.IgnoreHostnameAnnotation) case "istio-gateway": kubernetesClient, err := p.KubeClient() if err != nil { From a2480b348ec2932f87b9cc13cf06397b1b2337c5 Mon Sep 17 00:00:00 2001 From: Enrique Gonzalez Date: Mon, 10 Aug 2020 11:30:37 +0200 Subject: [PATCH 004/175] docs: add feature to Unreleased changes Signed-off-by: Enrique Gonzalez --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index db00e9965..8b03f9b0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ - digitalocean: increase API page size (#1611) @tdyas - improve linter quality for external-dns (#1618) @njuettner - fix convert int to string bug (#1620) @tariq1890 +- Add regex domain filters (#1504) @offzale ## v0.7.2 - 2020-06-03 From 87f291a548d611f0983444d5d4b12fa2a5a81baf Mon Sep 17 00:00:00 2001 From: "dan.simone@oracle.com" Date: Fri, 25 Sep 2020 16:07:05 -0700 Subject: [PATCH 005/175] Fix unit test --- source/ingress_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/ingress_test.go b/source/ingress_test.go index 4130c412d..2d9dcafa0 100644 --- a/source/ingress_test.go +++ b/source/ingress_test.go @@ -316,7 +316,7 @@ func testEndpointsFromIngressHostnameSourceAnnotation(t *testing.T) { } { t.Run(ti.title, func(t *testing.T) { realIngress := ti.ingress.Ingress() - validateEndpoints(t, endpointsFromIngress(realIngress, false), ti.expected) + validateEndpoints(t, endpointsFromIngress(realIngress, false, false), ti.expected) }) } } From 28b61befbf225be7ce046e0b2646ea5d23b46fce Mon Sep 17 00:00:00 2001 From: Enrique Gonzalez Date: Tue, 3 Nov 2020 16:36:17 +0100 Subject: [PATCH 006/175] git: solve merge conflict Signed-off-by: Enrique Gonzalez --- pkg/apis/externaldns/types.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 304026808..109fc36ec 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -334,12 +334,9 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, aws-sd, google, azure, azure-dns, azure-private-dns, cloudflare, rcodezero, digitalocean, hetzner, dnsimple, akamai, infoblox, dyn, designate, coredns, skydns, inmemory, ovh, pdns, oci, exoscale, linode, rfc2136, ns1, transip, vinyldns, rdns, scaleway, vultr, ultradns)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "aws-sd", "google", "azure", "azure-dns", "hetzner", "azure-private-dns", "alibabacloud", "cloudflare", "rcodezero", "digitalocean", "dnsimple", "akamai", "infoblox", "dyn", "designate", "coredns", "skydns", "inmemory", "ovh", "pdns", "oci", "exoscale", "linode", "rfc2136", "ns1", "transip", "vinyldns", "rdns", "scaleway", "vultr", "ultradns") app.Flag("domain-filter", "Limit possible target zones by a domain suffix; specify multiple times for multiple domains (optional)").Default("").StringsVar(&cfg.DomainFilter) app.Flag("exclude-domains", "Exclude subdomains (optional)").Default("").StringsVar(&cfg.ExcludeDomains) -<<<<<<< HEAD app.Flag("regex-domain-filter", "Limit possible domains and target zones by a Regex filter; Overrides domain-filter (optional)").Default("").StringVar(&cfg.RegexDomainFilter) app.Flag("regex-domain-exclusion", "Regex filter that excludes domains and target zones matched by regex-domain-filter (optional)").Default("").StringVar(&cfg.RegexDomainExclusion) -======= app.Flag("zone-name-filter", "Filter target zones by zone domain (For now, only AzureDNS provider is using this flag); specify multiple times for multiple zones (optional)").Default("").StringsVar(&cfg.ZoneNameFilter) ->>>>>>> upstream/master app.Flag("zone-id-filter", "Filter target zones by hosted zone id; specify multiple times for multiple zones (optional)").Default("").StringsVar(&cfg.ZoneIDFilter) app.Flag("google-project", "When using the Google provider, current project is auto-detected, when running on GCP. Specify other project with this. Must be specified when running outside GCP.").Default(defaultConfig.GoogleProject).StringVar(&cfg.GoogleProject) app.Flag("google-batch-change-size", "When using the Google provider, set the maximum number of changes that will be applied in each batch.").Default(strconv.Itoa(defaultConfig.GoogleBatchChangeSize)).IntVar(&cfg.GoogleBatchChangeSize) From 0bcc2ed39e236c2d8e8a720acb58ebf1e6bcffc9 Mon Sep 17 00:00:00 2001 From: "dan.simone@oracle.com" Date: Fri, 4 Dec 2020 10:44:12 -0800 Subject: [PATCH 007/175] FAQ changes based on feedback --- docs/faq.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/faq.md b/docs/faq.md index b6692be3e..b04f82b34 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -57,8 +57,8 @@ Services exposed via `type=LoadBalancer`, `type=ExternalName` and for the hostna There are three sources of information for ExternalDNS to decide on DNS name. ExternalDNS will pick one in order as listed below: -1. For ingress objects ExternalDNS will create a DNS record based on the hosts specified for the ingress object, as well as the `external-dns.alpha.kubernetes.io/hostname` annotation. For services ExternalDNS will look for the annotation `external-dns.alpha.kubernetes.io/hostname` on the service and use the corresponding value. - - For ingresses, you can optionally force ExternalDNS to create records based on _either_ the hosts specified or the `external-dns.alpha.kubernetes.io/hostname` annotation. This behavior is controlled by +1. For ingress objects ExternalDNS will create a DNS record based on the hosts specified for the ingress object, as well as the `external-dns.alpha.kubernetes.io/hostname` annotation. For services ExternalDNS will look for the annotation `external-dns.alpha.kubernetes.io/hostname` on the service and use the corresponding value. + - For ingresses, you can optionally force ExternalDNS to create records based on _either_ the hosts specified or the `external-dns.alpha.kubernetes.io/hostname` annotation. This behavior is controlled by setting the `external-dns.alpha.kubernetes.io/ingress-hostname-source` annotation on that ingress to either `defined-hosts-only` or `annotation-only`. 2. If compatibility mode is enabled (e.g. `--compatibility={mate,molecule}` flag), External DNS will parse annotations used by Zalando/Mate, wearemolecule/route53-kubernetes. Compatibility mode with Kops DNS Controller is planned to be added in the future. From 20703084c6d5b3201ad24a244fe8b3419b854641 Mon Sep 17 00:00:00 2001 From: "dan.simone@oracle.com" Date: Fri, 4 Dec 2020 11:04:02 -0800 Subject: [PATCH 008/175] Tidy up the logic that constructs the final list of ingresses based on the hostname source annotation --- source/ingress.go | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/source/ingress.go b/source/ingress.go index c1b1419a7..85ab4d8b3 100644 --- a/source/ingress.go +++ b/source/ingress.go @@ -283,19 +283,24 @@ func endpointsFromIngress(ing *v1beta1.Ingress, ignoreHostnameAnnotation bool, i // Gather endpoints defined on annotations in the ingress var annotationEndpoints []*endpoint.Endpoint - for _, hostname := range getHostnamesFromAnnotations(ing.Annotations) { - annotationEndpoints = append(annotationEndpoints, endpointsForHostname(hostname, targets, ttl, providerSpecific, setIdentifier)...) + if !ignoreHostnameAnnotation { + for _, hostname := range getHostnamesFromAnnotations(ing.Annotations) { + annotationEndpoints = append(annotationEndpoints, endpointsForHostname(hostname, targets, ttl, providerSpecific, setIdentifier)...) + } } // Determine which hostnames to consider in our final list + hostnameSourceAnnotation, hostnameSourceAnnotationExists := ing.Annotations[ingressHostnameSourceKey] + if !hostnameSourceAnnotationExists { + return append(definedHostsEndpoints, annotationEndpoints...) + } + + // Include endpoints according to the hostname source annotation in our final list var endpoints []*endpoint.Endpoint - hostnameSourceAnnotation, exists := ing.Annotations[ingressHostnameSourceKey] - useDefinedHosts := !exists || strings.ToLower(hostnameSourceAnnotation) != IngressHostnameSourceAnnotationOnlyValue - useAnnotationHosts := !exists || strings.ToLower(hostnameSourceAnnotation) != IngressHostnameSourceDefinedHostsOnlyValue - if useDefinedHosts { + if strings.ToLower(hostnameSourceAnnotation) != IngressHostnameSourceAnnotationOnlyValue { endpoints = append(endpoints, definedHostsEndpoints...) } - if !ignoreHostnameAnnotation && useAnnotationHosts { + if strings.ToLower(hostnameSourceAnnotation) != IngressHostnameSourceDefinedHostsOnlyValue { endpoints = append(endpoints, annotationEndpoints...) } return endpoints From 01d426b07befc3875bbde5917cd18d9391f5b741 Mon Sep 17 00:00:00 2001 From: "dan.simone@oracle.com" Date: Mon, 4 Jan 2021 15:39:56 -0800 Subject: [PATCH 009/175] Merge FAQ line --- docs/faq.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/faq.md b/docs/faq.md index 948dfe83f..1aef10570 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -57,9 +57,7 @@ Services exposed via `type=LoadBalancer`, `type=ExternalName` and for the hostna There are three sources of information for ExternalDNS to decide on DNS name. ExternalDNS will pick one in order as listed below: -1. For ingress objects ExternalDNS will create a DNS record based on the host specified for the ingress object. For services ExternalDNS will look for the annotation `external-dns.alpha.kubernetes.io/hostname` on the service and use the loadbalancer IP, it also will look for the annotation `external-dns.alpha.kubernetes.io/internal-hostname` on the service and use the service IP. - -1. For ingress objects ExternalDNS will create a DNS record based on the hosts specified for the ingress object, as well as the `external-dns.alpha.kubernetes.io/hostname` annotation. For services ExternalDNS will look for the annotation `external-dns.alpha.kubernetes.io/hostname` on the service and use the corresponding value. +1. For ingress objects ExternalDNS will create a DNS record based on the hosts specified for the ingress object, as well as the `external-dns.alpha.kubernetes.io/hostname` annotation. For services ExternalDNS will look for the annotation `external-dns.alpha.kubernetes.io/hostname` on the service and use the loadbalancer IP, it also will look for the annotation `external-dns.alpha.kubernetes.io/internal-hostname` on the service and use the service IP. - For ingresses, you can optionally force ExternalDNS to create records based on _either_ the hosts specified or the `external-dns.alpha.kubernetes.io/hostname` annotation. This behavior is controlled by setting the `external-dns.alpha.kubernetes.io/ingress-hostname-source` annotation on that ingress to either `defined-hosts-only` or `annotation-only`. From a70d8010b59c9c3432bceecd47a80455bdf241cf Mon Sep 17 00:00:00 2001 From: "dan.simone@oracle.com" Date: Mon, 4 Jan 2021 15:41:52 -0800 Subject: [PATCH 010/175] Tidy up newline --- docs/faq.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/faq.md b/docs/faq.md index 1aef10570..9fa129841 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -59,8 +59,8 @@ There are three sources of information for ExternalDNS to decide on DNS name. Ex 1. For ingress objects ExternalDNS will create a DNS record based on the hosts specified for the ingress object, as well as the `external-dns.alpha.kubernetes.io/hostname` annotation. For services ExternalDNS will look for the annotation `external-dns.alpha.kubernetes.io/hostname` on the service and use the loadbalancer IP, it also will look for the annotation `external-dns.alpha.kubernetes.io/internal-hostname` on the service and use the service IP. - For ingresses, you can optionally force ExternalDNS to create records based on _either_ the hosts specified or the `external-dns.alpha.kubernetes.io/hostname` annotation. This behavior is controlled by - setting the `external-dns.alpha.kubernetes.io/ingress-hostname-source` annotation on that ingress to either `defined-hosts-only` or `annotation-only`. - + setting the `external-dns.alpha.kubernetes.io/ingress-hostname-source` annotation on that ingress to either `defined-hosts-only` or `annotation-only`. + 2. If compatibility mode is enabled (e.g. `--compatibility={mate,molecule}` flag), External DNS will parse annotations used by Zalando/Mate, wearemolecule/route53-kubernetes. Compatibility mode with Kops DNS Controller is planned to be added in the future. 3. If `--fqdn-template` flag is specified, e.g. `--fqdn-template={{.Name}}.my-org.com`, ExternalDNS will use service/ingress specifications for the provided template to generate DNS name. From 72f0be6eb7a288fe3124179b3a0e71b741599311 Mon Sep 17 00:00:00 2001 From: fboltz Date: Sun, 10 Jan 2021 19:23:02 +0100 Subject: [PATCH 011/175] FEAT: Add GoDaddy provider First commit --- main.go | 4 + pkg/apis/externaldns/types.go | 13 +- provider/godaddy/client.go | 299 +++++++++++++++ provider/godaddy/godaddy.go | 358 ++++++++++++++++++ provider/godaddy/godaddy_test.go | 630 +++++++++++++++++++++++++++++++ 5 files changed, 1303 insertions(+), 1 deletion(-) create mode 100644 provider/godaddy/client.go create mode 100644 provider/godaddy/godaddy.go create mode 100644 provider/godaddy/godaddy_test.go diff --git a/main.go b/main.go index 3b2cf7923..9fe13ba78 100644 --- a/main.go +++ b/main.go @@ -46,6 +46,7 @@ import ( "sigs.k8s.io/external-dns/provider/dnsimple" "sigs.k8s.io/external-dns/provider/dyn" "sigs.k8s.io/external-dns/provider/exoscale" + "sigs.k8s.io/external-dns/provider/godaddy" "sigs.k8s.io/external-dns/provider/google" "sigs.k8s.io/external-dns/provider/hetzner" "sigs.k8s.io/external-dns/provider/infoblox" @@ -297,6 +298,9 @@ func main() { p, err = transip.NewTransIPProvider(cfg.TransIPAccountName, cfg.TransIPPrivateKeyFile, domainFilter, cfg.DryRun) case "scaleway": p, err = scaleway.NewScalewayProvider(ctx, domainFilter, cfg.DryRun) + + case "godaddy": + p, err = godaddy.NewGoDaddyProvider(ctx, domainFilter, cfg.GoDaddyAPIKey, cfg.GoDaddySecretKey, cfg.GoDaddyProduction, cfg.DryRun) default: log.Fatalf("unknown dns provider: %s", cfg.Provider) } diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 01a09cdfa..b86c74350 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -148,6 +148,9 @@ type Config struct { TransIPAccountName string TransIPPrivateKeyFile string DigitalOceanAPIPageSize int + GoDaddyAPIKey string + GoDaddySecretKey string `secure:"yes"` + GoDaddyProduction bool } var defaultConfig = &Config{ @@ -250,6 +253,9 @@ var defaultConfig = &Config{ TransIPAccountName: "", TransIPPrivateKeyFile: "", DigitalOceanAPIPageSize: 50, + GoDaddyAPIKey: "", + GoDaddySecretKey: "", + GoDaddyProduction: true, } // NewConfig returns new Config object @@ -329,7 +335,7 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("service-type-filter", "The service types to take care about (default: all, expected: ClusterIP, NodePort, LoadBalancer or ExternalName)").StringsVar(&cfg.ServiceTypeFilter) // Flags related to providers - app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, aws-sd, google, azure, azure-dns, azure-private-dns, cloudflare, rcodezero, digitalocean, hetzner, dnsimple, akamai, infoblox, dyn, designate, coredns, skydns, inmemory, ovh, pdns, oci, exoscale, linode, rfc2136, ns1, transip, vinyldns, rdns, scaleway, vultr, ultradns)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "aws-sd", "google", "azure", "azure-dns", "hetzner", "azure-private-dns", "alibabacloud", "cloudflare", "rcodezero", "digitalocean", "dnsimple", "akamai", "infoblox", "dyn", "designate", "coredns", "skydns", "inmemory", "ovh", "pdns", "oci", "exoscale", "linode", "rfc2136", "ns1", "transip", "vinyldns", "rdns", "scaleway", "vultr", "ultradns") + app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, aws-sd, google, azure, azure-dns, azure-private-dns, cloudflare, rcodezero, digitalocean, hetzner, dnsimple, akamai, infoblox, dyn, designate, coredns, skydns, inmemory, ovh, pdns, oci, exoscale, linode, rfc2136, ns1, transip, vinyldns, rdns, scaleway, vultr, ultradns)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "aws-sd", "google", "azure", "azure-dns", "hetzner", "azure-private-dns", "alibabacloud", "cloudflare", "rcodezero", "digitalocean", "dnsimple", "akamai", "infoblox", "dyn", "designate", "coredns", "skydns", "inmemory", "ovh", "pdns", "oci", "exoscale", "linode", "rfc2136", "ns1", "transip", "vinyldns", "rdns", "scaleway", "vultr", "ultradns", "godaddy") app.Flag("domain-filter", "Limit possible target zones by a domain suffix; specify multiple times for multiple domains (optional)").Default("").StringsVar(&cfg.DomainFilter) app.Flag("exclude-domains", "Exclude subdomains (optional)").Default("").StringsVar(&cfg.ExcludeDomains) app.Flag("zone-name-filter", "Filter target zones by zone domain (For now, only AzureDNS provider is using this flag); specify multiple times for multiple zones (optional)").Default("").StringsVar(&cfg.ZoneNameFilter) @@ -384,6 +390,11 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("ns1-min-ttl", "Minimal TTL (in seconds) for records. This value will be used if the provided TTL for a service/ingress is lower than this.").IntVar(&cfg.NS1MinTTLSeconds) app.Flag("digitalocean-api-page-size", "Configure the page size used when querying the DigitalOcean API.").Default(strconv.Itoa(defaultConfig.DigitalOceanAPIPageSize)).IntVar(&cfg.DigitalOceanAPIPageSize) + // GoDaddy flags + app.Flag("godaddy-api-key", "When using the GoDaddy provider, specify the API Key (required when --provider=godaddy)").Default(defaultConfig.GoDaddyAPIKey).StringVar(&cfg.GoDaddyAPIKey) + app.Flag("godaddy-api-secret", "When using the GoDaddy provider, specify the API secret (required when --provider=godaddy)").Default(defaultConfig.GoDaddySecretKey).StringVar(&cfg.GoDaddySecretKey) + app.Flag("godaddy-api-production", "When using the GoDaddy provider, specify if production or OTE use (required when --provider=godaddy)").Default(strconv.FormatBool(defaultConfig.GoDaddyProduction)).BoolVar(&cfg.GoDaddyProduction) + // Flags related to TLS communication app.Flag("tls-ca", "When using TLS communication, the path to the certificate authority to verify server communications (optionally specify --tls-client-cert for two-way TLS)").Default(defaultConfig.TLSCA).StringVar(&cfg.TLSCA) app.Flag("tls-client-cert", "When using TLS communication, the path to the certificate to present as a client (not required for TLS)").Default(defaultConfig.TLSClientCert).StringVar(&cfg.TLSClientCert) diff --git a/provider/godaddy/client.go b/provider/godaddy/client.go new file mode 100644 index 000000000..440c3ad27 --- /dev/null +++ b/provider/godaddy/client.go @@ -0,0 +1,299 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package godaddy + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "net/http" + "time" + + "sigs.k8s.io/external-dns/pkg/apis/externaldns" +) + +// DefaultTimeout api requests after 180s +const DefaultTimeout = 180 * time.Second + +// Errors +var ( + ErrAPIDown = errors.New("go-vh: the GoDaddy API is down, it does't respond to /time anymore") +) + +// APIError error +type APIError struct { + Code string + Message string +} + +func (err *APIError) Error() string { + return fmt.Sprintf("Error %s: %q", err.Code, err.Message) +} + +// Logger is the interface that should be implemented for loggers that wish to +// log HTTP requests and HTTP responses. +type Logger interface { + // LogRequest logs an HTTP request. + LogRequest(*http.Request) + + // LogResponse logs an HTTP response. + LogResponse(*http.Response) +} + +// Client represents a client to call the GoDaddy API +type Client struct { + // APIKey holds the Application key + APIKey string + + // APISecret holds the Application secret key + APISecret string + + // API endpoint + APIEndPoint string + + // Client is the underlying HTTP client used to run the requests. It may be overloaded but a default one is instanciated in ``NewClient`` by default. + Client *http.Client + + // Logger is used to log HTTP requests and responses. + Logger Logger + + Timeout time.Duration +} + +// NewClient represents a new client to call the API +func NewClient(production bool, apiKey, apiSecret string) (*Client, error) { + var endpoint string + + if production { + endpoint = "https://api.godaddy.com" + } else { + endpoint = " https://api.ote-godaddy.com" + } + + client := Client{ + APIKey: apiKey, + APISecret: apiSecret, + APIEndPoint: endpoint, + Client: &http.Client{}, + Timeout: DefaultTimeout, + } + + // Get and check the configuration + if err := client.validate(); err != nil { + return nil, err + } + return &client, nil +} + +// +// Common request wrappers +// + +// Get is a wrapper for the GET method +func (c *Client) Get(url string, resType interface{}) error { + return c.CallAPI("GET", url, nil, resType, true) +} + +// Patch is a wrapper for the POST method +func (c *Client) Patch(url string, reqBody, resType interface{}) error { + return c.CallAPI("PATCH", url, reqBody, resType, true) +} + +// Post is a wrapper for the POST method +func (c *Client) Post(url string, reqBody, resType interface{}) error { + return c.CallAPI("POST", url, reqBody, resType, true) +} + +// Put is a wrapper for the PUT method +func (c *Client) Put(url string, reqBody, resType interface{}) error { + return c.CallAPI("PUT", url, reqBody, resType, true) +} + +// Delete is a wrapper for the DELETE method +func (c *Client) Delete(url string, resType interface{}) error { + return c.CallAPI("DELETE", url, nil, resType, true) +} + +// GetWithContext is a wrapper for the GET method +func (c *Client) GetWithContext(ctx context.Context, url string, resType interface{}) error { + return c.CallAPIWithContext(ctx, "GET", url, nil, resType, true) +} + +// PatchWithContext is a wrapper for the POST method +func (c *Client) PatchWithContext(ctx context.Context, url string, reqBody, resType interface{}) error { + return c.CallAPIWithContext(ctx, "PATCH", url, reqBody, resType, true) +} + +// PostWithContext is a wrapper for the POST method +func (c *Client) PostWithContext(ctx context.Context, url string, reqBody, resType interface{}) error { + return c.CallAPIWithContext(ctx, "POST", url, reqBody, resType, true) +} + +// PutWithContext is a wrapper for the PUT method +func (c *Client) PutWithContext(ctx context.Context, url string, reqBody, resType interface{}) error { + return c.CallAPIWithContext(ctx, "PUT", url, reqBody, resType, true) +} + +// DeleteWithContext is a wrapper for the DELETE method +func (c *Client) DeleteWithContext(ctx context.Context, url string, resType interface{}) error { + return c.CallAPIWithContext(ctx, "DELETE", url, nil, resType, true) +} + +// NewRequest returns a new HTTP request +func (c *Client) NewRequest(method, path string, reqBody interface{}, needAuth bool) (*http.Request, error) { + var body []byte + var err error + + if reqBody != nil { + body, err = json.Marshal(reqBody) + if err != nil { + return nil, err + } + } + + target := fmt.Sprintf("%s%s", c.APIEndPoint, path) + req, err := http.NewRequest(method, target, bytes.NewReader(body)) + if err != nil { + return nil, err + } + + // Inject headers + if body != nil { + req.Header.Set("Content-Type", "application/json;charset=utf-8") + } + req.Header.Set("Authorization", fmt.Sprintf("sso-key %s:%s", c.APIKey, c.APISecret)) + req.Header.Set("Accept", "application/json") + req.Header.Set("User-Agent", "ExternalDNS/"+externaldns.Version) + + // Send the request with requested timeout + c.Client.Timeout = c.Timeout + + return req, nil +} + +// Do sends an HTTP request and returns an HTTP response +func (c *Client) Do(req *http.Request) (*http.Response, error) { + if c.Logger != nil { + c.Logger.LogRequest(req) + } + resp, err := c.Client.Do(req) + if err != nil { + return nil, err + } + if c.Logger != nil { + c.Logger.LogResponse(resp) + } + return resp, nil +} + +// CallAPI is the lowest level call helper. If needAuth is true, +// inject authentication headers and sign the request. +// +// Request signature is a sha1 hash on following fields, joined by '+': +// - applicationSecret (from Client instance) +// - consumerKey (from Client instance) +// - capitalized method (from arguments) +// - full request url, including any query string argument +// - full serialized request body +// - server current time (takes time delta into account) +// +// Call will automatically assemble the target url from the endpoint +// configured in the client instance and the path argument. If the reqBody +// argument is not nil, it will also serialize it as json and inject +// the required Content-Type header. +// +// If everything went fine, unmarshall response into resType and return nil +// otherwise, return the error +func (c *Client) CallAPI(method, path string, reqBody, resType interface{}, needAuth bool) error { + return c.CallAPIWithContext(context.Background(), method, path, reqBody, resType, needAuth) +} + +// CallAPIWithContext is the lowest level call helper. If needAuth is true, +// inject authentication headers and sign the request. +// +// Request signature is a sha1 hash on following fields, joined by '+': +// - applicationSecret (from Client instance) +// - consumerKey (from Client instance) +// - capitalized method (from arguments) +// - full request url, including any query string argument +// - full serialized request body +// - server current time (takes time delta into account) +// +// Context is used by http.Client to handle context cancelation +// +// Call will automatically assemble the target url from the endpoint +// configured in the client instance and the path argument. If the reqBody +// argument is not nil, it will also serialize it as json and inject +// the required Content-Type header. +// +// If everything went fine, unmarshall response into resType and return nil +// otherwise, return the error +func (c *Client) CallAPIWithContext(ctx context.Context, method, path string, reqBody, resType interface{}, needAuth bool) error { + req, err := c.NewRequest(method, path, reqBody, needAuth) + if err != nil { + return err + } + req = req.WithContext(ctx) + response, err := c.Do(req) + if err != nil { + return err + } + return c.UnmarshalResponse(response, resType) +} + +// UnmarshalResponse checks the response and unmarshals it into the response +// type if needed Helper function, called from CallAPI +func (c *Client) UnmarshalResponse(response *http.Response, resType interface{}) error { + // Read all the response body + defer response.Body.Close() + body, err := ioutil.ReadAll(response.Body) + if err != nil { + return err + } + + // < 200 && >= 300 : API error + if response.StatusCode < http.StatusOK || response.StatusCode >= http.StatusMultipleChoices { + apiError := &APIError{ + Code: fmt.Sprintf("HTTPStatus: %d", response.StatusCode), + } + + if err = json.Unmarshal(body, apiError); err != nil { + return err + } + + return apiError + } + + // Nothing to unmarshal + if len(body) == 0 || resType == nil { + return nil + } + + return json.Unmarshal(body, &resType) +} + +func (c *Client) validate() error { + var response interface{} + + if err := c.Get("/v1/domains?statuses=ACTIVE", response); err != nil { + return err + } + + return nil +} diff --git a/provider/godaddy/godaddy.go b/provider/godaddy/godaddy.go new file mode 100644 index 000000000..6e25d7d6c --- /dev/null +++ b/provider/godaddy/godaddy.go @@ -0,0 +1,358 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package godaddy + +import ( + "context" + "errors" + "fmt" + "strings" + + log "github.com/sirupsen/logrus" + "golang.org/x/sync/errgroup" + + "sigs.k8s.io/external-dns/endpoint" + "sigs.k8s.io/external-dns/plan" + "sigs.k8s.io/external-dns/provider" +) + +const ( + gdDefaultTTL = 600 + gdCreate = iota + gdUpdate + gdDelete +) + +var ( + // ErrRecordToMutateNotFound when ApplyChange has to update/delete and didn't found the record in the existing zone (Change with no record ID) + ErrRecordToMutateNotFound = errors.New("record to mutate not found in current zone") + // ErrNoDryRun No dry run support for the moment + ErrNoDryRun = errors.New("dry run not supported") +) + +type gdClient interface { + Patch(string, interface{}, interface{}) error + Post(string, interface{}, interface{}) error + Put(string, interface{}, interface{}) error + Get(string, interface{}) error + Delete(string, interface{}) error +} + +// GDProvider declare GoDaddy provider +type GDProvider struct { + provider.BaseProvider + + domainFilter endpoint.DomainFilter + client gdClient + DryRun bool +} + +type gdRecordField struct { + Data string + Name string + Port int + Priority int + Protocol *string + Service *string + TTL int + Type string + Weight int +} + +type gdRecord struct { + gdRecordField + zone *string +} + +type gdChange struct { + gdRecord + Action int +} + +type gdZone struct { + CreatedAt string + Domain string + DomainID int64 + ExpirationProtected bool + Expires string + ExposeWhois bool + HoldRegistrar bool + Locked bool + NameServers *[]string + Privacy bool + RenewAuto bool + RenewDeadline string + Renewable bool + Status string + TransferProtected bool +} + +// NewGoDaddyProvider initializes a new OVH DNS based Provider. +func NewGoDaddyProvider(ctx context.Context, domainFilter endpoint.DomainFilter, apiKey, apiSecret string, production, dryRun bool) (*GDProvider, error) { + client, err := NewClient(production, apiKey, apiSecret) + + if err != nil { + return nil, err + } + + // TODO: Add Dry Run support + if dryRun { + return nil, ErrNoDryRun + } + + return &GDProvider{ + client: client, + domainFilter: domainFilter, + DryRun: dryRun, + }, nil +} + +func (p *GDProvider) zones() ([]string, error) { + zones := []gdZone{} + filteredZones := []string{} + + if err := p.client.Get("/v1/domains?statuses=ACTIVE", &zones); err != nil { + return nil, err + } + + for _, zone := range zones { + if p.domainFilter.Match(zone.Domain) { + filteredZones = append(filteredZones, zone.Domain) + } + } + + log.Infof("GoDaddy: %d zones found", len(filteredZones)) + + return filteredZones, nil +} + +func (p *GDProvider) zonesRecords(ctx context.Context) ([]string, []gdRecord, error) { + var allRecords []gdRecord + zones, err := p.zones() + + if err != nil { + return nil, nil, err + } + + chRecords := make(chan []gdRecord, len(zones)) + + eg, ctx := errgroup.WithContext(ctx) + + for _, zone := range zones { + zone := zone + eg.Go(func() error { + return p.records(&ctx, &zone, chRecords) + }) + } + + if err := eg.Wait(); err != nil { + return nil, nil, err + } + + close(chRecords) + + for records := range chRecords { + allRecords = append(allRecords, records...) + } + + return zones, allRecords, nil +} + +func (p *GDProvider) records(ctx *context.Context, zone *string, records chan<- []gdRecord) error { + var recordsIds []gdRecord + + log.Debugf("GoDaddy: Getting records for %s", *zone) + + if err := p.client.Get(fmt.Sprintf("/v1/domains/%s/records", *zone), &recordsIds); err != nil { + return err + } + + results := make([]gdRecord, 0, len(recordsIds)) + + for _, rec := range recordsIds { + if provider.SupportedRecordType(rec.Type) { + log.Debugf("GoDaddy: Record %s for %s is %+v", rec.Name, *zone, rec) + + rec.zone = zone + results = append(results, rec) + } + } + + records <- results + + return nil +} + +func (p *GDProvider) groupByNameAndType(records []gdRecord) []*endpoint.Endpoint { + endpoints := []*endpoint.Endpoint{} + + // group supported records by name and type + groups := map[string][]gdRecord{} + + for _, r := range records { + groupBy := fmt.Sprintf("%s - %s.%s", r.Type, r.Name, *r.zone) + + if _, ok := groups[groupBy]; !ok { + groups[groupBy] = []gdRecord{} + } + + groups[groupBy] = append(groups[groupBy], r) + } + + // create single endpoint with all the targets for each name/type + for _, records := range groups { + targets := []string{} + + for _, record := range records { + targets = append(targets, record.Data) + } + + endpoint := endpoint.NewEndpointWithTTL( + strings.TrimPrefix(fmt.Sprintf("%s.%s", records[0].Name, *records[0].zone), "."), + records[0].Type, + endpoint.TTL(records[0].TTL), + targets..., + ) + + endpoints = append(endpoints, endpoint) + } + + return endpoints +} + +// Records returns the list of records in all relevant zones. +func (p *GDProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error) { + _, records, err := p.zonesRecords(ctx) + + if err != nil { + return nil, err + } + + endpoints := p.groupByNameAndType(records) + + log.Infof("GoDaddy: %d endpoints have been found", len(endpoints)) + + return endpoints, nil +} + +func (p *GDProvider) change(change gdChange) error { + switch change.Action { + case gdCreate: + log.Debugf("GoDaddy: Add an entry to %s", change.String()) + return p.client.Patch(fmt.Sprintf("/v1/domains/%s/records", *change.zone), []gdRecordField{change.gdRecord.gdRecordField}, nil) + case gdUpdate: + log.Debugf("GoDaddy: Update an entry to %s", change.String()) + return p.client.Put(fmt.Sprintf("/v1/domains/%s/records/%s/%s", *change.zone, change.Type, change.Name), []gdRecordField{change.gdRecord.gdRecordField}, nil) + case gdDelete: + log.Debugf("GoDaddy: Delete an entry to %s", change.String()) + return p.client.Delete(fmt.Sprintf("/v1/domains/%s/records/%s/%s", *change.zone, change.Type, change.Name), nil) + } + return nil +} + +// ApplyChanges applies a given set of changes in a given zone. +func (p *GDProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error { + zones, records, err := p.zonesRecords(ctx) + zonesChangeUniques := map[string]bool{} + if err != nil { + return err + } + + allChanges := make([]gdChange, 0, countTargets(changes.Create, changes.UpdateNew, changes.UpdateOld, changes.Delete)) + + allChanges = append(allChanges, newGoDaddyChange(gdCreate, changes.Create, zones, records)...) + allChanges = append(allChanges, newGoDaddyChange(gdCreate, changes.UpdateNew, zones, records)...) + + allChanges = append(allChanges, newGoDaddyChange(gdDelete, changes.UpdateOld, zones, records)...) + allChanges = append(allChanges, newGoDaddyChange(gdDelete, changes.Delete, zones, records)...) + + log.Infof("GoDaddy: %d changes will be done", len(allChanges)) + + eg, _ := errgroup.WithContext(ctx) + + for _, change := range allChanges { + change := change + zonesChangeUniques[*change.zone] = true + + eg.Go(func() error { return p.change(change) }) + } + + if err := eg.Wait(); err != nil { + return err + } + + return nil +} + +func countTargets(allEndpoints ...[]*endpoint.Endpoint) int { + count := 0 + for _, endpoints := range allEndpoints { + for _, endpoint := range endpoints { + count += len(endpoint.Targets) + } + } + return count +} + +func newGoDaddyChange(action int, endpoints []*endpoint.Endpoint, zones []string, records []gdRecord) []gdChange { + gdChanges := make([]gdChange, 0, countTargets(endpoints)) + zoneNameIDMapper := provider.ZoneIDName{} + + for _, zone := range zones { + zoneNameIDMapper.Add(zone, zone) + } + + for _, e := range endpoints { + zone, _ := zoneNameIDMapper.FindZone(e.DNSName) + + if zone == "" { + log.Debugf("Skipping record %s because no hosted zone matching record DNS Name was detected", e.DNSName) + continue + } + + for _, target := range e.Targets { + if e.RecordType == endpoint.RecordTypeCNAME { + target = target + "." + } + + change := gdChange{ + Action: action, + gdRecord: gdRecord{ + zone: &zone, + gdRecordField: gdRecordField{ + Type: e.RecordType, + Name: strings.TrimSuffix(e.DNSName, "."+zone), + TTL: gdDefaultTTL, + Data: target, + }, + }, + } + + if e.RecordTTL.IsConfigured() { + change.TTL = int(e.RecordTTL) + } + + gdChanges = append(gdChanges, change) + } + } + + return gdChanges +} + +func (c *gdChange) String() string { + return fmt.Sprintf("%s zone : %s %d IN %s %s", *c.zone, c.Name, c.TTL, c.Type, c.Data) +} diff --git a/provider/godaddy/godaddy_test.go b/provider/godaddy/godaddy_test.go new file mode 100644 index 000000000..701ed78b8 --- /dev/null +++ b/provider/godaddy/godaddy_test.go @@ -0,0 +1,630 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package godaddy + +import ( + "context" + "encoding/json" + "sort" + "testing" + + "github.com/ovh/go-ovh/ovh" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "sigs.k8s.io/external-dns/endpoint" + "sigs.k8s.io/external-dns/plan" +) + +type mockGoDaddyClient struct { + mock.Mock +} + +var ( + zoneNameExampleOrg string = "example.org" + zoneNameExampleNet string = "example.net" +) + +func (c *mockGoDaddyClient) Post(endpoint string, input interface{}, output interface{}) error { + stub := c.Called(endpoint, input) + data, _ := json.Marshal(stub.Get(0)) + json.Unmarshal(data, output) + return stub.Error(1) +} + +func (c *mockGoDaddyClient) Patch(endpoint string, input interface{}, output interface{}) error { + stub := c.Called(endpoint, input) + data, _ := json.Marshal(stub.Get(0)) + json.Unmarshal(data, output) + return stub.Error(1) +} + +func (c *mockGoDaddyClient) Put(endpoint string, input interface{}, output interface{}) error { + stub := c.Called(endpoint, input) + data, _ := json.Marshal(stub.Get(0)) + json.Unmarshal(data, output) + return stub.Error(1) +} + +func (c *mockGoDaddyClient) Get(endpoint string, output interface{}) error { + stub := c.Called(endpoint) + data, _ := json.Marshal(stub.Get(0)) + json.Unmarshal(data, output) + return stub.Error(1) +} + +func (c *mockGoDaddyClient) Delete(endpoint string, output interface{}) error { + stub := c.Called(endpoint) + data, _ := json.Marshal(stub.Get(0)) + json.Unmarshal(data, output) + return stub.Error(1) +} + +func TestGoDaddyZones(t *testing.T) { + assert := assert.New(t) + client := new(mockGoDaddyClient) + provider := &GDProvider{ + client: client, + domainFilter: endpoint.NewDomainFilter([]string{"com"}), + } + + // Basic zones + client.On("Get", "/v1/domains?statuses=ACTIVE").Return([]gdZone{ + { + Domain: "example.com", + }, + { + Domain: "example.net", + }, + }, nil).Once() + + domains, err := provider.zones() + + assert.NoError(err) + assert.Contains(domains, "example.com") + assert.NotContains(domains, "example.net") + + client.AssertExpectations(t) + + // Error on getting zones + client.On("Get", "/v1/domains?statuses=ACTIVE").Return(nil, ErrAPIDown).Once() + domains, err = provider.zones() + assert.Error(err) + assert.Nil(domains) + client.AssertExpectations(t) +} + +func TestGoDaddyZoneRecords(t *testing.T) { + assert := assert.New(t) + client := new(mockGoDaddyClient) + provider := &GDProvider{ + client: client, + } + + // Basic zones records + client.On("Get", "/v1/domains?statuses=ACTIVE").Return([]gdZone{ + { + Domain: zoneNameExampleNet, + }, + }, nil).Once() + + client.On("Get", "/v1/domains/example.net/records").Return([]gdRecord{ + { + zone: &zoneNameExampleNet, + gdRecordField: gdRecordField{ + Name: "godaddy", + Type: "NS", + TTL: 10, + Data: "203.0.113.42", + }, + }, + { + zone: &zoneNameExampleNet, + gdRecordField: gdRecordField{ + Name: "godaddy", + Type: "A", + TTL: 10, + Data: "203.0.113.42", + }, + }, + }, nil).Once() + + zones, records, err := provider.zonesRecords(context.TODO()) + + assert.NoError(err) + + assert.ElementsMatch(zones, []string{ + zoneNameExampleNet, + }) + + assert.ElementsMatch(records, []gdRecord{ + { + zone: &zoneNameExampleNet, + gdRecordField: gdRecordField{ + Name: "godaddy", + Type: "NS", + TTL: 10, + Data: "203.0.113.42", + }, + }, + { + zone: &zoneNameExampleNet, + gdRecordField: gdRecordField{ + Name: "godaddy", + Type: "A", + TTL: 10, + Data: "203.0.113.42", + }, + }, + }) + + client.AssertExpectations(t) + + // Error on getting zones list + client.On("Get", "/v1/domains?statuses=ACTIVE").Return(nil, ErrAPIDown).Once() + zones, records, err = provider.zonesRecords(context.TODO()) + assert.Error(err) + assert.Nil(zones) + assert.Nil(records) + client.AssertExpectations(t) + + // Error on getting zone records + client.On("Get", "/v1/domains?statuses=ACTIVE").Return([]gdZone{ + { + Domain: zoneNameExampleNet, + }, + }, nil).Once() + + client.On("Get", "/v1/domains/example.net/records").Return(nil, ErrAPIDown).Once() + + zones, records, err = provider.zonesRecords(context.TODO()) + + assert.Error(err) + assert.Nil(zones) + assert.Nil(records) + client.AssertExpectations(t) + + // Error on getting zone record detail + client.On("Get", "/v1/domains?statuses=ACTIVE").Return([]gdZone{ + { + Domain: zoneNameExampleNet, + }, + }, nil).Once() + + client.On("Get", "/v1/domains/example.net/records").Return(nil, ErrAPIDown).Once() + + zones, records, err = provider.zonesRecords(context.TODO()) + assert.Error(err) + assert.Nil(zones) + assert.Nil(records) + client.AssertExpectations(t) +} + +func TestGoDaddyRecords(t *testing.T) { + assert := assert.New(t) + client := new(mockGoDaddyClient) + provider := &GDProvider{ + client: client, + } + + // Basic zones records + client.On("Get", "/v1/domains?statuses=ACTIVE").Return([]gdZone{ + { + Domain: zoneNameExampleOrg, + }, + { + Domain: zoneNameExampleNet, + }, + }, nil).Once() + + client.On("Get", "/v1/domains/example.org/records").Return([]gdRecord{ + { + zone: &zoneNameExampleOrg, + gdRecordField: gdRecordField{ + Name: "@", + Type: "A", + TTL: 10, + Data: "203.0.113.42", + }, + }, + { + zone: &zoneNameExampleOrg, + gdRecordField: gdRecordField{ + Name: "www", + Type: "CNAME", + TTL: 10, + Data: "example.org", + }, + }, + }, nil).Once() + + client.On("Get", "/v1/domains/example.net/records").Return([]gdRecord{ + { + zone: &zoneNameExampleNet, + gdRecordField: gdRecordField{ + Name: "godaddy", + Type: "A", + TTL: 10, + Data: "203.0.113.42", + }, + }, + { + zone: &zoneNameExampleNet, + gdRecordField: gdRecordField{ + Name: "godaddy", + Type: "A", + TTL: 10, + Data: "203.0.113.43", + }, + }, + }, nil).Once() + + endpoints, err := provider.Records(context.TODO()) + assert.NoError(err) + + // Little fix for multi targets endpoint + for _, endpoint := range endpoints { + sort.Strings(endpoint.Targets) + } + + assert.ElementsMatch(endpoints, []*endpoint.Endpoint{ + { + DNSName: "example.org", + RecordType: "A", + RecordTTL: 10, + Labels: endpoint.NewLabels(), + Targets: []string{ + "203.0.113.42", + }, + }, + { + DNSName: "www.example.org", + RecordType: "CNAME", + RecordTTL: 10, + Labels: endpoint.NewLabels(), + Targets: []string{ + "example.org", + }, + }, + { + DNSName: "godaddy.example.net", + RecordType: "A", + RecordTTL: 10, + Labels: endpoint.NewLabels(), + Targets: []string{ + "203.0.113.42", + "203.0.113.43", + }, + }, + }) + + client.AssertExpectations(t) + + // Error getting zone + client.On("Get", "/v1/domains?statuses=ACTIVE").Return(nil, ovh.ErrAPIDown).Once() + endpoints, err = provider.Records(context.TODO()) + assert.Error(err) + assert.Nil(endpoints) + client.AssertExpectations(t) +} + +func TestGoDaddyNewChange(t *testing.T) { + assert := assert.New(t) + endpoints := []*endpoint.Endpoint{ + { + DNSName: ".example.net", + RecordType: "A", + RecordTTL: 10, Targets: []string{ + "203.0.113.42", + }, + }, + { + DNSName: "godaddy.example.net", + RecordType: "A", + Targets: []string{ + "203.0.113.43", + }, + }, + { + DNSName: "godaddy2.example.net", + RecordType: "CNAME", + Targets: []string{ + "godaddy.example.net", + }, + }, + { + DNSName: "test.example.org", + }, + } + + // Create change + changes := newGoDaddyChange(gdCreate, endpoints, []string{"example.net"}, []gdRecord{}) + + assert.ElementsMatch(changes, []gdChange{ + { + Action: gdCreate, + gdRecord: gdRecord{ + zone: &zoneNameExampleNet, + gdRecordField: gdRecordField{ + Name: "", + Type: "A", + TTL: 10, + Data: "203.0.113.42", + }, + }, + }, + { + Action: gdCreate, + gdRecord: gdRecord{ + zone: &zoneNameExampleNet, + gdRecordField: gdRecordField{ + Name: "godaddy", + Type: "A", + TTL: gdDefaultTTL, + Data: "203.0.113.43", + }, + }, + }, + { + Action: gdCreate, + gdRecord: gdRecord{ + zone: &zoneNameExampleNet, + gdRecordField: gdRecordField{ + Name: "godaddy2", + Type: "CNAME", + TTL: gdDefaultTTL, + Data: "godaddy.example.net.", + }, + }, + }}) + + // Delete change + endpoints = []*endpoint.Endpoint{ + { + DNSName: "godaddy.example.net", + RecordType: "A", + Targets: []string{ + "203.0.113.42", + }, + }, + } + + records := []gdRecord{ + { + zone: &zoneNameExampleNet, + gdRecordField: gdRecordField{ + Type: "A", + Name: "godaddy", + Data: "203.0.113.42", + }, + }, + } + + changes = newGoDaddyChange(gdDelete, endpoints, []string{ + zoneNameExampleNet, + }, records) + + assert.ElementsMatch(changes, []gdChange{ + { + Action: gdDelete, + gdRecord: gdRecord{ + zone: &zoneNameExampleNet, + gdRecordField: gdRecordField{ + Name: "godaddy", + Type: "A", + TTL: gdDefaultTTL, + Data: "203.0.113.42", + }, + }, + }, + }) +} + +func TestGoDaddyApplyChanges(t *testing.T) { + assert := assert.New(t) + client := new(mockGoDaddyClient) + + provider := &GDProvider{ + client: client, + } + + changes := plan.Changes{ + Create: []*endpoint.Endpoint{ + { + DNSName: ".example.net", + RecordType: "A", + RecordTTL: 10, + Targets: []string{ + "203.0.113.42", + }, + }, + }, + Delete: []*endpoint.Endpoint{ + { + DNSName: "godaddy.example.net", + RecordType: "A", + Targets: []string{ + "203.0.113.43", + }, + }, + }, + } + + client.On("Get", "/v1/domains?statuses=ACTIVE").Return([]gdZone{ + { + Domain: zoneNameExampleNet, + }, + }, nil).Once() + + client.On("Get", "/v1/domains/example.net/records").Return([]gdRecord{ + { + zone: &zoneNameExampleNet, + gdRecordField: gdRecordField{ + Name: "godaddy", + Type: "A", + TTL: 10, + Data: "203.0.113.43", + }, + }, + }, nil).Once() + + client.On("Get", "/v1/domains/example.net/records/A/goddady").Return([]gdRecord{ + { + zone: &zoneNameExampleNet, + gdRecordField: gdRecordField{ + Name: "godaddy", + Type: "A", + TTL: 10, + Data: "203.0.113.43", + }, + }, + }, nil).Once() + + client.On("Patch", "/v1/domains/example.net/records", []gdRecordField{ + { + Name: "@", + Type: "A", + TTL: 10, + Data: "203.0.113.42", + }, + }).Return(nil, nil).Once() + + client.On("Delete", "/v1/domains/example.net/records/A/@").Return(nil, nil).Once() + + // Basic changes + assert.NoError(provider.ApplyChanges(context.TODO(), &changes)) + + client.AssertExpectations(t) + + // Getting zones failed + client.On("Get", "/v1/domains?statuses=ACTIVE").Return(nil, ErrAPIDown).Once() + assert.Error(provider.ApplyChanges(context.TODO(), &changes)) + client.AssertExpectations(t) + + // Apply change failed + client.On("Get", "/v1/domains?statuses=ACTIVE").Return([]gdZone{ + { + Domain: zoneNameExampleNet, + }, + }, nil).Once() + + client.On("Get", "/v1/domains/example.net/records").Return([]gdRecord{}, nil).Once() + + client.On("Patch", "/v1/domains/example.net/records/A/godaddy", []gdRecordField{ + { + Name: "", + Type: "A", + TTL: 10, + Data: "203.0.113.42", + }, + }).Return(nil, ErrAPIDown).Once() + + assert.Error(provider.ApplyChanges(context.TODO(), &plan.Changes{ + Create: []*endpoint.Endpoint{ + { + DNSName: ".example.net", + RecordType: "A", + RecordTTL: 10, + Targets: []string{ + "203.0.113.42", + }, + }, + }, + })) + + client.AssertExpectations(t) +} + +func TestGoDaddyChange(t *testing.T) { + assert := assert.New(t) + client := new(mockGoDaddyClient) + provider := &GDProvider{ + client: client, + } + + // Record creation + client.On("Patch", "/v1/domains/example.net/records", []gdRecordField{ + { + Name: "godaddy", + Type: "A", + TTL: 10, + Data: "203.0.113.42", + }, + }).Return(nil, nil).Once() + + assert.NoError(provider.change(gdChange{ + Action: gdCreate, + gdRecord: gdRecord{ + zone: &zoneNameExampleNet, + gdRecordField: gdRecordField{ + Name: "godaddy", + Type: "A", + TTL: 10, + Data: "203.0.113.42", + }, + }, + })) + + client.AssertExpectations(t) + + // Record deletion + client.On("Delete", "/v1/domains/example.net/records/A/godaddy").Return(nil, nil).Once() + + assert.NoError(provider.change(gdChange{ + Action: gdDelete, + gdRecord: gdRecord{ + zone: &zoneNameExampleNet, + gdRecordField: gdRecordField{ + Name: "godaddy", + Type: "A", + }, + }, + })) + + client.AssertExpectations(t) + + // Record deletion error + assert.Error(provider.change(gdChange{ + Action: gdDelete, + gdRecord: gdRecord{ + zone: &zoneNameExampleNet, + gdRecordField: gdRecordField{ + Name: "godaddy", + Type: "A", + }, + }, + })) + + client.AssertExpectations(t) +} + +func TestOGoDaddyCountTargets(t *testing.T) { + cases := []struct { + endpoints [][]*endpoint.Endpoint + count int + }{ + {[][]*endpoint.Endpoint{{{DNSName: "godaddy.example.net", Targets: endpoint.Targets{"target"}}}}, 1}, + {[][]*endpoint.Endpoint{{{DNSName: "godaddy.example.net", Targets: endpoint.Targets{"target"}}, {DNSName: "godaddy.example.net", Targets: endpoint.Targets{"target"}}}}, 2}, + {[][]*endpoint.Endpoint{{{DNSName: "godaddy.example.net", Targets: endpoint.Targets{"target", "target", "target"}}}}, 3}, + {[][]*endpoint.Endpoint{{{DNSName: "godaddy.example.net", Targets: endpoint.Targets{"target", "target"}}}, {{DNSName: "godaddy.example.net", Targets: endpoint.Targets{"target", "target"}}}}, 4}, + } + for _, test := range cases { + count := countTargets(test.endpoints...) + if count != test.count { + t.Errorf("Wrong targets counts (Should be %d, get %d)", test.count, count) + } + } +} From 8a8e2412a6e1a3d8fcbdd81abf982bb82628115a Mon Sep 17 00:00:00 2001 From: fboltz Date: Mon, 11 Jan 2021 17:35:36 +0100 Subject: [PATCH 012/175] Handle wildcard subdomain --- provider/godaddy/godaddy.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/provider/godaddy/godaddy.go b/provider/godaddy/godaddy.go index 6e25d7d6c..b3c4aba7c 100644 --- a/provider/godaddy/godaddy.go +++ b/provider/godaddy/godaddy.go @@ -221,8 +221,16 @@ func (p *GDProvider) groupByNameAndType(records []gdRecord) []*endpoint.Endpoint targets = append(targets, record.Data) } + var recordName string + + if records[0].Name == "*" || records[0].Name == "@" { + recordName = strings.TrimPrefix(*records[0].zone, ".") + } else { + recordName = strings.TrimPrefix(fmt.Sprintf("%s.%s", records[0].Name, *records[0].zone), ".") + } + endpoint := endpoint.NewEndpointWithTTL( - strings.TrimPrefix(fmt.Sprintf("%s.%s", records[0].Name, *records[0].zone), "."), + recordName, records[0].Type, endpoint.TTL(records[0].TTL), targets..., From 1152334a1ecd7a235ee16fd0a91ad601cce628c7 Mon Sep 17 00:00:00 2001 From: fboltz Date: Mon, 11 Jan 2021 17:36:17 +0100 Subject: [PATCH 013/175] Sort the response to match test --- provider/godaddy/godaddy_test.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/provider/godaddy/godaddy_test.go b/provider/godaddy/godaddy_test.go index 701ed78b8..bb6930961 100644 --- a/provider/godaddy/godaddy_test.go +++ b/provider/godaddy/godaddy_test.go @@ -281,6 +281,16 @@ func TestGoDaddyRecords(t *testing.T) { } assert.ElementsMatch(endpoints, []*endpoint.Endpoint{ + { + DNSName: "godaddy.example.net", + RecordType: "A", + RecordTTL: 10, + Labels: endpoint.NewLabels(), + Targets: []string{ + "203.0.113.42", + "203.0.113.43", + }, + }, { DNSName: "example.org", RecordType: "A", @@ -299,16 +309,6 @@ func TestGoDaddyRecords(t *testing.T) { "example.org", }, }, - { - DNSName: "godaddy.example.net", - RecordType: "A", - RecordTTL: 10, - Labels: endpoint.NewLabels(), - Targets: []string{ - "203.0.113.42", - "203.0.113.43", - }, - }, }) client.AssertExpectations(t) From 78996ed8e18e45309db73c6005cb231f385861cd Mon Sep 17 00:00:00 2001 From: fboltz Date: Mon, 11 Jan 2021 17:48:34 +0100 Subject: [PATCH 014/175] FIX: Remove uneeded test --- provider/godaddy/godaddy_test.go | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/provider/godaddy/godaddy_test.go b/provider/godaddy/godaddy_test.go index bb6930961..1786a53d0 100644 --- a/provider/godaddy/godaddy_test.go +++ b/provider/godaddy/godaddy_test.go @@ -595,20 +595,6 @@ func TestGoDaddyChange(t *testing.T) { })) client.AssertExpectations(t) - - // Record deletion error - assert.Error(provider.change(gdChange{ - Action: gdDelete, - gdRecord: gdRecord{ - zone: &zoneNameExampleNet, - gdRecordField: gdRecordField{ - Name: "godaddy", - Type: "A", - }, - }, - })) - - client.AssertExpectations(t) } func TestOGoDaddyCountTargets(t *testing.T) { From 930067ae767b40a3db276e3030a164dc3bf3e9d9 Mon Sep 17 00:00:00 2001 From: fboltz Date: Mon, 11 Jan 2021 21:09:49 +0100 Subject: [PATCH 015/175] FIX: Wildcard handling --- provider/godaddy/godaddy.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/provider/godaddy/godaddy.go b/provider/godaddy/godaddy.go index b3c4aba7c..ca9ca00e0 100644 --- a/provider/godaddy/godaddy.go +++ b/provider/godaddy/godaddy.go @@ -223,7 +223,7 @@ func (p *GDProvider) groupByNameAndType(records []gdRecord) []*endpoint.Endpoint var recordName string - if records[0].Name == "*" || records[0].Name == "@" { + if records[0].Name == "@" { recordName = strings.TrimPrefix(*records[0].zone, ".") } else { recordName = strings.TrimPrefix(fmt.Sprintf("%s.%s", records[0].Name, *records[0].zone), ".") @@ -332,9 +332,18 @@ func newGoDaddyChange(action int, endpoints []*endpoint.Endpoint, zones []string continue } + dnsName := strings.TrimSuffix(e.DNSName, "."+zone) + + if e.RecordType == endpoint.RecordTypeA && (len(dnsName) == 0) { + dnsName = "@" + } + for _, target := range e.Targets { + if e.RecordType == endpoint.RecordTypeCNAME { target = target + "." + } else if e.RecordType == endpoint.RecordTypeA && (len(dnsName) == 0 || dnsName == ".") { + dnsName = "@" } change := gdChange{ @@ -343,7 +352,7 @@ func newGoDaddyChange(action int, endpoints []*endpoint.Endpoint, zones []string zone: &zone, gdRecordField: gdRecordField{ Type: e.RecordType, - Name: strings.TrimSuffix(e.DNSName, "."+zone), + Name: dnsName, TTL: gdDefaultTTL, Data: target, }, From 6d1d133ee775da62f6f940a023365984bc904e5f Mon Sep 17 00:00:00 2001 From: fboltz Date: Mon, 11 Jan 2021 21:10:56 +0100 Subject: [PATCH 016/175] FIX: Don't use channel, execution order is not garanty --- provider/godaddy/godaddy.go | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/provider/godaddy/godaddy.go b/provider/godaddy/godaddy.go index ca9ca00e0..df8e3f80e 100644 --- a/provider/godaddy/godaddy.go +++ b/provider/godaddy/godaddy.go @@ -275,7 +275,7 @@ func (p *GDProvider) change(change gdChange) error { // ApplyChanges applies a given set of changes in a given zone. func (p *GDProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error { zones, records, err := p.zonesRecords(ctx) - zonesChangeUniques := map[string]bool{} + if err != nil { return err } @@ -290,17 +290,10 @@ func (p *GDProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) er log.Infof("GoDaddy: %d changes will be done", len(allChanges)) - eg, _ := errgroup.WithContext(ctx) - for _, change := range allChanges { - change := change - zonesChangeUniques[*change.zone] = true - - eg.Go(func() error { return p.change(change) }) - } - - if err := eg.Wait(); err != nil { - return err + if err = p.change(change); err != nil { + return err + } } return nil From 787fdd08bbebb6d0e98f7d075bc3fc941320ba3c Mon Sep 17 00:00:00 2001 From: fboltz Date: Mon, 11 Jan 2021 21:11:29 +0100 Subject: [PATCH 017/175] FIX: Make test working --- provider/godaddy/godaddy_test.go | 44 ++++++++++++++++---------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/provider/godaddy/godaddy_test.go b/provider/godaddy/godaddy_test.go index 1786a53d0..886d0c622 100644 --- a/provider/godaddy/godaddy_test.go +++ b/provider/godaddy/godaddy_test.go @@ -23,6 +23,7 @@ import ( "testing" "github.com/ovh/go-ovh/ovh" + log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "sigs.k8s.io/external-dns/endpoint" @@ -31,6 +32,13 @@ import ( type mockGoDaddyClient struct { mock.Mock + currentTest *testing.T +} + +func newMockGoDaddyClient(t *testing.T) *mockGoDaddyClient { + return &mockGoDaddyClient{ + currentTest: t, + } } var ( @@ -39,6 +47,7 @@ var ( ) func (c *mockGoDaddyClient) Post(endpoint string, input interface{}, output interface{}) error { + log.Infof("POST: %s - %v", endpoint, input) stub := c.Called(endpoint, input) data, _ := json.Marshal(stub.Get(0)) json.Unmarshal(data, output) @@ -46,6 +55,7 @@ func (c *mockGoDaddyClient) Post(endpoint string, input interface{}, output inte } func (c *mockGoDaddyClient) Patch(endpoint string, input interface{}, output interface{}) error { + log.Infof("PATCH: %s - %v", endpoint, input) stub := c.Called(endpoint, input) data, _ := json.Marshal(stub.Get(0)) json.Unmarshal(data, output) @@ -53,6 +63,7 @@ func (c *mockGoDaddyClient) Patch(endpoint string, input interface{}, output int } func (c *mockGoDaddyClient) Put(endpoint string, input interface{}, output interface{}) error { + log.Infof("PUT: %s - %v", endpoint, input) stub := c.Called(endpoint, input) data, _ := json.Marshal(stub.Get(0)) json.Unmarshal(data, output) @@ -60,6 +71,7 @@ func (c *mockGoDaddyClient) Put(endpoint string, input interface{}, output inter } func (c *mockGoDaddyClient) Get(endpoint string, output interface{}) error { + log.Infof("GET: %s", endpoint) stub := c.Called(endpoint) data, _ := json.Marshal(stub.Get(0)) json.Unmarshal(data, output) @@ -67,6 +79,7 @@ func (c *mockGoDaddyClient) Get(endpoint string, output interface{}) error { } func (c *mockGoDaddyClient) Delete(endpoint string, output interface{}) error { + log.Infof("DELETE: %s", endpoint) stub := c.Called(endpoint) data, _ := json.Marshal(stub.Get(0)) json.Unmarshal(data, output) @@ -75,7 +88,7 @@ func (c *mockGoDaddyClient) Delete(endpoint string, output interface{}) error { func TestGoDaddyZones(t *testing.T) { assert := assert.New(t) - client := new(mockGoDaddyClient) + client := newMockGoDaddyClient(t) provider := &GDProvider{ client: client, domainFilter: endpoint.NewDomainFilter([]string{"com"}), @@ -109,7 +122,7 @@ func TestGoDaddyZones(t *testing.T) { func TestGoDaddyZoneRecords(t *testing.T) { assert := assert.New(t) - client := new(mockGoDaddyClient) + client := newMockGoDaddyClient(t) provider := &GDProvider{ client: client, } @@ -215,7 +228,7 @@ func TestGoDaddyZoneRecords(t *testing.T) { func TestGoDaddyRecords(t *testing.T) { assert := assert.New(t) - client := new(mockGoDaddyClient) + client := newMockGoDaddyClient(t) provider := &GDProvider{ client: client, } @@ -359,7 +372,7 @@ func TestGoDaddyNewChange(t *testing.T) { gdRecord: gdRecord{ zone: &zoneNameExampleNet, gdRecordField: gdRecordField{ - Name: "", + Name: "@", Type: "A", TTL: 10, Data: "203.0.113.42", @@ -435,7 +448,7 @@ func TestGoDaddyNewChange(t *testing.T) { func TestGoDaddyApplyChanges(t *testing.T) { assert := assert.New(t) - client := new(mockGoDaddyClient) + client := newMockGoDaddyClient(t) provider := &GDProvider{ client: client, @@ -462,7 +475,6 @@ func TestGoDaddyApplyChanges(t *testing.T) { }, }, } - client.On("Get", "/v1/domains?statuses=ACTIVE").Return([]gdZone{ { Domain: zoneNameExampleNet, @@ -481,18 +493,6 @@ func TestGoDaddyApplyChanges(t *testing.T) { }, }, nil).Once() - client.On("Get", "/v1/domains/example.net/records/A/goddady").Return([]gdRecord{ - { - zone: &zoneNameExampleNet, - gdRecordField: gdRecordField{ - Name: "godaddy", - Type: "A", - TTL: 10, - Data: "203.0.113.43", - }, - }, - }, nil).Once() - client.On("Patch", "/v1/domains/example.net/records", []gdRecordField{ { Name: "@", @@ -502,7 +502,7 @@ func TestGoDaddyApplyChanges(t *testing.T) { }, }).Return(nil, nil).Once() - client.On("Delete", "/v1/domains/example.net/records/A/@").Return(nil, nil).Once() + client.On("Delete", "/v1/domains/example.net/records/A/godaddy").Return(nil, nil).Once() // Basic changes assert.NoError(provider.ApplyChanges(context.TODO(), &changes)) @@ -523,9 +523,9 @@ func TestGoDaddyApplyChanges(t *testing.T) { client.On("Get", "/v1/domains/example.net/records").Return([]gdRecord{}, nil).Once() - client.On("Patch", "/v1/domains/example.net/records/A/godaddy", []gdRecordField{ + client.On("Patch", "/v1/domains/example.net/records", []gdRecordField{ { - Name: "", + Name: "@", Type: "A", TTL: 10, Data: "203.0.113.42", @@ -550,7 +550,7 @@ func TestGoDaddyApplyChanges(t *testing.T) { func TestGoDaddyChange(t *testing.T) { assert := assert.New(t) - client := new(mockGoDaddyClient) + client := newMockGoDaddyClient(t) provider := &GDProvider{ client: client, } From 7ccc70b12f71b127e181f990ad0aab6836648ffe Mon Sep 17 00:00:00 2001 From: fboltz Date: Sun, 17 Jan 2021 17:22:57 +0100 Subject: [PATCH 018/175] Change arguments: Switch to OTE and add TTL --- main.go | 2 +- pkg/apis/externaldns/types.go | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/main.go b/main.go index 9fe13ba78..c56e959a8 100644 --- a/main.go +++ b/main.go @@ -300,7 +300,7 @@ func main() { p, err = scaleway.NewScalewayProvider(ctx, domainFilter, cfg.DryRun) case "godaddy": - p, err = godaddy.NewGoDaddyProvider(ctx, domainFilter, cfg.GoDaddyAPIKey, cfg.GoDaddySecretKey, cfg.GoDaddyProduction, cfg.DryRun) + p, err = godaddy.NewGoDaddyProvider(ctx, domainFilter, cfg.GoDaddyTTL, cfg.GoDaddyAPIKey, cfg.GoDaddySecretKey, cfg.GoDaddyOTE, cfg.DryRun) default: log.Fatalf("unknown dns provider: %s", cfg.Provider) } diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index b86c74350..312c95a93 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -148,9 +148,10 @@ type Config struct { TransIPAccountName string TransIPPrivateKeyFile string DigitalOceanAPIPageSize int - GoDaddyAPIKey string + GoDaddyAPIKey string `secure:"yes"` GoDaddySecretKey string `secure:"yes"` - GoDaddyProduction bool + GoDaddyTTL int64 + GoDaddyOTE bool } var defaultConfig = &Config{ @@ -255,7 +256,8 @@ var defaultConfig = &Config{ DigitalOceanAPIPageSize: 50, GoDaddyAPIKey: "", GoDaddySecretKey: "", - GoDaddyProduction: true, + GoDaddyTTL: 600, + GoDaddyOTE: false, } // NewConfig returns new Config object @@ -393,7 +395,8 @@ func (cfg *Config) ParseFlags(args []string) error { // GoDaddy flags app.Flag("godaddy-api-key", "When using the GoDaddy provider, specify the API Key (required when --provider=godaddy)").Default(defaultConfig.GoDaddyAPIKey).StringVar(&cfg.GoDaddyAPIKey) app.Flag("godaddy-api-secret", "When using the GoDaddy provider, specify the API secret (required when --provider=godaddy)").Default(defaultConfig.GoDaddySecretKey).StringVar(&cfg.GoDaddySecretKey) - app.Flag("godaddy-api-production", "When using the GoDaddy provider, specify if production or OTE use (required when --provider=godaddy)").Default(strconv.FormatBool(defaultConfig.GoDaddyProduction)).BoolVar(&cfg.GoDaddyProduction) + app.Flag("godaddy-api-ttl", "TTL (in seconds) for records. This value will be used if the provided TTL for a service/ingress is not provided.").Int64Var(&cfg.GoDaddyTTL) + app.Flag("godaddy-api-ote", "When using the GoDaddy provider, use OTE api (optional, default: false, when --provider=godaddy)").BoolVar(&cfg.GoDaddyOTE) // Flags related to TLS communication app.Flag("tls-ca", "When using TLS communication, the path to the certificate authority to verify server communications (optionally specify --tls-client-cert for two-way TLS)").Default(defaultConfig.TLSCA).StringVar(&cfg.TLSCA) From 0fdd2a8eaf740e7ca60ddadb5a9365b1a329efe2 Mon Sep 17 00:00:00 2001 From: fboltz Date: Sun, 17 Jan 2021 17:25:04 +0100 Subject: [PATCH 019/175] Progress: Debug and make working --- provider/godaddy/godaddy.go | 458 ++++++++++++++++++++----------- provider/godaddy/godaddy_test.go | 366 +++++------------------- 2 files changed, 368 insertions(+), 456 deletions(-) diff --git a/provider/godaddy/godaddy.go b/provider/godaddy/godaddy.go index df8e3f80e..08ae304da 100644 --- a/provider/godaddy/godaddy.go +++ b/provider/godaddy/godaddy.go @@ -31,7 +31,7 @@ import ( ) const ( - gdDefaultTTL = 600 + gdMinimalTTL = 600 gdCreate = iota gdUpdate gdDelete @@ -58,29 +58,31 @@ type GDProvider struct { domainFilter endpoint.DomainFilter client gdClient + ttl int64 DryRun bool } +type gdEndpoint struct { + endpoint *endpoint.Endpoint + action int +} + type gdRecordField struct { - Data string - Name string - Port int - Priority int - Protocol *string - Service *string - TTL int - Type string - Weight int + Data string `json:"data"` + Name string `json:"name"` + TTL int64 `json:"ttl"` + Type string `json:"type"` + Port *int `json:"port,omitempty"` + Priority *int `json:"priority,omitempty"` + Weight *int64 `json:"weight,omitempty"` + Protocol *string `json:"protocol,omitempty"` + Service *string `json:"service,omitempty"` } -type gdRecord struct { - gdRecordField - zone *string -} - -type gdChange struct { - gdRecord - Action int +type gdRecords struct { + records []gdRecordField + changed bool + zone string } type gdZone struct { @@ -101,9 +103,38 @@ type gdZone struct { TransferProtected bool } -// NewGoDaddyProvider initializes a new OVH DNS based Provider. -func NewGoDaddyProvider(ctx context.Context, domainFilter endpoint.DomainFilter, apiKey, apiSecret string, production, dryRun bool) (*GDProvider, error) { - client, err := NewClient(production, apiKey, apiSecret) +type gdZoneIDName map[string]*gdRecords + +func (z gdZoneIDName) add(zoneID string, zoneRecord *gdRecords) { + z[zoneID] = zoneRecord +} + +func (z gdZoneIDName) values() []*gdRecords { + values := make([]*gdRecords, 0, len(z)) + + for _, v := range z { + values = append(values, v) + } + + return values +} + +func (z gdZoneIDName) findZoneRecord(hostname string) (suitableZoneID string, suitableZoneRecord *gdRecords) { + for zoneID, zoneRecord := range z { + if hostname == zoneRecord.zone || strings.HasSuffix(hostname, "."+zoneRecord.zone) { + if suitableZoneRecord == nil || len(zoneRecord.zone) > len(suitableZoneRecord.zone) { + suitableZoneID = zoneID + suitableZoneRecord = zoneRecord + } + } + } + + return +} + +// NewGoDaddyProvider initializes a new GoDaddy DNS based Provider. +func NewGoDaddyProvider(ctx context.Context, domainFilter endpoint.DomainFilter, ttl int64, apiKey, apiSecret string, useOTE, dryRun bool) (*GDProvider, error) { + client, err := NewClient(useOTE, apiKey, apiSecret) if err != nil { return nil, err @@ -117,6 +148,7 @@ func NewGoDaddyProvider(ctx context.Context, domainFilter endpoint.DomainFilter, return &GDProvider{ client: client, domainFilter: domainFilter, + ttl: maxOf(gdMinimalTTL, ttl), DryRun: dryRun, }, nil } @@ -132,6 +164,7 @@ func (p *GDProvider) zones() ([]string, error) { for _, zone := range zones { if p.domainFilter.Match(zone.Domain) { filteredZones = append(filteredZones, zone.Domain) + log.Debugf("GoDaddy: %s zone found", zone.Domain) } } @@ -140,103 +173,140 @@ func (p *GDProvider) zones() ([]string, error) { return filteredZones, nil } -func (p *GDProvider) zonesRecords(ctx context.Context) ([]string, []gdRecord, error) { - var allRecords []gdRecord +func (p *GDProvider) zonesRecords(ctx context.Context, all bool) ([]string, []gdRecords, error) { + var allRecords []gdRecords zones, err := p.zones() if err != nil { return nil, nil, err } - chRecords := make(chan []gdRecord, len(zones)) + if len(zones) == 0 { + allRecords = []gdRecords{} + } else if len(zones) == 1 { + record, err := p.records(&ctx, zones[0], all) - eg, ctx := errgroup.WithContext(ctx) + if err != nil { + return nil, nil, err + } - for _, zone := range zones { - zone := zone - eg.Go(func() error { - return p.records(&ctx, &zone, chRecords) - }) - } + allRecords = append(allRecords, *record) + } else { + chRecords := make(chan gdRecords, len(zones)) - if err := eg.Wait(); err != nil { - return nil, nil, err - } + eg, ctx := errgroup.WithContext(ctx) - close(chRecords) + for _, zoneName := range zones { + zone := zoneName + eg.Go(func() error { + record, err := p.records(&ctx, zone, all) - for records := range chRecords { - allRecords = append(allRecords, records...) + if err != nil { + return err + } + + chRecords <- *record + + return nil + }) + } + + if err := eg.Wait(); err != nil { + return nil, nil, err + } + + close(chRecords) + + for records := range chRecords { + allRecords = append(allRecords, records) + } } return zones, allRecords, nil } -func (p *GDProvider) records(ctx *context.Context, zone *string, records chan<- []gdRecord) error { - var recordsIds []gdRecord +func (p *GDProvider) records(ctx *context.Context, zone string, all bool) (*gdRecords, error) { + var recordsIds []gdRecordField - log.Debugf("GoDaddy: Getting records for %s", *zone) + log.Debugf("GoDaddy: Getting records for %s", zone) - if err := p.client.Get(fmt.Sprintf("/v1/domains/%s/records", *zone), &recordsIds); err != nil { - return err + if err := p.client.Get(fmt.Sprintf("/v1/domains/%s/records", zone), &recordsIds); err != nil { + return nil, err } - results := make([]gdRecord, 0, len(recordsIds)) + if all { + return &gdRecords{ + zone: zone, + records: recordsIds, + }, nil + } + + results := &gdRecords{ + zone: zone, + records: make([]gdRecordField, 0, len(recordsIds)), + } for _, rec := range recordsIds { if provider.SupportedRecordType(rec.Type) { - log.Debugf("GoDaddy: Record %s for %s is %+v", rec.Name, *zone, rec) + log.Debugf("GoDaddy: Record %s for %s is %+v", rec.Name, zone, rec) - rec.zone = zone - results = append(results, rec) + results.records = append(results.records, rec) + } else { + log.Infof("GoDaddy: Discard record %s for %s is %+v", rec.Name, zone, rec) } } - records <- results - - return nil + return results, nil } -func (p *GDProvider) groupByNameAndType(records []gdRecord) []*endpoint.Endpoint { +func (p *GDProvider) groupByNameAndType(zoneRecords []gdRecords) []*endpoint.Endpoint { endpoints := []*endpoint.Endpoint{} // group supported records by name and type - groups := map[string][]gdRecord{} + groupsByZone := map[string]map[string][]gdRecordField{} - for _, r := range records { - groupBy := fmt.Sprintf("%s - %s.%s", r.Type, r.Name, *r.zone) + for _, zone := range zoneRecords { + groups := map[string][]gdRecordField{} - if _, ok := groups[groupBy]; !ok { - groups[groupBy] = []gdRecord{} + groupsByZone[zone.zone] = groups + + for _, r := range zone.records { + groupBy := fmt.Sprintf("%s - %s", r.Type, r.Name) + + if _, ok := groups[groupBy]; !ok { + groups[groupBy] = []gdRecordField{} + } + + groups[groupBy] = append(groups[groupBy], r) } - - groups[groupBy] = append(groups[groupBy], r) } // create single endpoint with all the targets for each name/type - for _, records := range groups { - targets := []string{} + for zoneName, groups := range groupsByZone { + for _, records := range groups { + targets := []string{} - for _, record := range records { - targets = append(targets, record.Data) + for _, record := range records { + targets = append(targets, record.Data) + } + + var recordName string + + if records[0].Name == "@" { + recordName = strings.TrimPrefix(zoneName, ".") + } else { + recordName = strings.TrimPrefix(fmt.Sprintf("%s.%s", records[0].Name, zoneName), ".") + } + + endpoint := endpoint.NewEndpointWithTTL( + recordName, + records[0].Type, + endpoint.TTL(records[0].TTL), + targets..., + ) + + endpoints = append(endpoints, endpoint) } - - var recordName string - - if records[0].Name == "@" { - recordName = strings.TrimPrefix(*records[0].zone, ".") - } else { - recordName = strings.TrimPrefix(fmt.Sprintf("%s.%s", records[0].Name, *records[0].zone), ".") - } - - endpoint := endpoint.NewEndpointWithTTL( - recordName, - records[0].Type, - endpoint.TTL(records[0].TTL), - targets..., - ) - - endpoints = append(endpoints, endpoint) } return endpoints @@ -244,7 +314,7 @@ func (p *GDProvider) groupByNameAndType(records []gdRecord) []*endpoint.Endpoint // Records returns the list of records in all relevant zones. func (p *GDProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error) { - _, records, err := p.zonesRecords(ctx) + _, records, err := p.zonesRecords(ctx, false) if err != nil { return nil, err @@ -257,112 +327,194 @@ func (p *GDProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error) return endpoints, nil } -func (p *GDProvider) change(change gdChange) error { - switch change.Action { - case gdCreate: - log.Debugf("GoDaddy: Add an entry to %s", change.String()) - return p.client.Patch(fmt.Sprintf("/v1/domains/%s/records", *change.zone), []gdRecordField{change.gdRecord.gdRecordField}, nil) - case gdUpdate: - log.Debugf("GoDaddy: Update an entry to %s", change.String()) - return p.client.Put(fmt.Sprintf("/v1/domains/%s/records/%s/%s", *change.zone, change.Type, change.Name), []gdRecordField{change.gdRecord.gdRecordField}, nil) - case gdDelete: - log.Debugf("GoDaddy: Delete an entry to %s", change.String()) - return p.client.Delete(fmt.Sprintf("/v1/domains/%s/records/%s/%s", *change.zone, change.Type, change.Name), nil) +func (p *GDProvider) flushRecords(patch bool, zoneRecord *gdRecords) error { + if patch { + return p.client.Patch(fmt.Sprintf("/v1/domains/%s/records", zoneRecord.zone), zoneRecord.records, nil) } + + return p.client.Put(fmt.Sprintf("/v1/domains/%s/records", zoneRecord.zone), zoneRecord.records, nil) +} + +func (p *GDProvider) appendChange(action int, endpoints []*endpoint.Endpoint, allChanges []gdEndpoint) []gdEndpoint { + for _, e := range endpoints { + allChanges = append(allChanges, gdEndpoint{ + action: action, + endpoint: e, + }) + } + + return allChanges +} + +func (p *GDProvider) changeAllRecords(patch bool, endpoints []gdEndpoint, zoneRecords []*gdRecords) error { + zoneNameIDMapper := gdZoneIDName{} + + for _, zoneRecord := range zoneRecords { + if patch { + zoneRecord.changed = false + zoneRecord.records = nil + } + + zoneNameIDMapper.add(zoneRecord.zone, zoneRecord) + } + + for _, e := range endpoints { + dnsName := e.endpoint.DNSName + zone, zoneRecord := zoneNameIDMapper.findZoneRecord(dnsName) + + if zone == "" { + log.Debugf("Skipping record %s because no hosted zone matching record DNS Name was detected", dnsName) + } else { + dnsName = strings.TrimSuffix(dnsName, "."+zone) + + if e.endpoint.RecordType == endpoint.RecordTypeA && (len(dnsName) == 0) { + dnsName = "@" + } + + for _, target := range e.endpoint.Targets { + + change := gdRecordField{ + Type: e.endpoint.RecordType, + Name: dnsName, + TTL: p.ttl, + Data: target, + } + + if e.endpoint.RecordTTL.IsConfigured() { + change.TTL = maxOf(gdMinimalTTL, int64(e.endpoint.RecordTTL)) + } + + zoneRecord.applyChange(e.action, change) + } + } + } + return nil } // ApplyChanges applies a given set of changes in a given zone. func (p *GDProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error { - zones, records, err := p.zonesRecords(ctx) + + if countTargets(changes) == 0 { + return nil + } + + _, records, err := p.zonesRecords(ctx, true) if err != nil { return err } - allChanges := make([]gdChange, 0, countTargets(changes.Create, changes.UpdateNew, changes.UpdateOld, changes.Delete)) + changedZoneRecords := make([]*gdRecords, len(records)) - allChanges = append(allChanges, newGoDaddyChange(gdCreate, changes.Create, zones, records)...) - allChanges = append(allChanges, newGoDaddyChange(gdCreate, changes.UpdateNew, zones, records)...) + for i := range records { + changedZoneRecords[i] = &records[i] + } - allChanges = append(allChanges, newGoDaddyChange(gdDelete, changes.UpdateOld, zones, records)...) - allChanges = append(allChanges, newGoDaddyChange(gdDelete, changes.Delete, zones, records)...) + allChanges := make([]gdEndpoint, 0, countTargets(changes)) + + allChanges = p.appendChange(gdCreate, changes.Create, allChanges) + allChanges = p.appendChange(gdCreate, changes.UpdateNew, allChanges) + allChanges = p.appendChange(gdDelete, changes.UpdateOld, allChanges) + allChanges = p.appendChange(gdDelete, changes.Delete, allChanges) log.Infof("GoDaddy: %d changes will be done", len(allChanges)) - for _, change := range allChanges { - if err = p.change(change); err != nil { - return err + patch := len(changes.UpdateOld)+len(changes.Delete) == 0 + + if err = p.changeAllRecords(patch, allChanges, changedZoneRecords); err != nil { + return err + } + + for _, record := range changedZoneRecords { + if record.changed { + if err = p.flushRecords(patch, record); err != nil { + return err + } } } return nil } -func countTargets(allEndpoints ...[]*endpoint.Endpoint) int { +func (p *gdRecords) addRecord(change gdRecordField) { + log.Debugf("GoDaddy: Add an entry %s to zone %s", change.String(), p.zone) + + p.records = append(p.records, change) + p.changed = true +} + +func (p *gdRecords) updateRecord(change gdRecordField) { + log.Debugf("GoDaddy: Update an entry %s to zone %s", change.String(), p.zone) + + for index, record := range p.records { + if record.Type == change.Type && record.Name == change.Name { + p.records[index] = change + p.changed = true + break + } + } +} + +// Remove one record from the record list +func (p *gdRecords) deleteRecord(change gdRecordField) { + log.Debugf("GoDaddy: Delete an entry %s to zone %s", change.String(), p.zone) + + deleteIndex := -1 + + for index, record := range p.records { + if record.Type == change.Type && record.Name == change.Name && record.Data == change.Data { + deleteIndex = index + break + } + } + + if deleteIndex >= 0 { + p.records[deleteIndex] = p.records[len(p.records)-1] + + p.records = p.records[:len(p.records)-1] + p.changed = true + } else { + log.Warnf("GoDaddy: record in zone %s not found %s to delete", p.zone, change.String()) + } +} + +func (p *gdRecords) applyChange(action int, change gdRecordField) { + switch action { + case gdCreate: + p.addRecord(change) + case gdUpdate: + p.updateRecord(change) + case gdDelete: + p.deleteRecord(change) + } +} + +func (c gdRecordField) String() string { + return fmt.Sprintf("%s %d IN %s %s", c.Name, c.TTL, c.Type, c.Data) +} + +func countTargets(p *plan.Changes) int { + changes := [][]*endpoint.Endpoint{p.Create, p.UpdateNew, p.UpdateOld, p.Delete} count := 0 - for _, endpoints := range allEndpoints { + + for _, endpoints := range changes { for _, endpoint := range endpoints { count += len(endpoint.Targets) } } + return count } -func newGoDaddyChange(action int, endpoints []*endpoint.Endpoint, zones []string, records []gdRecord) []gdChange { - gdChanges := make([]gdChange, 0, countTargets(endpoints)) - zoneNameIDMapper := provider.ZoneIDName{} +func maxOf(vars ...int64) int64 { + max := vars[0] - for _, zone := range zones { - zoneNameIDMapper.Add(zone, zone) - } - - for _, e := range endpoints { - zone, _ := zoneNameIDMapper.FindZone(e.DNSName) - - if zone == "" { - log.Debugf("Skipping record %s because no hosted zone matching record DNS Name was detected", e.DNSName) - continue - } - - dnsName := strings.TrimSuffix(e.DNSName, "."+zone) - - if e.RecordType == endpoint.RecordTypeA && (len(dnsName) == 0) { - dnsName = "@" - } - - for _, target := range e.Targets { - - if e.RecordType == endpoint.RecordTypeCNAME { - target = target + "." - } else if e.RecordType == endpoint.RecordTypeA && (len(dnsName) == 0 || dnsName == ".") { - dnsName = "@" - } - - change := gdChange{ - Action: action, - gdRecord: gdRecord{ - zone: &zone, - gdRecordField: gdRecordField{ - Type: e.RecordType, - Name: dnsName, - TTL: gdDefaultTTL, - Data: target, - }, - }, - } - - if e.RecordTTL.IsConfigured() { - change.TTL = int(e.RecordTTL) - } - - gdChanges = append(gdChanges, change) + for _, i := range vars { + if max < i { + max = i } } - return gdChanges -} - -func (c *gdChange) String() string { - return fmt.Sprintf("%s zone : %s %d IN %s %s", *c.zone, c.Name, c.TTL, c.Type, c.Data) + return max } diff --git a/provider/godaddy/godaddy_test.go b/provider/godaddy/godaddy_test.go index 886d0c622..5cbd34416 100644 --- a/provider/godaddy/godaddy_test.go +++ b/provider/godaddy/godaddy_test.go @@ -22,7 +22,6 @@ import ( "sort" "testing" - "github.com/ovh/go-ovh/ovh" log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -134,28 +133,22 @@ func TestGoDaddyZoneRecords(t *testing.T) { }, }, nil).Once() - client.On("Get", "/v1/domains/example.net/records").Return([]gdRecord{ + client.On("Get", "/v1/domains/example.net/records").Return([]gdRecordField{ { - zone: &zoneNameExampleNet, - gdRecordField: gdRecordField{ - Name: "godaddy", - Type: "NS", - TTL: 10, - Data: "203.0.113.42", - }, + Name: "godaddy", + Type: "NS", + TTL: 10, + Data: "203.0.113.42", }, { - zone: &zoneNameExampleNet, - gdRecordField: gdRecordField{ - Name: "godaddy", - Type: "A", - TTL: 10, - Data: "203.0.113.42", - }, + Name: "godaddy", + Type: "A", + TTL: 10, + Data: "203.0.113.42", }, }, nil).Once() - zones, records, err := provider.zonesRecords(context.TODO()) + zones, records, err := provider.zonesRecords(context.TODO(), true) assert.NoError(err) @@ -163,23 +156,22 @@ func TestGoDaddyZoneRecords(t *testing.T) { zoneNameExampleNet, }) - assert.ElementsMatch(records, []gdRecord{ + assert.ElementsMatch(records, []gdRecords{ { - zone: &zoneNameExampleNet, - gdRecordField: gdRecordField{ - Name: "godaddy", - Type: "NS", - TTL: 10, - Data: "203.0.113.42", - }, - }, - { - zone: &zoneNameExampleNet, - gdRecordField: gdRecordField{ - Name: "godaddy", - Type: "A", - TTL: 10, - Data: "203.0.113.42", + zone: zoneNameExampleNet, + records: []gdRecordField{ + { + Name: "godaddy", + Type: "NS", + TTL: 10, + Data: "203.0.113.42", + }, + { + Name: "godaddy", + Type: "A", + TTL: 10, + Data: "203.0.113.42", + }, }, }, }) @@ -188,7 +180,7 @@ func TestGoDaddyZoneRecords(t *testing.T) { // Error on getting zones list client.On("Get", "/v1/domains?statuses=ACTIVE").Return(nil, ErrAPIDown).Once() - zones, records, err = provider.zonesRecords(context.TODO()) + zones, records, err = provider.zonesRecords(context.TODO(), false) assert.Error(err) assert.Nil(zones) assert.Nil(records) @@ -203,7 +195,7 @@ func TestGoDaddyZoneRecords(t *testing.T) { client.On("Get", "/v1/domains/example.net/records").Return(nil, ErrAPIDown).Once() - zones, records, err = provider.zonesRecords(context.TODO()) + zones, records, err = provider.zonesRecords(context.TODO(), false) assert.Error(err) assert.Nil(zones) @@ -219,7 +211,7 @@ func TestGoDaddyZoneRecords(t *testing.T) { client.On("Get", "/v1/domains/example.net/records").Return(nil, ErrAPIDown).Once() - zones, records, err = provider.zonesRecords(context.TODO()) + zones, records, err = provider.zonesRecords(context.TODO(), false) assert.Error(err) assert.Nil(zones) assert.Nil(records) @@ -243,45 +235,33 @@ func TestGoDaddyRecords(t *testing.T) { }, }, nil).Once() - client.On("Get", "/v1/domains/example.org/records").Return([]gdRecord{ + client.On("Get", "/v1/domains/example.org/records").Return([]gdRecordField{ { - zone: &zoneNameExampleOrg, - gdRecordField: gdRecordField{ - Name: "@", - Type: "A", - TTL: 10, - Data: "203.0.113.42", - }, + Name: "@", + Type: "A", + TTL: 10, + Data: "203.0.113.42", }, { - zone: &zoneNameExampleOrg, - gdRecordField: gdRecordField{ - Name: "www", - Type: "CNAME", - TTL: 10, - Data: "example.org", - }, + Name: "www", + Type: "CNAME", + TTL: 10, + Data: "example.org", }, }, nil).Once() - client.On("Get", "/v1/domains/example.net/records").Return([]gdRecord{ + client.On("Get", "/v1/domains/example.net/records").Return([]gdRecordField{ { - zone: &zoneNameExampleNet, - gdRecordField: gdRecordField{ - Name: "godaddy", - Type: "A", - TTL: 10, - Data: "203.0.113.42", - }, + Name: "godaddy", + Type: "A", + TTL: 10, + Data: "203.0.113.42", }, { - zone: &zoneNameExampleNet, - gdRecordField: gdRecordField{ - Name: "godaddy", - Type: "A", - TTL: 10, - Data: "203.0.113.43", - }, + Name: "godaddy", + Type: "A", + TTL: 10, + Data: "203.0.113.43", }, }, nil).Once() @@ -327,129 +307,16 @@ func TestGoDaddyRecords(t *testing.T) { client.AssertExpectations(t) // Error getting zone - client.On("Get", "/v1/domains?statuses=ACTIVE").Return(nil, ovh.ErrAPIDown).Once() + client.On("Get", "/v1/domains?statuses=ACTIVE").Return(nil, ErrAPIDown).Once() endpoints, err = provider.Records(context.TODO()) assert.Error(err) assert.Nil(endpoints) client.AssertExpectations(t) } -func TestGoDaddyNewChange(t *testing.T) { - assert := assert.New(t) - endpoints := []*endpoint.Endpoint{ - { - DNSName: ".example.net", - RecordType: "A", - RecordTTL: 10, Targets: []string{ - "203.0.113.42", - }, - }, - { - DNSName: "godaddy.example.net", - RecordType: "A", - Targets: []string{ - "203.0.113.43", - }, - }, - { - DNSName: "godaddy2.example.net", - RecordType: "CNAME", - Targets: []string{ - "godaddy.example.net", - }, - }, - { - DNSName: "test.example.org", - }, - } - - // Create change - changes := newGoDaddyChange(gdCreate, endpoints, []string{"example.net"}, []gdRecord{}) - - assert.ElementsMatch(changes, []gdChange{ - { - Action: gdCreate, - gdRecord: gdRecord{ - zone: &zoneNameExampleNet, - gdRecordField: gdRecordField{ - Name: "@", - Type: "A", - TTL: 10, - Data: "203.0.113.42", - }, - }, - }, - { - Action: gdCreate, - gdRecord: gdRecord{ - zone: &zoneNameExampleNet, - gdRecordField: gdRecordField{ - Name: "godaddy", - Type: "A", - TTL: gdDefaultTTL, - Data: "203.0.113.43", - }, - }, - }, - { - Action: gdCreate, - gdRecord: gdRecord{ - zone: &zoneNameExampleNet, - gdRecordField: gdRecordField{ - Name: "godaddy2", - Type: "CNAME", - TTL: gdDefaultTTL, - Data: "godaddy.example.net.", - }, - }, - }}) - - // Delete change - endpoints = []*endpoint.Endpoint{ - { - DNSName: "godaddy.example.net", - RecordType: "A", - Targets: []string{ - "203.0.113.42", - }, - }, - } - - records := []gdRecord{ - { - zone: &zoneNameExampleNet, - gdRecordField: gdRecordField{ - Type: "A", - Name: "godaddy", - Data: "203.0.113.42", - }, - }, - } - - changes = newGoDaddyChange(gdDelete, endpoints, []string{ - zoneNameExampleNet, - }, records) - - assert.ElementsMatch(changes, []gdChange{ - { - Action: gdDelete, - gdRecord: gdRecord{ - zone: &zoneNameExampleNet, - gdRecordField: gdRecordField{ - Name: "godaddy", - Type: "A", - TTL: gdDefaultTTL, - Data: "203.0.113.42", - }, - }, - }, - }) -} - -func TestGoDaddyApplyChanges(t *testing.T) { +func TestGoDaddyChange(t *testing.T) { assert := assert.New(t) client := newMockGoDaddyClient(t) - provider := &GDProvider{ client: client, } @@ -475,142 +342,35 @@ func TestGoDaddyApplyChanges(t *testing.T) { }, }, } + + // Fetch domains client.On("Get", "/v1/domains?statuses=ACTIVE").Return([]gdZone{ { Domain: zoneNameExampleNet, }, }, nil).Once() - client.On("Get", "/v1/domains/example.net/records").Return([]gdRecord{ - { - zone: &zoneNameExampleNet, - gdRecordField: gdRecordField{ - Name: "godaddy", - Type: "A", - TTL: 10, - Data: "203.0.113.43", - }, - }, - }, nil).Once() - - client.On("Patch", "/v1/domains/example.net/records", []gdRecordField{ - { - Name: "@", - Type: "A", - TTL: 10, - Data: "203.0.113.42", - }, - }).Return(nil, nil).Once() - - client.On("Delete", "/v1/domains/example.net/records/A/godaddy").Return(nil, nil).Once() - - // Basic changes - assert.NoError(provider.ApplyChanges(context.TODO(), &changes)) - - client.AssertExpectations(t) - - // Getting zones failed - client.On("Get", "/v1/domains?statuses=ACTIVE").Return(nil, ErrAPIDown).Once() - assert.Error(provider.ApplyChanges(context.TODO(), &changes)) - client.AssertExpectations(t) - - // Apply change failed - client.On("Get", "/v1/domains?statuses=ACTIVE").Return([]gdZone{ - { - Domain: zoneNameExampleNet, - }, - }, nil).Once() - - client.On("Get", "/v1/domains/example.net/records").Return([]gdRecord{}, nil).Once() - - client.On("Patch", "/v1/domains/example.net/records", []gdRecordField{ - { - Name: "@", - Type: "A", - TTL: 10, - Data: "203.0.113.42", - }, - }).Return(nil, ErrAPIDown).Once() - - assert.Error(provider.ApplyChanges(context.TODO(), &plan.Changes{ - Create: []*endpoint.Endpoint{ - { - DNSName: ".example.net", - RecordType: "A", - RecordTTL: 10, - Targets: []string{ - "203.0.113.42", - }, - }, - }, - })) - - client.AssertExpectations(t) -} - -func TestGoDaddyChange(t *testing.T) { - assert := assert.New(t) - client := newMockGoDaddyClient(t) - provider := &GDProvider{ - client: client, - } - - // Record creation - client.On("Patch", "/v1/domains/example.net/records", []gdRecordField{ + // Fetch record + client.On("Get", "/v1/domains/example.net/records").Return([]gdRecordField{ { Name: "godaddy", Type: "A", TTL: 10, + Data: "203.0.113.43", + }, + }, nil).Once() + + // Update domain + client.On("Put", "/v1/domains/example.net/records", []gdRecordField{ + { + Name: "@", + Type: "A", + TTL: 10, Data: "203.0.113.42", }, }).Return(nil, nil).Once() - assert.NoError(provider.change(gdChange{ - Action: gdCreate, - gdRecord: gdRecord{ - zone: &zoneNameExampleNet, - gdRecordField: gdRecordField{ - Name: "godaddy", - Type: "A", - TTL: 10, - Data: "203.0.113.42", - }, - }, - })) - - client.AssertExpectations(t) - - // Record deletion - client.On("Delete", "/v1/domains/example.net/records/A/godaddy").Return(nil, nil).Once() - - assert.NoError(provider.change(gdChange{ - Action: gdDelete, - gdRecord: gdRecord{ - zone: &zoneNameExampleNet, - gdRecordField: gdRecordField{ - Name: "godaddy", - Type: "A", - }, - }, - })) + assert.NoError(provider.ApplyChanges(context.TODO(), &changes)) client.AssertExpectations(t) } - -func TestOGoDaddyCountTargets(t *testing.T) { - cases := []struct { - endpoints [][]*endpoint.Endpoint - count int - }{ - {[][]*endpoint.Endpoint{{{DNSName: "godaddy.example.net", Targets: endpoint.Targets{"target"}}}}, 1}, - {[][]*endpoint.Endpoint{{{DNSName: "godaddy.example.net", Targets: endpoint.Targets{"target"}}, {DNSName: "godaddy.example.net", Targets: endpoint.Targets{"target"}}}}, 2}, - {[][]*endpoint.Endpoint{{{DNSName: "godaddy.example.net", Targets: endpoint.Targets{"target", "target", "target"}}}}, 3}, - {[][]*endpoint.Endpoint{{{DNSName: "godaddy.example.net", Targets: endpoint.Targets{"target", "target"}}}, {{DNSName: "godaddy.example.net", Targets: endpoint.Targets{"target", "target"}}}}, 4}, - } - for _, test := range cases { - count := countTargets(test.endpoints...) - if count != test.count { - t.Errorf("Wrong targets counts (Should be %d, get %d)", test.count, count) - } - } -} From d8a0bc4dc9d8b11e97b90cc8591c8f8bb5e6ca15 Mon Sep 17 00:00:00 2001 From: fboltz Date: Sun, 17 Jan 2021 17:25:33 +0100 Subject: [PATCH 020/175] Change arguments: OTE --- provider/godaddy/client.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/provider/godaddy/client.go b/provider/godaddy/client.go index 440c3ad27..6a0326f8b 100644 --- a/provider/godaddy/client.go +++ b/provider/godaddy/client.go @@ -77,13 +77,13 @@ type Client struct { } // NewClient represents a new client to call the API -func NewClient(production bool, apiKey, apiSecret string) (*Client, error) { +func NewClient(useOTE bool, apiKey, apiSecret string) (*Client, error) { var endpoint string - if production { - endpoint = "https://api.godaddy.com" - } else { + if useOTE { endpoint = " https://api.ote-godaddy.com" + } else { + endpoint = "https://api.godaddy.com" } client := Client{ From 9aa6fb291f45e5d317595c56e5356100ce4eaf02 Mon Sep 17 00:00:00 2001 From: fboltz Date: Sun, 17 Jan 2021 17:26:07 +0100 Subject: [PATCH 021/175] Update README --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index d24bb47ed..8486d4603 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ ExternalDNS' current release is `v0.7`. This version allows you to keep selected * [Vultr](https://www.vultr.com) * [OVH](https://www.ovh.com) * [Scaleway](https://www.scaleway.com) +* [GoDaddy](https://www.godaddy.com) From this release, ExternalDNS can become aware of the records it is managing (enabled via `--registry=txt`), therefore ExternalDNS can safely manage non-empty hosted zones. We strongly encourage you to use `v0.5` (or greater) with `--registry=txt` enabled and `--txt-owner-id` set to a unique value that doesn't change for the lifetime of your cluster. You might also want to run ExternalDNS in a dry run mode (`--dry-run` flag) to see the changes to be submitted to your DNS Provider API. @@ -102,6 +103,7 @@ The following table clarifies the current status of the providers according to t | Scaleway DNS | Alpha | @Sh4d1 | | Vultr | Alpha | | | UltraDNS | Alpha | | +| GoDaddy | Alpha | | ## Running ExternalDNS: @@ -154,6 +156,7 @@ The following tutorials are provided: * [Scaleway](docs/tutorials/scaleway.md) * [Vultr](docs/tutorials/vultr.md) * [UltraDNS](docs/tutorials/ultradns.md) +* [GoDaddy](docs/tutorials/godaddy.md) ### Running Locally From 2b113c25fa159452385598b725efa83e73ae3b51 Mon Sep 17 00:00:00 2001 From: fboltz Date: Sun, 17 Jan 2021 17:26:31 +0100 Subject: [PATCH 022/175] Add tutorial --- docs/tutorials/godaddy.md | 197 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 docs/tutorials/godaddy.md diff --git a/docs/tutorials/godaddy.md b/docs/tutorials/godaddy.md new file mode 100644 index 000000000..782ac4dd0 --- /dev/null +++ b/docs/tutorials/godaddy.md @@ -0,0 +1,197 @@ +# Setting up ExternalDNS for Services on GoDaddy + +This tutorial describes how to setup ExternalDNS for use within a +Kubernetes cluster using GoDaddy DNS. + +Make sure to use **>=0.6** version of ExternalDNS for this tutorial. + +## Creating a zone with GoDaddy DNS + +If you are new to GoDaddy, we recommend you first read the following +instructions for creating a zone. + +[Creating a zone using the GoDaddy web console](https://www.godaddy.com/) + +[Creating a zone using the GoDaddy API](https://developer.godaddy.com/) + +## Creating GoDaddy API key + +You first need to create an API Key. + +Using the [GoDaddy documentation](https://developer.godaddy.com/getstarted) you will have your `API key` and `API secret` + +## Deploy ExternalDNS + +Connect your `kubectl` client to the cluster with which you want to test ExternalDNS, and then apply one of the following manifest files for deployment: + +### Manifest (for clusters without RBAC enabled) + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: external-dns +spec: + strategy: + type: Recreate + selector: + matchLabels: + app: external-dns + template: + metadata: + labels: + app: external-dns + spec: + containers: + - name: external-dns + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 + args: + - --source=service # ingress is also possible + - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. + - --provider=godaddy + - --txt-prefix=external-dns. # In case of multiple k8s cluster + - --txt-owner-id=owner-id # In case of multiple k8s cluster + - --godaddy-api-key= + - --godaddy-api-secret= +``` + +### Manifest (for clusters with RBAC enabled) + +```yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: external-dns +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: external-dns +rules: +- apiGroups: [""] + resources: ["services"] + verbs: ["get","watch","list"] +- apiGroups: [""] + resources: ["pods"] + verbs: ["get","watch","list"] +- apiGroups: ["extensions","networking.k8s.io"] + resources: ["ingresses"] + verbs: ["get","watch","list"] +- apiGroups: [""] + resources: ["nodes"] + verbs: ["list"] +- apiGroups: [""] + resources: ["endpoints"] + verbs: ["get","watch","list"] +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: external-dns-viewer +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: external-dns +subjects: +- kind: ServiceAccount + name: external-dns + namespace: default +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: external-dns +spec: + strategy: + type: Recreate + selector: + matchLabels: + app: external-dns + template: + metadata: + labels: + app: external-dns + spec: + serviceAccountName: external-dns + containers: + - name: external-dns + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 + args: + - --source=service # ingress is also possible + - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. + - --provider=godaddy + - --txt-prefix=external-dns. # In case of multiple k8s cluster + - --txt-owner-id=owner-id # In case of multiple k8s cluster + - --godaddy-api-key= + - --godaddy-api-secret= +``` + +## Deploying an Nginx Service + +Create a service file called 'nginx.yaml' with the following contents: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx + name: nginx + ports: + - containerPort: 80 +--- +apiVersion: v1 +kind: Service +metadata: + name: nginx + annotations: + external-dns.alpha.kubernetes.io/hostname: example.com + external-dns.alpha.kubernetes.io/ttl: "120" #optional +spec: + selector: + app: nginx + type: LoadBalancer + ports: + - protocol: TCP + port: 80 + targetPort: 80 +``` + +**A note about annotations** + +Verify that the annotation on the service uses the same hostname as the GoDaddy DNS zone created above. The annotation may also be a subdomain of the DNS zone (e.g. 'www.example.com'). + +The TTL annotation can be used to configure the TTL on DNS records managed by ExternalDNS and is optional. If this annotation is not set, the TTL on records managed by ExternalDNS will default to 10. + +ExternalDNS uses the hostname annotation to determine which services should be registered with DNS. Removing the hostname annotation will cause ExternalDNS to remove the corresponding DNS records. + +### Create the deployment and service + +``` +$ kubectl create -f nginx.yaml +``` + +Depending on where you run your service, it may take some time for your cloud provider to create an external IP for the service. Once an external IP is assigned, ExternalDNS detects the new service IP address and synchronizes the GoDaddy DNS records. + +## Verifying GoDaddy DNS records + +Use the GoDaddy web console or API to verify that the A record for your domain shows the external IP address of the services. + +## Cleanup + +Once you successfully configure and verify record management via ExternalDNS, you can delete the tutorial's example: + +``` +$ kubectl delete -f nginx.yaml +$ kubectl delete -f externaldns.yaml +``` From 2e3138e1322cd56ddf8dfb468def197c4fc33642 Mon Sep 17 00:00:00 2001 From: fboltz Date: Sun, 17 Jan 2021 17:26:46 +0100 Subject: [PATCH 023/175] Typo --- provider/godaddy/client.go | 1 + 1 file changed, 1 insertion(+) diff --git a/provider/godaddy/client.go b/provider/godaddy/client.go index 6a0326f8b..b4ca89c22 100644 --- a/provider/godaddy/client.go +++ b/provider/godaddy/client.go @@ -13,6 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ + package godaddy import ( From 66dcd89e666525cf64fdbcddbd003d9929f15535 Mon Sep 17 00:00:00 2001 From: fboltz Date: Sun, 17 Jan 2021 17:27:01 +0100 Subject: [PATCH 024/175] Typo: Change message --- provider/godaddy/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/provider/godaddy/client.go b/provider/godaddy/client.go index b4ca89c22..ffed0ed2c 100644 --- a/provider/godaddy/client.go +++ b/provider/godaddy/client.go @@ -34,7 +34,7 @@ const DefaultTimeout = 180 * time.Second // Errors var ( - ErrAPIDown = errors.New("go-vh: the GoDaddy API is down, it does't respond to /time anymore") + ErrAPIDown = errors.New("godaddy: the GoDaddy API is down") ) // APIError error From 4509f727cdd97989d1674bc549d4e0179feede35 Mon Sep 17 00:00:00 2001 From: fboltz Date: Sun, 17 Jan 2021 17:53:25 +0100 Subject: [PATCH 025/175] FIX: Set TTL value --- provider/godaddy/godaddy_test.go | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/provider/godaddy/godaddy_test.go b/provider/godaddy/godaddy_test.go index 5cbd34416..2e9b07342 100644 --- a/provider/godaddy/godaddy_test.go +++ b/provider/godaddy/godaddy_test.go @@ -137,13 +137,13 @@ func TestGoDaddyZoneRecords(t *testing.T) { { Name: "godaddy", Type: "NS", - TTL: 10, + TTL: gdMinimalTTL, Data: "203.0.113.42", }, { Name: "godaddy", Type: "A", - TTL: 10, + TTL: gdMinimalTTL, Data: "203.0.113.42", }, }, nil).Once() @@ -163,13 +163,13 @@ func TestGoDaddyZoneRecords(t *testing.T) { { Name: "godaddy", Type: "NS", - TTL: 10, + TTL: gdMinimalTTL, Data: "203.0.113.42", }, { Name: "godaddy", Type: "A", - TTL: 10, + TTL: gdMinimalTTL, Data: "203.0.113.42", }, }, @@ -239,13 +239,13 @@ func TestGoDaddyRecords(t *testing.T) { { Name: "@", Type: "A", - TTL: 10, + TTL: gdMinimalTTL, Data: "203.0.113.42", }, { Name: "www", Type: "CNAME", - TTL: 10, + TTL: gdMinimalTTL, Data: "example.org", }, }, nil).Once() @@ -254,13 +254,13 @@ func TestGoDaddyRecords(t *testing.T) { { Name: "godaddy", Type: "A", - TTL: 10, + TTL: gdMinimalTTL, Data: "203.0.113.42", }, { Name: "godaddy", Type: "A", - TTL: 10, + TTL: gdMinimalTTL, Data: "203.0.113.43", }, }, nil).Once() @@ -277,7 +277,7 @@ func TestGoDaddyRecords(t *testing.T) { { DNSName: "godaddy.example.net", RecordType: "A", - RecordTTL: 10, + RecordTTL: gdMinimalTTL, Labels: endpoint.NewLabels(), Targets: []string{ "203.0.113.42", @@ -287,7 +287,7 @@ func TestGoDaddyRecords(t *testing.T) { { DNSName: "example.org", RecordType: "A", - RecordTTL: 10, + RecordTTL: gdMinimalTTL, Labels: endpoint.NewLabels(), Targets: []string{ "203.0.113.42", @@ -296,7 +296,7 @@ func TestGoDaddyRecords(t *testing.T) { { DNSName: "www.example.org", RecordType: "CNAME", - RecordTTL: 10, + RecordTTL: gdMinimalTTL, Labels: endpoint.NewLabels(), Targets: []string{ "example.org", @@ -326,7 +326,7 @@ func TestGoDaddyChange(t *testing.T) { { DNSName: ".example.net", RecordType: "A", - RecordTTL: 10, + RecordTTL: gdMinimalTTL, Targets: []string{ "203.0.113.42", }, @@ -355,7 +355,7 @@ func TestGoDaddyChange(t *testing.T) { { Name: "godaddy", Type: "A", - TTL: 10, + TTL: gdMinimalTTL, Data: "203.0.113.43", }, }, nil).Once() @@ -365,7 +365,7 @@ func TestGoDaddyChange(t *testing.T) { { Name: "@", Type: "A", - TTL: 10, + TTL: gdMinimalTTL, Data: "203.0.113.42", }, }).Return(nil, nil).Once() From 0805acf594dbcc6cdb0647d7655a7a63a48b4616 Mon Sep 17 00:00:00 2001 From: fboltz Date: Sun, 17 Jan 2021 17:53:34 +0100 Subject: [PATCH 026/175] Update go.mod --- go.mod | 1 + 1 file changed, 1 insertion(+) diff --git a/go.mod b/go.mod index 06b632e7a..5b5206b0d 100644 --- a/go.mod +++ b/go.mod @@ -56,6 +56,7 @@ require ( go.uber.org/ratelimit v0.1.0 golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d + golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e google.golang.org/api v0.15.0 gopkg.in/ns1/ns1-go.v2 v2.0.0-20190322154155-0dafb5275fd1 gopkg.in/yaml.v2 v2.2.8 From 6fdfa0d2774d218c0cd6c90049c6ee5aae9196d1 Mon Sep 17 00:00:00 2001 From: fboltz Date: Sun, 17 Jan 2021 19:28:13 +0100 Subject: [PATCH 027/175] FIX: make golangci-lint happy --- provider/godaddy/godaddy.go | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/provider/godaddy/godaddy.go b/provider/godaddy/godaddy.go index 08ae304da..fcfc5ccce 100644 --- a/provider/godaddy/godaddy.go +++ b/provider/godaddy/godaddy.go @@ -109,16 +109,6 @@ func (z gdZoneIDName) add(zoneID string, zoneRecord *gdRecords) { z[zoneID] = zoneRecord } -func (z gdZoneIDName) values() []*gdRecords { - values := make([]*gdRecords, 0, len(z)) - - for _, v := range z { - values = append(values, v) - } - - return values -} - func (z gdZoneIDName) findZoneRecord(hostname string) (suitableZoneID string, suitableZoneRecord *gdRecords) { for zoneID, zoneRecord := range z { if hostname == zoneRecord.zone || strings.HasSuffix(hostname, "."+zoneRecord.zone) { @@ -372,7 +362,6 @@ func (p *GDProvider) changeAllRecords(patch bool, endpoints []gdEndpoint, zoneRe } for _, target := range e.endpoint.Targets { - change := gdRecordField{ Type: e.endpoint.RecordType, Name: dnsName, @@ -394,7 +383,6 @@ func (p *GDProvider) changeAllRecords(patch bool, endpoints []gdEndpoint, zoneRe // ApplyChanges applies a given set of changes in a given zone. func (p *GDProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error { - if countTargets(changes) == 0 { return nil } From bf6641d9734ea838414056eaa8c5f720295d60e8 Mon Sep 17 00:00:00 2001 From: Frederic BOLTZ Date: Tue, 19 Jan 2021 14:30:34 +0100 Subject: [PATCH 028/175] Update docs/tutorials/godaddy.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nick Jüttner --- docs/tutorials/godaddy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/godaddy.md b/docs/tutorials/godaddy.md index 782ac4dd0..7ce4c4edb 100644 --- a/docs/tutorials/godaddy.md +++ b/docs/tutorials/godaddy.md @@ -79,7 +79,7 @@ rules: verbs: ["get","watch","list"] - apiGroups: [""] resources: ["nodes"] - verbs: ["list"] + verbs: ["list","watch"] - apiGroups: [""] resources: ["endpoints"] verbs: ["get","watch","list"] From 85e048d4c94e2dda0e5c82711ca1781a3cd1bc20 Mon Sep 17 00:00:00 2001 From: Frederic BOLTZ Date: Tue, 19 Jan 2021 14:30:47 +0100 Subject: [PATCH 029/175] Update docs/tutorials/godaddy.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nick Jüttner --- docs/tutorials/godaddy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/godaddy.md b/docs/tutorials/godaddy.md index 7ce4c4edb..daf9a7ad7 100644 --- a/docs/tutorials/godaddy.md +++ b/docs/tutorials/godaddy.md @@ -44,7 +44,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.6 + image: k8s.gcr.io/external-dns/external-dns:v0.7.7 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. From 02acef614d5dd36742f5aa19da39fbb37f1cdc92 Mon Sep 17 00:00:00 2001 From: Frederic BOLTZ Date: Tue, 19 Jan 2021 14:30:57 +0100 Subject: [PATCH 030/175] Update docs/tutorials/godaddy.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nick Jüttner --- docs/tutorials/godaddy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/godaddy.md b/docs/tutorials/godaddy.md index daf9a7ad7..c6d24b46f 100644 --- a/docs/tutorials/godaddy.md +++ b/docs/tutorials/godaddy.md @@ -115,7 +115,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.6 + image: k8s.gcr.io/external-dns/external-dns:v0.7.7 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. From 33e53edcd4cec3b8b679547d969d0b985df4ab91 Mon Sep 17 00:00:00 2001 From: Frederic BOLTZ Date: Tue, 19 Jan 2021 14:31:47 +0100 Subject: [PATCH 031/175] Update main.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nick Jüttner --- main.go | 1 - 1 file changed, 1 deletion(-) diff --git a/main.go b/main.go index c61b28b26..c210a0745 100644 --- a/main.go +++ b/main.go @@ -299,7 +299,6 @@ func main() { p, err = transip.NewTransIPProvider(cfg.TransIPAccountName, cfg.TransIPPrivateKeyFile, domainFilter, cfg.DryRun) case "scaleway": p, err = scaleway.NewScalewayProvider(ctx, domainFilter, cfg.DryRun) - case "godaddy": p, err = godaddy.NewGoDaddyProvider(ctx, domainFilter, cfg.GoDaddyTTL, cfg.GoDaddyAPIKey, cfg.GoDaddySecretKey, cfg.GoDaddyOTE, cfg.DryRun) default: From 6e3c8ef1a4fd274b3c143c4647e0878436a57fa3 Mon Sep 17 00:00:00 2001 From: Frederic BOLTZ Date: Tue, 19 Jan 2021 14:32:05 +0100 Subject: [PATCH 032/175] Update pkg/apis/externaldns/types.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nick Jüttner --- pkg/apis/externaldns/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index b3225965a..f8b791ae8 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -346,7 +346,7 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("managed-record-types", "Comma separated list of record types to manage (default: A, CNAME) (supported records: CNAME, A, NS").Default("A", "CNAME").StringsVar(&cfg.ManagedDNSRecordTypes) // Flags related to providers - app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, aws-sd, google, azure, azure-dns, azure-private-dns, cloudflare, rcodezero, digitalocean, hetzner, dnsimple, akamai, infoblox, dyn, designate, coredns, skydns, inmemory, ovh, pdns, oci, exoscale, linode, rfc2136, ns1, transip, vinyldns, rdns, scaleway, vultr, ultradns)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "aws-sd", "google", "azure", "azure-dns", "hetzner", "azure-private-dns", "alibabacloud", "cloudflare", "rcodezero", "digitalocean", "dnsimple", "akamai", "infoblox", "dyn", "designate", "coredns", "skydns", "inmemory", "ovh", "pdns", "oci", "exoscale", "linode", "rfc2136", "ns1", "transip", "vinyldns", "rdns", "scaleway", "vultr", "ultradns", "godaddy") + app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, aws-sd, godaddy, google, azure, azure-dns, azure-private-dns, cloudflare, rcodezero, digitalocean, hetzner, dnsimple, akamai, infoblox, dyn, designate, coredns, skydns, inmemory, ovh, pdns, oci, exoscale, linode, rfc2136, ns1, transip, vinyldns, rdns, scaleway, vultr, ultradns)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "aws-sd", "google", "azure", "azure-dns", "hetzner", "azure-private-dns", "alibabacloud", "cloudflare", "rcodezero", "digitalocean", "dnsimple", "akamai", "infoblox", "dyn", "designate", "coredns", "skydns", "inmemory", "ovh", "pdns", "oci", "exoscale", "linode", "rfc2136", "ns1", "transip", "vinyldns", "rdns", "scaleway", "vultr", "ultradns", "godaddy") app.Flag("domain-filter", "Limit possible target zones by a domain suffix; specify multiple times for multiple domains (optional)").Default("").StringsVar(&cfg.DomainFilter) app.Flag("exclude-domains", "Exclude subdomains (optional)").Default("").StringsVar(&cfg.ExcludeDomains) app.Flag("zone-name-filter", "Filter target zones by zone domain (For now, only AzureDNS provider is using this flag); specify multiple times for multiple zones (optional)").Default("").StringsVar(&cfg.ZoneNameFilter) From db648acfd3e5caeed9409adc07fe54058072e2b4 Mon Sep 17 00:00:00 2001 From: Frederic BOLTZ Date: Tue, 19 Jan 2021 14:32:20 +0100 Subject: [PATCH 033/175] Update pkg/apis/externaldns/types.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nick Jüttner --- pkg/apis/externaldns/types.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index f8b791ae8..c835e667e 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -402,7 +402,6 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("ns1-ignoressl", "When using the NS1 provider, specify whether to verify the SSL certificate (default: false)").Default(strconv.FormatBool(defaultConfig.NS1IgnoreSSL)).BoolVar(&cfg.NS1IgnoreSSL) app.Flag("ns1-min-ttl", "Minimal TTL (in seconds) for records. This value will be used if the provided TTL for a service/ingress is lower than this.").IntVar(&cfg.NS1MinTTLSeconds) app.Flag("digitalocean-api-page-size", "Configure the page size used when querying the DigitalOcean API.").Default(strconv.Itoa(defaultConfig.DigitalOceanAPIPageSize)).IntVar(&cfg.DigitalOceanAPIPageSize) - // GoDaddy flags app.Flag("godaddy-api-key", "When using the GoDaddy provider, specify the API Key (required when --provider=godaddy)").Default(defaultConfig.GoDaddyAPIKey).StringVar(&cfg.GoDaddyAPIKey) app.Flag("godaddy-api-secret", "When using the GoDaddy provider, specify the API secret (required when --provider=godaddy)").Default(defaultConfig.GoDaddySecretKey).StringVar(&cfg.GoDaddySecretKey) From b65b945e27050ced09a21ddf27a4b88806b708bb Mon Sep 17 00:00:00 2001 From: Raffaele Di Fazio Date: Thu, 28 Jan 2021 09:17:37 +0100 Subject: [PATCH 034/175] corrects broken links in alb-ingress tutorial --- docs/tutorials/alb-ingress.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/tutorials/alb-ingress.md b/docs/tutorials/alb-ingress.md index 08c40c3bb..eb7a19139 100644 --- a/docs/tutorials/alb-ingress.md +++ b/docs/tutorials/alb-ingress.md @@ -2,7 +2,7 @@ This tutorial describes how to use ExternalDNS with the [aws-alb-ingress-controller][1]. -[1]: https://kubernetes-sigs.github.io/aws-alb-ingress-controller/ +[1]: https://kubernetes-sigs.github.io/aws-load-balancer-controller ## Setting up ExternalDNS and aws-alb-ingress-controller @@ -14,12 +14,12 @@ this is not required. For help setting up the ALB Ingress Controller, follow the [Setup Guide][2]. -[2]: https://kubernetes-sigs.github.io/aws-alb-ingress-controller/guide/controller/setup/ +[2]: https://kubernetes-sigs.github.io/aws-load-balancer-controller/latest/deploy/installation/ Note that the ALB ingress controller uses the same tags for [subnet auto-discovery][3] as Kubernetes does with the AWS cloud provider. -[3]: https://kubernetes-sigs.github.io/aws-alb-ingress-controller/guide/controller/config/#subnet-auto-discovery +[3]: https://kubernetes-sigs.github.io/aws-load-balancer-controller/latest/deploy/subnet_discovery/ In the examples that follow, it is assumed that you configured the ALB Ingress Controller with the `ingress-class=alb` argument (not to be confused with the From eb7c8491cb701ae6a9cca3befef9978f85b2212a Mon Sep 17 00:00:00 2001 From: Brett Polivka Date: Thu, 4 Feb 2021 20:56:55 +0000 Subject: [PATCH 035/175] remove duplicate endpoints when processing VirtualService --- source/virtualservice.go | 13 ++++++++++++- source/virtualservice_test.go | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/source/virtualservice.go b/source/virtualservice.go index 2f59a0060..d9b720112 100644 --- a/source/virtualservice.go +++ b/source/virtualservice.go @@ -317,6 +317,15 @@ func (sc *virtualServiceSource) setResourceLabel(virtualservice networkingv1alph } } +func appendIfMissing(targets []string, target string) []string { + for _, element := range targets { + if element == target { + return targets + } + } + return append(targets, target) +} + func (sc *virtualServiceSource) targetsFromVirtualService(ctx context.Context, virtualService networkingv1alpha3.VirtualService, vsHost string) ([]string, error) { var targets []string // for each host we need to iterate through the gateways because each host might match for only one of the gateways @@ -332,7 +341,9 @@ func (sc *virtualServiceSource) targetsFromVirtualService(ctx context.Context, v if err != nil { return targets, err } - targets = append(targets, tgs...) + for _, target := range tgs { + targets = appendIfMissing(targets, target) + } } return targets, nil diff --git a/source/virtualservice_test.go b/source/virtualservice_test.go index 88087f0e4..3f8aff4a1 100644 --- a/source/virtualservice_test.go +++ b/source/virtualservice_test.go @@ -618,6 +618,41 @@ func testVirtualServiceEndpoints(t *testing.T) { }, }, }, + { + title: "one virtualservice with two gateways, one ingressgateway loadbalancer service", + lbServices: []fakeIngressGatewayService{ + { + namespace: namespace, + ips: []string{"8.8.8.8"}, + }, + }, + gwConfigs: []fakeGatewayConfig{ + { + name: "gw1", + namespace: namespace, + dnsnames: [][]string{{"*"}}, + }, + { + name: "gw2", + namespace: namespace, + dnsnames: [][]string{{"*"}}, + }, + }, + vsConfigs: []fakeVirtualServiceConfig{ + { + name: "vs", + namespace: namespace, + gateways: []string{"gw1", "gw2"}, + dnsnames: []string{"example.org"}, + }, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "example.org", + Targets: endpoint.Targets{"8.8.8.8"}, + }, + }, + }, { title: "two simple virtualservices on different namespaces with the same target gateway, one ingressgateway loadbalancer service", lbServices: []fakeIngressGatewayService{ From a203da9abf9eb43d3310ce0a02fac096fc21e439 Mon Sep 17 00:00:00 2001 From: Jeff Spahr Date: Sun, 31 Jan 2021 02:33:20 -0500 Subject: [PATCH 036/175] updated docs to reference the v0.7.6 image From eaf933328f4f7ed1db1546145fa81ed5a61cae3b Mon Sep 17 00:00:00 2001 From: Jeff Spahr Date: Thu, 4 Feb 2021 22:29:38 -0500 Subject: [PATCH 037/175] updated docs to reference the v0.7.6 image --- docs/faq.md | 4 ++-- docs/tutorials/alibabacloud.md | 4 ++-- docs/tutorials/aws-sd.md | 4 ++-- docs/tutorials/aws.md | 4 ++-- docs/tutorials/azure-private-dns.md | 6 +++--- docs/tutorials/azure.md | 6 +++--- docs/tutorials/cloudflare.md | 4 ++-- docs/tutorials/contour.md | 4 ++-- docs/tutorials/coredns.md | 4 ++-- docs/tutorials/designate.md | 4 ++-- docs/tutorials/digitalocean.md | 4 ++-- docs/tutorials/dnsimple.md | 4 ++-- docs/tutorials/dyn.md | 2 +- docs/tutorials/exoscale.md | 2 +- docs/tutorials/externalname.md | 2 +- docs/tutorials/gke.md | 4 ++-- docs/tutorials/hetzner.md | 6 +++--- docs/tutorials/hostport.md | 4 ++-- docs/tutorials/infoblox.md | 4 ++-- docs/tutorials/istio.md | 4 ++-- docs/tutorials/kube-ingress-aws.md | 2 +- docs/tutorials/linode.md | 4 ++-- docs/tutorials/nginx-ingress.md | 4 ++-- docs/tutorials/ns1.md | 4 ++-- docs/tutorials/openshift.md | 4 ++-- docs/tutorials/oracle.md | 2 +- docs/tutorials/ovh.md | 4 ++-- docs/tutorials/pdns.md | 2 +- docs/tutorials/public-private-route53.md | 4 ++-- docs/tutorials/rcodezero.md | 4 ++-- docs/tutorials/rdns.md | 4 ++-- docs/tutorials/rfc2136.md | 4 ++-- docs/tutorials/security-context.md | 2 +- docs/tutorials/transip.md | 4 ++-- docs/tutorials/ultradns.md | 4 ++-- docs/tutorials/vinyldns.md | 4 ++-- docs/tutorials/vultr.md | 4 ++-- 37 files changed, 70 insertions(+), 70 deletions(-) diff --git a/docs/faq.md b/docs/faq.md index 20926ffb1..0037e8f9a 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -214,7 +214,7 @@ $ docker run \ -e EXTERNAL_DNS_SOURCE=$'service\ningress' \ -e EXTERNAL_DNS_PROVIDER=google \ -e EXTERNAL_DNS_DOMAIN_FILTER=$'foo.com\nbar.com' \ - k8s.gcr.io/external-dns/external-dns:v0.7.3 + k8s.gcr.io/external-dns/external-dns:v0.7.6 time="2017-08-08T14:10:26Z" level=info msg="config: &{APIServerURL: KubeConfig: Sources:[service ingress] Namespace: ... ``` @@ -302,7 +302,7 @@ When we tag a new release, we push a container image to the Kubernetes projects k8s.gcr.io/external-dns/external-dns ``` -As tags, you use the external-dns release of choice(i.e. `v0.7.3`). A `latest` tag is not provided in the container registry. +As tags, you use the external-dns release of choice(i.e. `v0.7.6`). A `latest` tag is not provided in the container registry. If you wish to build your own image, you can use the provided [Dockerfile](../Dockerfile) as a starting point. diff --git a/docs/tutorials/alibabacloud.md b/docs/tutorials/alibabacloud.md index be5ad66f3..cbe774572 100644 --- a/docs/tutorials/alibabacloud.md +++ b/docs/tutorials/alibabacloud.md @@ -113,7 +113,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service - --source=ingress @@ -187,7 +187,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service - --source=ingress diff --git a/docs/tutorials/aws-sd.md b/docs/tutorials/aws-sd.md index f489529d6..e75d363ad 100644 --- a/docs/tutorials/aws-sd.md +++ b/docs/tutorials/aws-sd.md @@ -81,7 +81,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 env: - name: AWS_REGION value: us-east-1 # put your CloudMap NameSpace region @@ -148,7 +148,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 env: - name: AWS_REGION value: us-east-1 # put your CloudMap NameSpace region diff --git a/docs/tutorials/aws.md b/docs/tutorials/aws.md index d89b1aea0..648e3c290 100644 --- a/docs/tutorials/aws.md +++ b/docs/tutorials/aws.md @@ -141,7 +141,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service - --source=ingress @@ -216,7 +216,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service - --source=ingress diff --git a/docs/tutorials/azure-private-dns.md b/docs/tutorials/azure-private-dns.md index 4aa2a5197..43f4ac734 100644 --- a/docs/tutorials/azure-private-dns.md +++ b/docs/tutorials/azure-private-dns.md @@ -171,7 +171,7 @@ spec: spec: containers: - name: externaldns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service - --source=ingress @@ -242,7 +242,7 @@ spec: serviceAccountName: externaldns containers: - name: externaldns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service - --source=ingress @@ -313,7 +313,7 @@ spec: serviceAccountName: externaldns containers: - name: externaldns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service - --source=ingress diff --git a/docs/tutorials/azure.md b/docs/tutorials/azure.md index 6379f3f3b..fd925d154 100644 --- a/docs/tutorials/azure.md +++ b/docs/tutorials/azure.md @@ -191,7 +191,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service - --source=ingress @@ -261,7 +261,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service - --source=ingress @@ -331,7 +331,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service - --source=ingress diff --git a/docs/tutorials/cloudflare.md b/docs/tutorials/cloudflare.md index d609d3ff1..98580585c 100644 --- a/docs/tutorials/cloudflare.md +++ b/docs/tutorials/cloudflare.md @@ -50,7 +50,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. @@ -118,7 +118,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. diff --git a/docs/tutorials/contour.md b/docs/tutorials/contour.md index 6f3c84423..ed055b16d 100644 --- a/docs/tutorials/contour.md +++ b/docs/tutorials/contour.md @@ -26,7 +26,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service - --source=ingress @@ -102,7 +102,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service - --source=ingress diff --git a/docs/tutorials/coredns.md b/docs/tutorials/coredns.md index 2e4ac6f7c..b9c1282ca 100644 --- a/docs/tutorials/coredns.md +++ b/docs/tutorials/coredns.md @@ -108,7 +108,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=ingress - --provider=coredns @@ -175,7 +175,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=ingress - --provider=coredns diff --git a/docs/tutorials/designate.md b/docs/tutorials/designate.md index 7d8a4df47..2871d2764 100644 --- a/docs/tutorials/designate.md +++ b/docs/tutorials/designate.md @@ -59,7 +59,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. @@ -136,7 +136,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. diff --git a/docs/tutorials/digitalocean.md b/docs/tutorials/digitalocean.md index 08e0fc00f..cd1356fa8 100644 --- a/docs/tutorials/digitalocean.md +++ b/docs/tutorials/digitalocean.md @@ -43,7 +43,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. @@ -107,7 +107,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. diff --git a/docs/tutorials/dnsimple.md b/docs/tutorials/dnsimple.md index 658741ac2..2b7113841 100644 --- a/docs/tutorials/dnsimple.md +++ b/docs/tutorials/dnsimple.md @@ -35,7 +35,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone you create in DNSimple. @@ -100,7 +100,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone you create in DNSimple. diff --git a/docs/tutorials/dyn.md b/docs/tutorials/dyn.md index 1256f4c29..fcee842f2 100644 --- a/docs/tutorials/dyn.md +++ b/docs/tutorials/dyn.md @@ -43,7 +43,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=ingress - --txt-prefix=_d diff --git a/docs/tutorials/exoscale.md b/docs/tutorials/exoscale.md index cc567e841..d3d8e92d4 100644 --- a/docs/tutorials/exoscale.md +++ b/docs/tutorials/exoscale.md @@ -41,7 +41,7 @@ spec: # serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=ingress # or service or both - --provider=exoscale diff --git a/docs/tutorials/externalname.md b/docs/tutorials/externalname.md index d215e70f2..ecc2e9a16 100644 --- a/docs/tutorials/externalname.md +++ b/docs/tutorials/externalname.md @@ -27,7 +27,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --log-level=debug - --source=service diff --git a/docs/tutorials/gke.md b/docs/tutorials/gke.md index 7cba0c341..7e978cb8b 100644 --- a/docs/tutorials/gke.md +++ b/docs/tutorials/gke.md @@ -116,7 +116,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service - --source=ingress @@ -439,7 +439,7 @@ spec: - --google-project=zalando-external-dns-test - --registry=txt - --txt-owner-id=my-identifier - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 name: external-dns securityContext: fsGroup: 65534 diff --git a/docs/tutorials/hetzner.md b/docs/tutorials/hetzner.md index a7b750bf9..3cf647037 100644 --- a/docs/tutorials/hetzner.md +++ b/docs/tutorials/hetzner.md @@ -2,7 +2,7 @@ This tutorial describes how to setup ExternalDNS for usage within a Kubernetes cluster using Hetzner DNS. -Make sure to use **>=0.7.3** version of ExternalDNS for this tutorial. +Make sure to use **>=0.7.6** version of ExternalDNS for this tutorial. ## Creating a Hetzner DNS zone @@ -43,7 +43,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. @@ -107,7 +107,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. diff --git a/docs/tutorials/hostport.md b/docs/tutorials/hostport.md index ea9e8af4a..631b3374e 100644 --- a/docs/tutorials/hostport.md +++ b/docs/tutorials/hostport.md @@ -31,7 +31,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --log-level=debug - --source=service @@ -96,7 +96,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --log-level=debug - --source=service diff --git a/docs/tutorials/infoblox.md b/docs/tutorials/infoblox.md index b0dcd8a43..f0b95d557 100644 --- a/docs/tutorials/infoblox.md +++ b/docs/tutorials/infoblox.md @@ -69,7 +69,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service - --domain-filter=example.com # (optional) limit to only example.com domains. @@ -149,7 +149,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service - --domain-filter=example.com # (optional) limit to only example.com domains. diff --git a/docs/tutorials/istio.md b/docs/tutorials/istio.md index 68263c7cc..74898a7df 100644 --- a/docs/tutorials/istio.md +++ b/docs/tutorials/istio.md @@ -28,7 +28,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service - --source=ingress @@ -98,7 +98,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service - --source=ingress diff --git a/docs/tutorials/kube-ingress-aws.md b/docs/tutorials/kube-ingress-aws.md index 99cd07714..fa4ee4381 100644 --- a/docs/tutorials/kube-ingress-aws.md +++ b/docs/tutorials/kube-ingress-aws.md @@ -265,7 +265,7 @@ written by [kube-ingress-aws-controller][1]: status: loadBalancer: ingress: - - hostname: kube-ing-lb-atedkrlml7iu-1681027139.$region.elb.amazonaws.com + - hostname: kube-ing-lb-atedkrlml7iu-16810.7.69.$region.elb.amazonaws.com ``` ExternalDNS will create a A-records `echoserver.example.org`, that diff --git a/docs/tutorials/linode.md b/docs/tutorials/linode.md index 528575577..ce975e609 100644 --- a/docs/tutorials/linode.md +++ b/docs/tutorials/linode.md @@ -41,7 +41,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. @@ -105,7 +105,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. diff --git a/docs/tutorials/nginx-ingress.md b/docs/tutorials/nginx-ingress.md index b2898935f..28a29d1f2 100644 --- a/docs/tutorials/nginx-ingress.md +++ b/docs/tutorials/nginx-ingress.md @@ -273,7 +273,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=ingress - --domain-filter=external-dns-test.gcp.zalan.do @@ -565,7 +565,7 @@ spec: - --google-project=zalando-external-dns-test - --registry=txt - --txt-owner-id=my-identifier - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 name: external-dns securityContext: fsGroup: 65534 diff --git a/docs/tutorials/ns1.md b/docs/tutorials/ns1.md index e3324dfd3..70cd1a1a8 100644 --- a/docs/tutorials/ns1.md +++ b/docs/tutorials/ns1.md @@ -61,7 +61,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. @@ -125,7 +125,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. diff --git a/docs/tutorials/openshift.md b/docs/tutorials/openshift.md index d055238d2..b685534fb 100644 --- a/docs/tutorials/openshift.md +++ b/docs/tutorials/openshift.md @@ -25,7 +25,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=openshift-route - --domain-filter=external-dns-test.my-org.com # will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones @@ -92,7 +92,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=openshift-route - --domain-filter=external-dns-test.my-org.com # will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones diff --git a/docs/tutorials/oracle.md b/docs/tutorials/oracle.md index 1aef3ce11..33a65e42a 100644 --- a/docs/tutorials/oracle.md +++ b/docs/tutorials/oracle.md @@ -93,7 +93,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service - --source=ingress diff --git a/docs/tutorials/ovh.md b/docs/tutorials/ovh.md index f357d6ddd..a0132ab18 100644 --- a/docs/tutorials/ovh.md +++ b/docs/tutorials/ovh.md @@ -86,7 +86,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. @@ -160,7 +160,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. diff --git a/docs/tutorials/pdns.md b/docs/tutorials/pdns.md index 750af7aed..492e00688 100644 --- a/docs/tutorials/pdns.md +++ b/docs/tutorials/pdns.md @@ -42,7 +42,7 @@ spec: # serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # or ingress or both - --provider=pdns diff --git a/docs/tutorials/public-private-route53.md b/docs/tutorials/public-private-route53.md index b775e9a66..15933bc4b 100644 --- a/docs/tutorials/public-private-route53.md +++ b/docs/tutorials/public-private-route53.md @@ -243,7 +243,7 @@ spec: - --txt-owner-id=external-dns - --annotation-filter=kubernetes.io/ingress.class=external-ingress - --aws-zone-type=public - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 name: external-dns-public ``` @@ -281,7 +281,7 @@ spec: - --txt-owner-id=dev.k8s.nexus - --annotation-filter=kubernetes.io/ingress.class=internal-ingress - --aws-zone-type=private - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 name: external-dns-private ``` diff --git a/docs/tutorials/rcodezero.md b/docs/tutorials/rcodezero.md index 3bc8de65e..ee669bca7 100644 --- a/docs/tutorials/rcodezero.md +++ b/docs/tutorials/rcodezero.md @@ -53,7 +53,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. @@ -120,7 +120,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. diff --git a/docs/tutorials/rdns.md b/docs/tutorials/rdns.md index 94779c52e..3a0fc85fd 100644 --- a/docs/tutorials/rdns.md +++ b/docs/tutorials/rdns.md @@ -54,7 +54,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=ingress - --provider=rdns @@ -123,7 +123,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=ingress - --provider=rdns diff --git a/docs/tutorials/rfc2136.md b/docs/tutorials/rfc2136.md index 7a9082661..902ca5a24 100644 --- a/docs/tutorials/rfc2136.md +++ b/docs/tutorials/rfc2136.md @@ -218,7 +218,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --txt-owner-id=k8s - --provider=rfc2136 @@ -258,7 +258,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --txt-owner-id=k8s - --provider=rfc2136 diff --git a/docs/tutorials/security-context.md b/docs/tutorials/security-context.md index b2a72af8e..44a6f7429 100644 --- a/docs/tutorials/security-context.md +++ b/docs/tutorials/security-context.md @@ -20,7 +20,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - ... # your arguments here securityContext: diff --git a/docs/tutorials/transip.md b/docs/tutorials/transip.md index 62942611c..62e48e591 100644 --- a/docs/tutorials/transip.md +++ b/docs/tutorials/transip.md @@ -36,7 +36,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains @@ -107,7 +107,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains diff --git a/docs/tutorials/ultradns.md b/docs/tutorials/ultradns.md index e0bbae2a6..156f2a068 100644 --- a/docs/tutorials/ultradns.md +++ b/docs/tutorials/ultradns.md @@ -44,7 +44,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service - --source=ingress # ingress is also possible @@ -116,7 +116,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service - --source=ingress diff --git a/docs/tutorials/vinyldns.md b/docs/tutorials/vinyldns.md index 76fc8c039..3720a2594 100644 --- a/docs/tutorials/vinyldns.md +++ b/docs/tutorials/vinyldns.md @@ -66,7 +66,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --provider=vinyldns - --source=service @@ -137,7 +137,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --provider=vinyldns - --source=service diff --git a/docs/tutorials/vultr.md b/docs/tutorials/vultr.md index 091c1c2be..6ccb7ec22 100644 --- a/docs/tutorials/vultr.md +++ b/docs/tutorials/vultr.md @@ -42,7 +42,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. @@ -106,7 +106,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.3 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. From d3577a1e1761d1ea9a30157a5e7b824a5fac15c3 Mon Sep 17 00:00:00 2001 From: Jeff Spahr Date: Thu, 4 Feb 2021 22:48:43 -0500 Subject: [PATCH 038/175] fixed sed being too eager on kube-ingress-aws --- docs/tutorials/kube-ingress-aws.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/kube-ingress-aws.md b/docs/tutorials/kube-ingress-aws.md index fa4ee4381..99cd07714 100644 --- a/docs/tutorials/kube-ingress-aws.md +++ b/docs/tutorials/kube-ingress-aws.md @@ -265,7 +265,7 @@ written by [kube-ingress-aws-controller][1]: status: loadBalancer: ingress: - - hostname: kube-ing-lb-atedkrlml7iu-16810.7.69.$region.elb.amazonaws.com + - hostname: kube-ing-lb-atedkrlml7iu-1681027139.$region.elb.amazonaws.com ``` ExternalDNS will create a A-records `echoserver.example.org`, that From 1e4c1e299da5d6e0109a26e34b57ecffdbbd7a53 Mon Sep 17 00:00:00 2001 From: Dustin Scott Date: Thu, 4 Feb 2021 15:14:48 -0600 Subject: [PATCH 039/175] Add RFC3645 support for secure updates with GSS-TSIG --- docs/tutorials/rfc2136.md | 94 ++++++++++++++++++- go.mod | 5 +- go.sum | 45 +++++++++ main.go | 2 +- pkg/apis/externaldns/types.go | 9 ++ pkg/apis/externaldns/validation/validation.go | 10 ++ .../externaldns/validation/validation_test.go | 60 ++++++++++++ provider/rfc2136/rfc2136.go | 75 +++++++++++++-- provider/rfc2136/rfc2136_test.go | 2 +- 9 files changed, 284 insertions(+), 18 deletions(-) diff --git a/docs/tutorials/rfc2136.md b/docs/tutorials/rfc2136.md index 7a9082661..d8977609a 100644 --- a/docs/tutorials/rfc2136.md +++ b/docs/tutorials/rfc2136.md @@ -220,6 +220,8 @@ spec: - name: external-dns image: k8s.gcr.io/external-dns/external-dns:v0.7.3 args: + - --registry=txt + - --txt-prefix=external-dns- - --txt-owner-id=k8s - --provider=rfc2136 - --rfc2136-host=192.168.0.1 @@ -260,6 +262,8 @@ spec: - name: external-dns image: k8s.gcr.io/external-dns/external-dns:v0.7.3 args: + - --registry=txt + - --txt-prefix=external-dns- - --txt-owner-id=k8s - --provider=rfc2136 - --rfc2136-host=192.168.0.1 @@ -273,17 +277,19 @@ spec: - --domain-filter=k8s.example.org ``` -## Microsoft DNS +## Microsoft DNS (Insecure Updates) While `external-dns` was not developed or tested against Microsoft DNS, it can be configured to work against it. YMMV. -### DNS-side configuration +### Insecure Updates + +#### DNS-side configuration 1. Create a DNS zone 2. Enable insecure dynamic updates for the zone 3. Enable Zone Transfers from all servers -### `external-dns` configuration +#### `external-dns` configuration You'll want to configure `external-dns` similarly to the following: @@ -298,4 +304,84 @@ You'll want to configure `external-dns` similarly to the following: ... ``` -Since Microsoft DNS does not support secure updates via TSIG, this will let `external-dns` make insecure updates. Do this at your own risk. +### Secure Updates Using RFC3645 (GSS-TSIG) + +### DNS-side configuration + +1. Create a DNS zone +2. Enable secure dynamic updates for the zone +3. Enable Zone Transfers from all servers + + +#### Kerberos Configuration + +DNS with secure updates relies upon a valid Kerberos configuration running within the `external-dns` container. At this time, you will need to create a ConfigMap for the `external-dns` container to use and mount it in your deployment. Below is an example of a working Kerberos configuration inside a ConfigMap definition. This may be different depending on many factors in your environment: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + creationTimestamp: null + name: krb5.conf +data: + krb5.conf: | + [logging] + default = FILE:/var/log/krb5libs.log + kdc = FILE:/var/log/krb5kdc.log + admin_server = FILE:/var/log/kadmind.log + + [libdefaults] + dns_lookup_realm = false + ticket_lifetime = 24h + renew_lifetime = 7d + forwardable = true + rdns = false + pkinit_anchors = /etc/pki/tls/certs/ca-bundle.crt + default_ccache_name = KEYRING:persistent:%{uid} + + default_realm = YOURDOMAIN.COM + + [realms] + YOURDOMAIN.COM = { + kdc = dc1.yourdomain.com + admin_server = dc1.yourdomain.com + } + + [domain_realm] + yourdomain.com = YOURDOMAIN.COM + .yourdomain.com = YOURDOMAIN.COM +``` + +Once the ConfigMap is created, the container `external-dns` container needs to be told to mount that ConfigMap as a volume at the default Kerberos configuration location. The pod spec should include a similar configuration to the following: + +```yaml +... + volumeMounts: + - mountPath: /etc/krb5.conf + name: kerberos-config-volume + subPath: krb5.conf +... + volumes: + - configMap: + defaultMode: 420 + name: krb5.conf + name: kerberos-config-volume +... +``` + +#### `external-dns` configuration + +You'll want to configure `external-dns` similarly to the following: + +```text +... + - --provider=rfc2136 + - --rfc2136-gss-tsig + - --rfc2136-host=123.123.123.123 + - --rfc2136-port=53 + - --rfc2136-zone=your-domain.com + - --rfc2136-kerberos-username=your-domain-account + - --rfc2136-kerberos-password=your-domain-password + - --rfc2136-tsig-axfr # needed to enable zone transfers, which is required for deletion of records. +... +``` \ No newline at end of file diff --git a/go.mod b/go.mod index 6cdc70b13..a4ec1c2c2 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/alecthomas/repr v0.0.0-20200325044227-4184120f674c // indirect github.com/aliyun/alibaba-cloud-sdk-go v1.61.357 github.com/aws/aws-sdk-go v1.31.4 + github.com/bodgit/tsig v0.0.2 github.com/cloudflare/cloudflare-go v0.10.1 github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381 github.com/datawire/ambassador v1.6.0 @@ -33,7 +34,7 @@ require ( github.com/linki/instrumented_http v0.2.0 github.com/linode/linodego v0.19.0 github.com/maxatome/go-testdeep v1.4.0 - github.com/miekg/dns v1.1.30 + github.com/miekg/dns v1.1.36-0.20210109083720-731b191cabd1 github.com/nesv/go-dynect v0.6.0 github.com/nic-at/rc0go v1.1.1 github.com/openshift/api v0.0.0-20200605231317-fb2a6ca106ae @@ -55,7 +56,7 @@ require ( github.com/vultr/govultr v0.4.2 go.etcd.io/etcd v0.5.0-alpha.5.0.20200401174654-e694b7bb0875 go.uber.org/ratelimit v0.1.0 - golang.org/x/net v0.0.0-20200625001655-4c5254603344 + golang.org/x/net v0.0.0-20201224014010-6772e930b67b golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d golang.org/x/tools v0.0.0-20200708003708-134513de8882 // indirect google.golang.org/api v0.15.0 diff --git a/go.sum b/go.sum index 8bd1d55b6..d9e31a4a0 100644 --- a/go.sum +++ b/go.sum @@ -92,6 +92,7 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5/go.mod h1:976q2ETgjT2snVCf2ZaBnyBbVoPERGjUz+0sofzEfro= github.com/aliyun/alibaba-cloud-sdk-go v1.61.357 h1:3ynCSeUh9OtJLd/OzLapM1DLDv2g+0yyDdkLqSfZCaQ= github.com/aliyun/alibaba-cloud-sdk-go v1.61.357/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= @@ -124,6 +125,10 @@ github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngE github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/bodgit/tsig v0.0.2 h1:seNt23SrPW8dkWoyRYzdeuqFEzr+lDc0dAJvo94xB8U= +github.com/bodgit/tsig v0.0.2/go.mod h1:0mYe0t9it36SOvDQyeFekc7bLtvljFz7H9vHS/nYbgc= +github.com/bodgit/tsig v1.1.1 h1:SViReRa8KyaweqdJ3ojdYqIE3xDyJlR3G+6wAsSbLCo= +github.com/bodgit/tsig v1.1.1/go.mod h1:8LZ3Mn7AVZHH8GN2ArvzB7msHfLjoptWsdPEJRSw/uo= github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= @@ -231,6 +236,7 @@ github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkg github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/enceve/crypto v0.0.0-20160707101852-34d48bb93815/go.mod h1:wYFFK4LYXbX7j+76mOq7aiC/EAw2S22CrzPHqgsisPw= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.5/go.mod h1:OXl5to++W0ctG+EHWTFUjiypVxC/Y4VLc/KFU+al13s= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= @@ -421,6 +427,8 @@ github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= @@ -443,6 +451,7 @@ github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplb github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= @@ -452,6 +461,8 @@ github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjh github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM= github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= @@ -459,6 +470,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -484,7 +497,21 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/infobloxopen/infoblox-go-client v0.0.0-20180606155407-61dc5f9b0a65 h1:FP5rOFP4ifbtFIjFHJmwhFrsbDyONILK/FNntl/Pou8= github.com/infobloxopen/infoblox-go-client v0.0.0-20180606155407-61dc5f9b0a65/go.mod h1:BXiw7S2b9qJoM8MS40vfgCNB2NLHGusk1DtO16BD9zI= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8= +github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.1 h1:IGSJfqBzMS6TA0oJ7DxXdyzPK563QHa8T2IqER2ggyQ= +github.com/jcmturner/gokrb5/v8 v8.4.1/go.mod h1:T1hnNppQsBtxW0tCHMHTkAt8n/sABdzZgZdoFrZaZNM= +github.com/jcmturner/rpc/v2 v2.0.2 h1:gMB4IwRXYsWw4Bc6o/az2HJgFUA1ffSh90i26ZJ6Xl0= +github.com/jcmturner/rpc/v2 v2.0.2/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jinzhu/copier v0.1.0 h1:Vh8xALtH3rrKGB/XIRe5d0yCTHPZFauWPLvdpDAbi88= +github.com/jinzhu/copier v0.1.0/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -574,6 +601,9 @@ github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3N github.com/miekg/dns v1.1.6/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.30 h1:Qww6FseFn8PRfw07jueqIXqodm0JKiiKuK0DeXSqfyo= github.com/miekg/dns v1.1.30/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/miekg/dns v1.1.36-0.20210109083720-731b191cabd1 h1:kZZmnTeY2r+88mDNCVV/uCXL2gG3rkVPTN9jcYfGQcI= +github.com/miekg/dns v1.1.36-0.20210109083720-731b191cabd1/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/mikkeloscar/knolog v0.0.0-20190326191552-80742771eb6b h1:5f5B1kp+QerGOF91q1qVJcUWWvXsVEN3OKiyEzAAjIM= github.com/mikkeloscar/knolog v0.0.0-20190326191552-80742771eb6b/go.mod h1:PizLs/1ddmVrXpFgWOGNmTJ2YHSWUkpUXMYuUkTo3Go= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -660,6 +690,7 @@ github.com/openshift/api v0.0.0-20200605231317-fb2a6ca106ae/go.mod h1:l6TGeqJ92D github.com/openshift/build-machinery-go v0.0.0-20200424080330-082bf86082cc/go.mod h1:1CkcsT3aVebzRBzVTSbiKSkJMsC/CASqxesfqEMfJEc= github.com/openshift/client-go v0.0.0-20200608144219-584632b8fc73 h1:JePLt9EpNLF/30KsSsArrzxGWPaUIvYUt8Fwnw9wlgM= github.com/openshift/client-go v0.0.0-20200608144219-584632b8fc73/go.mod h1:+66gk3dEqw9e+WoiXjJFzWlS1KGhj9ZRHi/RI/YG/ZM= +github.com/openshift/gssapi v0.0.0-20161010215902-5fb4217df13b/go.mod h1:tNrEB5k8SI+g5kOlsCmL2ELASfpqEofI0+FLBgBdN08= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -910,12 +941,15 @@ golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -971,12 +1005,15 @@ golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190130055435-99b60b757ec1/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1025,6 +1062,7 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1033,6 +1071,13 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78 h1:nVuTkr9L6Bq62qpUqKo/RnZCFfzDBL0bYo6w9OJUqZY= +golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20171227012246-e19ae1496984/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/main.go b/main.go index 8a0db91bc..8135b1c54 100644 --- a/main.go +++ b/main.go @@ -282,7 +282,7 @@ func main() { p, err = oci.NewOCIProvider(*config, domainFilter, zoneIDFilter, cfg.DryRun) } case "rfc2136": - p, err = rfc2136.NewRfc2136Provider(cfg.RFC2136Host, cfg.RFC2136Port, cfg.RFC2136Zone, cfg.RFC2136Insecure, cfg.RFC2136TSIGKeyName, cfg.RFC2136TSIGSecret, cfg.RFC2136TSIGSecretAlg, cfg.RFC2136TAXFR, domainFilter, cfg.DryRun, cfg.RFC2136MinTTL, nil) + p, err = rfc2136.NewRfc2136Provider(cfg.RFC2136Host, cfg.RFC2136Port, cfg.RFC2136Zone, cfg.RFC2136Insecure, cfg.RFC2136TSIGKeyName, cfg.RFC2136TSIGSecret, cfg.RFC2136TSIGSecretAlg, cfg.RFC2136TAXFR, domainFilter, cfg.DryRun, cfg.RFC2136MinTTL, cfg.RFC2136GSSTSIG, cfg.RFC2136KerberosUsername, cfg.RFC2136KerberosPassword, nil) case "ns1": p, err = ns1.NewNS1Provider( ns1.NS1Config{ diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index c436b61f3..95453991a 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -141,6 +141,9 @@ type Config struct { RFC2136Port int RFC2136Zone string RFC2136Insecure bool + RFC2136GSSTSIG bool + RFC2136KerberosUsername string + RFC2136KerberosPassword string RFC2136TSIGKeyName string RFC2136TSIGSecret string `secure:"yes"` RFC2136TSIGSecretAlg string @@ -247,6 +250,9 @@ var defaultConfig = &Config{ RFC2136Port: 0, RFC2136Zone: "", RFC2136Insecure: false, + RFC2136GSSTSIG: false, + RFC2136KerberosUsername: "", + RFC2136KerberosPassword: "", RFC2136TSIGKeyName: "", RFC2136TSIGSecret: "", RFC2136TSIGSecretAlg: "", @@ -414,6 +420,9 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("rfc2136-tsig-secret-alg", "When using the RFC2136 provider, specify the TSIG (base64) value to attached to DNS messages (required when --rfc2136-insecure=false)").Default(defaultConfig.RFC2136TSIGSecretAlg).StringVar(&cfg.RFC2136TSIGSecretAlg) app.Flag("rfc2136-tsig-axfr", "When using the RFC2136 provider, specify the TSIG (base64) value to attached to DNS messages (required when --rfc2136-insecure=false)").BoolVar(&cfg.RFC2136TAXFR) app.Flag("rfc2136-min-ttl", "When using the RFC2136 provider, specify minimal TTL (in duration format) for records. This value will be used if the provided TTL for a service/ingress is lower than this").Default(defaultConfig.RFC2136MinTTL.String()).DurationVar(&cfg.RFC2136MinTTL) + app.Flag("rfc2136-gss-tsig", "When using the RFC2136 provider, specify whether to use secure updates with GSS-TSIG using Kerberos (default: false, requires --rfc2136-kerberos-username and rfc2136-kerberos-password)").Default(strconv.FormatBool(defaultConfig.RFC2136GSSTSIG)).BoolVar(&cfg.RFC2136GSSTSIG) + app.Flag("rfc2136-kerberos-username", "When using the RFC2136 provider with GSS-TSIG, specify the username of the user with permissions to update DNS records (required when --rfc2136-gss-tsig=true)").Default(defaultConfig.RFC2136KerberosUsername).StringVar(&cfg.RFC2136KerberosUsername) + app.Flag("rfc2136-kerberos-password", "When using the RFC2136 provider with GSS-TSIG, specify the password of the user with permissions to update DNS records (required when --rfc2136-gss-tsig=true)").Default(defaultConfig.RFC2136KerberosPassword).StringVar(&cfg.RFC2136KerberosPassword) // Flags related to TransIP provider app.Flag("transip-account", "When using the TransIP provider, specify the account name (required when --provider=transip)").Default(defaultConfig.TransIPAccountName).StringVar(&cfg.TransIPAccountName) diff --git a/pkg/apis/externaldns/validation/validation.go b/pkg/apis/externaldns/validation/validation.go index 3ec950311..81f27a34a 100644 --- a/pkg/apis/externaldns/validation/validation.go +++ b/pkg/apis/externaldns/validation/validation.go @@ -86,6 +86,16 @@ func ValidateConfig(cfg *externaldns.Config) error { if cfg.RFC2136MinTTL < 0 { return errors.New("TTL specified for rfc2136 is negative") } + + if cfg.RFC2136Insecure && cfg.RFC2136GSSTSIG { + return errors.New("--rfc2136-insecure and --rfc2136-gss-tsig are mutually exclusive arguments") + } + + if cfg.RFC2136GSSTSIG { + if cfg.RFC2136KerberosPassword == "" || cfg.RFC2136KerberosUsername == "" { + return errors.New("--rfc2136-kerberos-username and --rfc2136-kerberos-password both required when specifying --rfc2136-gss-tsig option") + } + } } if cfg.IgnoreHostnameAnnotation && cfg.FQDNTemplate == "" { diff --git a/pkg/apis/externaldns/validation/validation_test.go b/pkg/apis/externaldns/validation/validation_test.go index c62b2664a..98c5a5068 100644 --- a/pkg/apis/externaldns/validation/validation_test.go +++ b/pkg/apis/externaldns/validation/validation_test.go @@ -150,3 +150,63 @@ func TestValidateGoodRfc2136Config(t *testing.T) { assert.Nil(t, err) } + +func TestValidateBadRfc2136GssTsigConfig(t *testing.T) { + var invalidRfc2136GssTsigConfigs = []*externaldns.Config{ + { + LogFormat: "json", + Sources: []string{"test-source"}, + Provider: "rfc2136", + RFC2136GSSTSIG: true, + RFC2136KerberosUsername: "test-user", + RFC2136KerberosPassword: "", + RFC2136MinTTL: 3600, + }, + { + LogFormat: "json", + Sources: []string{"test-source"}, + Provider: "rfc2136", + RFC2136GSSTSIG: true, + RFC2136KerberosUsername: "", + RFC2136KerberosPassword: "test-pass", + RFC2136MinTTL: 3600, + }, + { + LogFormat: "json", + Sources: []string{"test-source"}, + Provider: "rfc2136", + RFC2136GSSTSIG: true, + RFC2136Insecure: true, + RFC2136KerberosUsername: "test-user", + RFC2136KerberosPassword: "test-pass", + RFC2136MinTTL: 3600, + }, + } + + for _, cfg := range invalidRfc2136GssTsigConfigs { + err := ValidateConfig(cfg) + + assert.NotNil(t, err) + } +} + +func TestValidateGoodRfc2136GssTsigConfig(t *testing.T) { + var validRfc2136GssTsigConfigs = []*externaldns.Config{ + { + LogFormat: "json", + Sources: []string{"test-source"}, + Provider: "rfc2136", + RFC2136GSSTSIG: true, + RFC2136Insecure: false, + RFC2136KerberosUsername: "test-user", + RFC2136KerberosPassword: "test-pass", + RFC2136MinTTL: 3600, + }, + } + + for _, cfg := range validRfc2136GssTsigConfigs { + err := ValidateConfig(cfg) + + assert.Nil(t, err) + } +} diff --git a/provider/rfc2136/rfc2136.go b/provider/rfc2136/rfc2136.go index 8874b9821..611261160 100644 --- a/provider/rfc2136/rfc2136.go +++ b/provider/rfc2136/rfc2136.go @@ -24,7 +24,11 @@ import ( "strings" "time" + "github.com/bodgit/tsig" + extendedClient "github.com/bodgit/tsig/client" + "github.com/bodgit/tsig/gss" "github.com/miekg/dns" + "github.com/pkg/errors" log "github.com/sirupsen/logrus" @@ -36,6 +40,9 @@ import ( const ( // maximum size of a UDP transport message in DNS protocol udpMaxMsgSize = 512 + + // maximum time DNS client can be off from server for an update to succeed + clockSkew = 300 ) // rfc2136 provider type @@ -50,6 +57,12 @@ type rfc2136Provider struct { axfr bool minTTL time.Duration + // options specific to rfc3645 gss-tsig support + gssTsig bool + krb5Username string + krb5Password string + krb5Realm string + // only consider hosted zones managing domains ending in this suffix domainFilter endpoint.DomainFilter dryRun bool @@ -72,9 +85,9 @@ type rfc2136Actions interface { } // NewRfc2136Provider is a factory function for OpenStack rfc2136 providers -func NewRfc2136Provider(host string, port int, zoneName string, insecure bool, keyName string, secret string, secretAlg string, axfr bool, domainFilter endpoint.DomainFilter, dryRun bool, minTTL time.Duration, actions rfc2136Actions) (provider.Provider, error) { +func NewRfc2136Provider(host string, port int, zoneName string, insecure bool, keyName string, secret string, secretAlg string, axfr bool, domainFilter endpoint.DomainFilter, dryRun bool, minTTL time.Duration, gssTsig bool, krb5Username string, krb5Password string, actions rfc2136Actions) (provider.Provider, error) { secretAlgChecked, ok := tsigAlgs[secretAlg] - if !ok && !insecure { + if !ok && !insecure && !gssTsig { return nil, errors.Errorf("%s is not supported TSIG algorithm", secretAlg) } @@ -82,6 +95,10 @@ func NewRfc2136Provider(host string, port int, zoneName string, insecure bool, k nameserver: net.JoinHostPort(host, strconv.Itoa(port)), zoneName: dns.Fqdn(zoneName), insecure: insecure, + gssTsig: gssTsig, + krb5Username: krb5Username, + krb5Password: krb5Password, + krb5Realm: strings.ToUpper(zoneName), domainFilter: domainFilter, dryRun: dryRun, axfr: axfr, @@ -103,6 +120,22 @@ func NewRfc2136Provider(host string, port int, zoneName string, insecure bool, k return r, nil } +// KeyName will return TKEY name and TSIG handle to use for followon actions with a secure connection +func (r rfc2136Provider) KeyData() (keyName *string, handle *gss.GSS, err error) { + handle, err = gss.New() + if err != nil { + return keyName, handle, err + } + + rawHost, _, err := net.SplitHostPort(r.nameserver) + if err != nil { + return keyName, handle, err + } + + keyName, _, err = handle.NegotiateContextWithCredentials(rawHost, r.krb5Realm, r.krb5Username, r.krb5Password) + return keyName, handle, err +} + // Records returns the list of records. func (r rfc2136Provider) Records(ctx context.Context) ([]*endpoint.Endpoint, error) { rrs, err := r.List() @@ -163,7 +196,7 @@ OuterLoop: func (r rfc2136Provider) IncomeTransfer(m *dns.Msg, a string) (env chan *dns.Envelope, err error) { t := new(dns.Transfer) - if !r.insecure { + if !r.insecure && !r.gssTsig { t.TsigSecret = map[string]string{r.tsigKeyName: r.tsigSecret} } @@ -180,8 +213,8 @@ func (r rfc2136Provider) List() ([]dns.RR, error) { m := new(dns.Msg) m.SetAxfr(r.zoneName) - if !r.insecure { - m.SetTsig(r.tsigKeyName, r.tsigSecretAlg, 300, time.Now().Unix()) + if !r.insecure && !r.gssTsig { + m.SetTsig(r.tsigKeyName, r.tsigSecretAlg, clockSkew, time.Now().Unix()) } env, err := r.actions.IncomeTransfer(m, r.nameserver) @@ -304,12 +337,31 @@ func (r rfc2136Provider) SendMessage(msg *dns.Msg) error { } log.Debugf("SendMessage") - c := new(dns.Client) + c := new(extendedClient.Client) c.SingleInflight = true if !r.insecure { - c.TsigSecret = map[string]string{r.tsigKeyName: r.tsigSecret} - msg.SetTsig(r.tsigKeyName, r.tsigSecretAlg, 300, time.Now().Unix()) + if r.gssTsig { + keyName, handle, err := r.KeyData() + if err != nil { + return err + } + defer handle.Close() + defer handle.DeleteContext(keyName) + + c.TsigAlgorithm = map[string]*extendedClient.TsigAlgorithm{ + tsig.GSS: { + Generate: handle.GenerateGSS, + Verify: handle.VerifyGSS, + }, + } + c.TsigSecret = map[string]string{*keyName: ""} + + msg.SetTsig(*keyName, tsig.GSS, clockSkew, time.Now().Unix()) + } else { + c.TsigSecret = map[string]string{r.tsigKeyName: r.tsigSecret} + msg.SetTsig(r.tsigKeyName, r.tsigSecretAlg, clockSkew, time.Now().Unix()) + } } if msg.Len() > udpMaxMsgSize { @@ -318,8 +370,11 @@ func (r rfc2136Provider) SendMessage(msg *dns.Msg) error { resp, _, err := c.Exchange(msg, r.nameserver) if err != nil { - log.Infof("error in dns.Client.Exchange: %s", err) - return err + if resp != nil && resp.Rcode != dns.RcodeSuccess { + log.Infof("error in dns.Client.Exchange: %s", err) + return err + } + log.Warnf("warn in dns.Client.Exchange: %s", err) } if resp != nil && resp.Rcode != dns.RcodeSuccess { log.Infof("Bad dns.Client.Exchange response: %s", resp) diff --git a/provider/rfc2136/rfc2136_test.go b/provider/rfc2136/rfc2136_test.go index 163414158..1df3ea1c6 100644 --- a/provider/rfc2136/rfc2136_test.go +++ b/provider/rfc2136/rfc2136_test.go @@ -95,7 +95,7 @@ func (r *rfc2136Stub) IncomeTransfer(m *dns.Msg, a string) (env chan *dns.Envelo } func createRfc2136StubProvider(stub *rfc2136Stub) (provider.Provider, error) { - return NewRfc2136Provider("", 0, "", false, "key", "secret", "hmac-sha512", true, endpoint.DomainFilter{}, false, 300*time.Second, stub) + return NewRfc2136Provider("", 0, "", false, "key", "secret", "hmac-sha512", true, endpoint.DomainFilter{}, false, 300*time.Second, false, "", "", stub) } func extractAuthoritySectionFromMessage(msg fmt.Stringer) []string { From 2226e00bd6b81b53951649c7f7bff5ae23c337a7 Mon Sep 17 00:00:00 2001 From: Danny Grove Date: Wed, 8 Apr 2020 09:57:59 -0700 Subject: [PATCH 040/175] Cleanup Docker context and decrease build time This is based off the work found in #1307 that was never merged. It moves around the install and copy of certain conponents to take better advantage of the Docker cache ad well as drops running tests during the build of the image. The reason for dropping tests is to improve build time and as running tests within the build while they're already being run in CI seems like an unnecessary added tax. Signed-off-by: Danny Grove --- .dockerignore | 15 +++++++++++++++ Dockerfile | 6 +++++- Dockerfile.mini | 16 ++++++++++------ 3 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..4e689bc2d --- /dev/null +++ b/.dockerignore @@ -0,0 +1,15 @@ +# Git Related Items +.git +.github +.gitignore + +# CI Related Items +.travis.yml +cloudbuild.yaml +.golangci.yml +.zappr.yaml + +# Other +docs +OWNERS +vendor diff --git a/Dockerfile b/Dockerfile index 8ba67b7b3..8e71170b0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,8 +19,12 @@ ARG ARCH WORKDIR /sigs.k8s.io/external-dns +COPY go.mod . +COPY go.sum . +RUN go mod download + COPY . . -RUN make test && make build.$ARCH +RUN make test build.$ARCH # final image FROM $ARCH/alpine:3.12 diff --git a/Dockerfile.mini b/Dockerfile.mini index d18516a2d..1f7633006 100644 --- a/Dockerfile.mini +++ b/Dockerfile.mini @@ -16,13 +16,17 @@ FROM golang:1.15 as builder WORKDIR /sigs.k8s.io/external-dns +RUN apt-get update \ + && apt-get install \ + ca-certificates \ + && update-ca-certificates + +COPY go.mod . +COPY go.sum . +RUN go mod download + COPY . . -RUN apt-get update && \ - apt-get install ca-certificates && \ - update-ca-certificates && \ - go mod vendor && \ - make test && \ - make build +RUN make test build FROM gcr.io/distroless/static From e3c14b5490b78723fe88d2b80bbfa6c2d77b56e2 Mon Sep 17 00:00:00 2001 From: Enrique Gonzalez Date: Wed, 10 Feb 2021 12:38:57 +0100 Subject: [PATCH 041/175] refactor: regexp types for filter and add tests --- endpoint/domain_filter.go | 44 +++++++++-------------- endpoint/domain_filter_test.go | 57 ++++++++++++++++++++++++++++++ main.go | 2 +- pkg/apis/externaldns/types.go | 13 +++---- pkg/apis/externaldns/types_test.go | 9 ++--- 5 files changed, 86 insertions(+), 39 deletions(-) diff --git a/endpoint/domain_filter.go b/endpoint/domain_filter.go index 4678aa9ee..91445e862 100644 --- a/endpoint/domain_filter.go +++ b/endpoint/domain_filter.go @@ -19,8 +19,6 @@ package endpoint import ( "regexp" "strings" - - log "github.com/sirupsen/logrus" ) // DomainFilter holds a lists of valid domain names @@ -30,9 +28,9 @@ type DomainFilter struct { // exclude define what domains not to match exclude []string // regex defines a regular expression to match the domains - regex string + regex *regexp.Regexp // regexExclusion defines a regular expression to exclude the domains matched - regexExclusion string + regexExclusion *regexp.Regexp } // prepareFilters provides consistent trimming for filters/exclude params @@ -46,23 +44,23 @@ func prepareFilters(filters []string) []string { // NewDomainFilterWithExclusions returns a new DomainFilter, given a list of matches and exclusions func NewDomainFilterWithExclusions(domainFilters []string, excludeDomains []string) DomainFilter { - return DomainFilter{prepareFilters(domainFilters), prepareFilters(excludeDomains), "", ""} + return DomainFilter{Filters: prepareFilters(domainFilters), exclude: prepareFilters(excludeDomains)} } // NewDomainFilter returns a new DomainFilter given a comma separated list of domains func NewDomainFilter(domainFilters []string) DomainFilter { - return DomainFilter{prepareFilters(domainFilters), []string{}, "", ""} + return DomainFilter{Filters: prepareFilters(domainFilters)} } // NewRegexDomainFilter returns a new DomainFilter given a regular expression -func NewRegexDomainFilter(regexDomainFilter string, regexDomainExclusion string) DomainFilter { - return DomainFilter{[]string{}, []string{}, regexDomainFilter, regexDomainExclusion} +func NewRegexDomainFilter(regexDomainFilter *regexp.Regexp, regexDomainExclusion *regexp.Regexp) DomainFilter { + return DomainFilter{regex: regexDomainFilter, regexExclusion: regexDomainExclusion} } // Match checks whether a domain can be found in the DomainFilter. // RegexFilter takes precedence over Filters func (df DomainFilter) Match(domain string) bool { - if df.regex != "" { + if df.regex != nil && df.regex.String() != "" { return matchRegex(df.regex, df.regexExclusion, domain) } @@ -95,32 +93,22 @@ func matchFilter(filters []string, domain string, emptyval bool) bool { return false } -// matchRegex determines if a domain matches the configured regular expressions in the DomainFilter. -// The negativeRegex, if set, takes precedence over regex. Therefore, -// matchRegex returns true when only regex regular expression matches the domain. -// Otherwise, if either negativeRegex matches or regex does not match the domain, it will return false. -func matchRegex(regex string, negativeRegex string, domain string) bool { +// matchRegex determines if a domain matches the configured regular expressions in DomainFilter. +// negativeRegex, if set, takes precedence over regex. Therefore, matchRegex returns true when +// only regex regular expression matches the domain +// Otherwise, if either negativeRegex matches or regex does not match the domain, it returns false +func matchRegex(regex *regexp.Regexp, negativeRegex *regexp.Regexp, domain string) bool { strippedDomain := strings.ToLower(strings.TrimSuffix(domain, ".")) - if negativeRegex != "" { - match, err := regexp.MatchString(negativeRegex, strippedDomain) - if err != nil { - log.Errorf("Failed to filter domain %s with the regex-exclusion filter: %v", domain, err) - } - if match { - return false - } + if negativeRegex != nil && negativeRegex.String() != "" { + return !negativeRegex.MatchString(strippedDomain) } - match, err := regexp.MatchString(regex, strippedDomain) - if err != nil { - log.Errorf("Failed to filter domain %s with the regex filter: %v", domain, err) - } - return match + return regex.MatchString(strippedDomain) } // IsConfigured returns true if DomainFilter is configured, false otherwise func (df DomainFilter) IsConfigured() bool { - if df.regex != "" { + if df.regex != nil && df.regex.String() != "" { return true } else if len(df.Filters) == 1 { return df.Filters[0] != "" diff --git a/endpoint/domain_filter_test.go b/endpoint/domain_filter_test.go index 8cf2e9324..0e1440642 100644 --- a/endpoint/domain_filter_test.go +++ b/endpoint/domain_filter_test.go @@ -17,6 +17,7 @@ limitations under the License. package endpoint import ( + "regexp" "testing" "github.com/stretchr/testify/assert" @@ -29,6 +30,13 @@ type domainFilterTest struct { expected bool } +type regexDomainFilterTest struct { + regex *regexp.Regexp + regexExclusion *regexp.Regexp + domains []string + expected bool +} + var domainFilterTests = []domainFilterTest{ { []string{"google.com.", "exaring.de", "inovex.de"}, @@ -212,6 +220,45 @@ var domainFilterTests = []domainFilterTest{ }, } +var regexDomainFilterTests = []regexDomainFilterTest{ + { + regexp.MustCompile("\\.org$"), + regexp.MustCompile(""), + []string{"foo.org", "bar.org", "foo.bar.org"}, + true, + }, + { + regexp.MustCompile("\\.bar\\.org$"), + regexp.MustCompile(""), + []string{"foo.org", "bar.org", "example.com"}, + false, + }, + { + regexp.MustCompile("(?:foo|bar)\\.org$"), + regexp.MustCompile(""), + []string{"foo.org", "bar.org", "example.foo.org", "example.bar.org", "a.example.foo.org", "a.example.bar.org"}, + true, + }, + { + regexp.MustCompile("(?:foo|bar)\\.org$"), + regexp.MustCompile("^example\\.(?:foo|bar)\\.org$"), + []string{"foo.org", "bar.org", "a.example.foo.org", "a.example.bar.org"}, + true, + }, + { + regexp.MustCompile("(?:foo|bar)\\.org$"), + regexp.MustCompile("^example\\.(?:foo|bar)\\.org$"), + []string{"example.foo.org", "example.bar.org"}, + false, + }, + { + regexp.MustCompile("(?:foo|bar)\\.org$"), + regexp.MustCompile("^example\\.(?:foo|bar)\\.org$"), + []string{"foo.org", "bar.org", "a.example.foo.org", "a.example.bar.org"}, + true, + }, +} + func TestDomainFilterMatch(t *testing.T) { for i, tt := range domainFilterTests { if len(tt.exclusions) > 0 { @@ -245,6 +292,16 @@ func TestDomainFilterMatchWithEmptyFilter(t *testing.T) { } } +func TestRegexDomainFilter(t *testing.T) { + for i, tt := range regexDomainFilterTests { + domainFilter := NewRegexDomainFilter(tt.regex, tt.regexExclusion) + for _, domain := range tt.domains { + assert.Equal(t, tt.expected, domainFilter.Match(domain), "should not fail: %v in test-case #%v", domain, i) + assert.Equal(t, tt.expected, domainFilter.Match(domain+"."), "should not fail: %v in test-case #%v", domain+".", i) + } + } +} + func TestPrepareFiltersStripsWhitespaceAndDotSuffix(t *testing.T) { for _, tt := range []struct { input []string diff --git a/main.go b/main.go index faa1de87d..e931564db 100644 --- a/main.go +++ b/main.go @@ -144,7 +144,7 @@ func main() { // RegexDomainFilter overrides DomainFilter var domainFilter endpoint.DomainFilter - if cfg.RegexDomainFilter != "" { + if cfg.RegexDomainFilter.String() != "" { domainFilter = endpoint.NewRegexDomainFilter(cfg.RegexDomainFilter, cfg.RegexDomainExclusion) } else { domainFilter = endpoint.NewDomainFilterWithExclusions(cfg.DomainFilter, cfg.ExcludeDomains) diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 109fc36ec..e6d880348 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -19,6 +19,7 @@ package externaldns import ( "fmt" "reflect" + "regexp" "strconv" "time" @@ -63,8 +64,8 @@ type Config struct { GoogleBatchChangeInterval time.Duration DomainFilter []string ExcludeDomains []string - RegexDomainFilter string - RegexDomainExclusion string + RegexDomainFilter *regexp.Regexp + RegexDomainExclusion *regexp.Regexp ZoneNameFilter []string ZoneIDFilter []string AlibabaCloudConfigFile string @@ -175,8 +176,8 @@ var defaultConfig = &Config{ GoogleBatchChangeInterval: time.Second, DomainFilter: []string{}, ExcludeDomains: []string{}, - RegexDomainFilter: "", - RegexDomainExclusion: "", + RegexDomainFilter: regexp.MustCompile(""), + RegexDomainExclusion: regexp.MustCompile(""), AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json", AWSZoneType: "", AWSZoneTagFilter: []string{}, @@ -334,8 +335,8 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, aws-sd, google, azure, azure-dns, azure-private-dns, cloudflare, rcodezero, digitalocean, hetzner, dnsimple, akamai, infoblox, dyn, designate, coredns, skydns, inmemory, ovh, pdns, oci, exoscale, linode, rfc2136, ns1, transip, vinyldns, rdns, scaleway, vultr, ultradns)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "aws-sd", "google", "azure", "azure-dns", "hetzner", "azure-private-dns", "alibabacloud", "cloudflare", "rcodezero", "digitalocean", "dnsimple", "akamai", "infoblox", "dyn", "designate", "coredns", "skydns", "inmemory", "ovh", "pdns", "oci", "exoscale", "linode", "rfc2136", "ns1", "transip", "vinyldns", "rdns", "scaleway", "vultr", "ultradns") app.Flag("domain-filter", "Limit possible target zones by a domain suffix; specify multiple times for multiple domains (optional)").Default("").StringsVar(&cfg.DomainFilter) app.Flag("exclude-domains", "Exclude subdomains (optional)").Default("").StringsVar(&cfg.ExcludeDomains) - app.Flag("regex-domain-filter", "Limit possible domains and target zones by a Regex filter; Overrides domain-filter (optional)").Default("").StringVar(&cfg.RegexDomainFilter) - app.Flag("regex-domain-exclusion", "Regex filter that excludes domains and target zones matched by regex-domain-filter (optional)").Default("").StringVar(&cfg.RegexDomainExclusion) + app.Flag("regex-domain-filter", "Limit possible domains and target zones by a Regex filter; Overrides domain-filter (optional)").Default(defaultConfig.RegexDomainFilter.String()).RegexpVar(&cfg.RegexDomainFilter) + app.Flag("regex-domain-exclusion", "Regex filter that excludes domains and target zones matched by regex-domain-filter (optional)").Default(defaultConfig.RegexDomainExclusion.String()).RegexpVar(&cfg.RegexDomainExclusion) app.Flag("zone-name-filter", "Filter target zones by zone domain (For now, only AzureDNS provider is using this flag); specify multiple times for multiple zones (optional)").Default("").StringsVar(&cfg.ZoneNameFilter) app.Flag("zone-id-filter", "Filter target zones by hosted zone id; specify multiple times for multiple zones (optional)").Default("").StringsVar(&cfg.ZoneIDFilter) app.Flag("google-project", "When using the Google provider, current project is auto-detected, when running on GCP. Specify other project with this. Must be specified when running outside GCP.").Default(defaultConfig.GoogleProject).StringVar(&cfg.GoogleProject) diff --git a/pkg/apis/externaldns/types_test.go b/pkg/apis/externaldns/types_test.go index c1053bf75..87e2144db 100644 --- a/pkg/apis/externaldns/types_test.go +++ b/pkg/apis/externaldns/types_test.go @@ -18,6 +18,7 @@ package externaldns import ( "os" + "regexp" "strings" "testing" "time" @@ -44,8 +45,8 @@ var ( GoogleBatchChangeInterval: time.Second, DomainFilter: []string{""}, ExcludeDomains: []string{""}, - RegexDomainFilter: "", - RegexDomainExclusion: "", + RegexDomainFilter: regexp.MustCompile(""), + RegexDomainExclusion: regexp.MustCompile(""), ZoneNameFilter: []string{""}, ZoneIDFilter: []string{""}, AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json", @@ -124,8 +125,8 @@ var ( GoogleBatchChangeInterval: time.Second * 2, DomainFilter: []string{"example.org", "company.com"}, ExcludeDomains: []string{"xapi.example.org", "xapi.company.com"}, - RegexDomainFilter: "(example\\.org|company\\.com)$", - RegexDomainExclusion: "xapi\\.(example\\.org|company\\.com)$", + RegexDomainFilter: regexp.MustCompile("(example\\.org|company\\.com)$"), + RegexDomainExclusion: regexp.MustCompile("xapi\\.(example\\.org|company\\.com)$"), ZoneNameFilter: []string{"yapi.example.org", "yapi.company.com"}, ZoneIDFilter: []string{"/hostedzone/ZTST1", "/hostedzone/ZTST2"}, AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json", From 0a9daa9e9b16307610f9c2cda88402390a8f2494 Mon Sep 17 00:00:00 2001 From: Rob Selway Date: Sun, 14 Feb 2021 13:40:25 +0000 Subject: [PATCH 042/175] Case insensitivity when comparing targets --- endpoint/endpoint.go | 4 ++-- endpoint/endpoint_test.go | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/endpoint/endpoint.go b/endpoint/endpoint.go index bb082e2a5..07bd3ea4b 100644 --- a/endpoint/endpoint.go +++ b/endpoint/endpoint.go @@ -71,7 +71,7 @@ func (t Targets) Swap(i, j int) { t[i], t[j] = t[j], t[i] } -// Same compares to Targets and returns true if they are completely identical +// Same compares to Targets and returns true if they are identical (case-insensitive) func (t Targets) Same(o Targets) bool { if len(t) != len(o) { return false @@ -80,7 +80,7 @@ func (t Targets) Same(o Targets) bool { sort.Stable(o) for i, e := range t { - if e != o[i] { + if !strings.EqualFold(e, o[i]) { return false } } diff --git a/endpoint/endpoint_test.go b/endpoint/endpoint_test.go index 18a79a02c..05104adbf 100644 --- a/endpoint/endpoint_test.go +++ b/endpoint/endpoint_test.go @@ -40,6 +40,7 @@ func TestTargetsSame(t *testing.T) { {""}, {"1.2.3.4"}, {"8.8.8.8", "8.8.4.4"}, + {"example.org", "EXAMPLE.ORG"}, } for _, d := range tests { From 091b8a8f825f7b6c2b5a90e0fdbd7fbb3bd1d4dc Mon Sep 17 00:00:00 2001 From: Rob Selway Date: Sun, 14 Feb 2021 13:41:38 +0000 Subject: [PATCH 043/175] Plan test for ignoring case when comparing targets --- plan/plan_test.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/plan/plan_test.go b/plan/plan_test.go index 5ea0f55ab..992263cd4 100644 --- a/plan/plan_test.go +++ b/plan/plan_test.go @@ -30,6 +30,7 @@ type PlanTestSuite struct { suite.Suite fooV1Cname *endpoint.Endpoint fooV2Cname *endpoint.Endpoint + fooV2CnameUppercase *endpoint.Endpoint fooV2TXT *endpoint.Endpoint fooV2CnameNoLabel *endpoint.Endpoint fooV3CnameSameResource *endpoint.Endpoint @@ -77,6 +78,14 @@ func (suite *PlanTestSuite) SetupTest() { endpoint.ResourceLabelKey: "ingress/default/foo-v2", }, } + suite.fooV2CnameUppercase = &endpoint.Endpoint{ + DNSName: "foo", + Targets: endpoint.Targets{"V2"}, + RecordType: "CNAME", + Labels: map[string]string{ + endpoint.ResourceLabelKey: "ingress/default/foo-v2", + }, + } suite.fooV2TXT = &endpoint.Endpoint{ DNSName: "foo", RecordType: "TXT", @@ -443,6 +452,27 @@ func (suite *PlanTestSuite) TestIgnoreTXT() { validateEntries(suite.T(), changes.Delete, expectedDelete) } +func (suite *PlanTestSuite) TestIgnoreTargetCase() { + current := []*endpoint.Endpoint{suite.fooV2Cname} + desired := []*endpoint.Endpoint{suite.fooV2CnameUppercase} + expectedCreate := []*endpoint.Endpoint{} + expectedUpdateOld := []*endpoint.Endpoint{} + expectedUpdateNew := []*endpoint.Endpoint{} + expectedDelete := []*endpoint.Endpoint{} + + p := &Plan{ + Policies: []Policy{&SyncPolicy{}}, + Current: current, + Desired: desired, + } + + changes := p.Calculate().Changes + validateEntries(suite.T(), changes.Create, expectedCreate) + validateEntries(suite.T(), changes.UpdateNew, expectedUpdateNew) + validateEntries(suite.T(), changes.UpdateOld, expectedUpdateOld) + validateEntries(suite.T(), changes.Delete, expectedDelete) +} + func (suite *PlanTestSuite) TestRemoveEndpoint() { current := []*endpoint.Endpoint{suite.fooV1Cname, suite.bar192A} desired := []*endpoint.Endpoint{suite.fooV1Cname} From 261779c468c9600088c15290dfa20bfa1fdcb5fc Mon Sep 17 00:00:00 2001 From: Rob Selway Date: Sun, 14 Feb 2021 13:44:36 +0000 Subject: [PATCH 044/175] Cloudflare fix for deletion of entry with casing difference --- provider/cloudflare/cloudflare_test.go | 46 ++++++++++++++++++++++++++ provider/provider.go | 4 +-- provider/provider_test.go | 9 +++++ 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/provider/cloudflare/cloudflare_test.go b/provider/cloudflare/cloudflare_test.go index 440cc8b65..b6bfc3b0d 100644 --- a/provider/cloudflare/cloudflare_test.go +++ b/provider/cloudflare/cloudflare_test.go @@ -693,6 +693,52 @@ func TestCloudflareApplyChanges(t *testing.T) { } } +func TestCloudflareApplyChangesUpsertOnly(t *testing.T) { + changes := &plan.Changes{} + client := NewMockCloudFlareClient() + provider := &CloudFlareProvider{ + Client: client, + } + changes.Create = []*endpoint.Endpoint{} + changes.Delete = []*endpoint.Endpoint{} + changes.UpdateOld = []*endpoint.Endpoint{{ + DNSName: "foobar.bar.com", + Targets: endpoint.Targets{"target-foo"}, + }} + changes.UpdateNew = []*endpoint.Endpoint{{ + DNSName: "new.bar.com", + Targets: endpoint.Targets{"target-new"}, + }} + err := provider.ApplyChanges(context.Background(), changes) + + if err != nil { + t.Errorf("should not fail, %s", err) + } + + td.Cmp(t, client.Actions, []MockAction{ + { + Name: "Create", + ZoneId: "001", + RecordData: cloudflare.DNSRecord{ + Name: "new.bar.com", + Content: "target-new", + TTL: 1, + }, + }, + }) + + // empty changes + changes.Create = []*endpoint.Endpoint{} + changes.Delete = []*endpoint.Endpoint{} + changes.UpdateOld = []*endpoint.Endpoint{} + changes.UpdateNew = []*endpoint.Endpoint{} + + err = provider.ApplyChanges(context.Background(), changes) + if err != nil { + t.Errorf("should not fail, %s", err) + } +} + func TestCloudflareGetRecordID(t *testing.T) { p := &CloudFlareProvider{} records := []cloudflare.DNSRecord{ diff --git a/provider/provider.go b/provider/provider.go index c0c66cff0..648e888a5 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -73,9 +73,9 @@ func Difference(current, desired []string) ([]string, []string, []string) { index[x] = struct{}{} } for _, x := range desired { - if _, found := index[x]; found { + if _, found := index[strings.ToLower(x)]; found { leave = append(leave, x) - delete(index, x) + delete(index, strings.ToLower(x)) } else { add = append(add, x) delete(index, x) diff --git a/provider/provider_test.go b/provider/provider_test.go index 0e24ca4f0..b6c3d7f52 100644 --- a/provider/provider_test.go +++ b/provider/provider_test.go @@ -55,6 +55,15 @@ func TestDifference(t *testing.T) { assert.Equal(t, leave, []string{"bar"}) } +func TestDifferenceCaseInsensitivity(t *testing.T) { + current := []string{"foo", "bar"} + desired := []string{"BAR", "baz"} + add, remove, leave := Difference(current, desired) + assert.Equal(t, []string{"baz"}, add) + assert.Equal(t, []string{"foo"}, remove) + assert.Equal(t, []string{"BAR"}, leave) +} + func TestBaseProviderPropertyEquality(t *testing.T) { p := BaseProvider{} assert.True(t, p.PropertyValuesEqual("some.property", "", ""), "Both properties not present") From 642744abacc337e7f4b950eebe19ffc08510f003 Mon Sep 17 00:00:00 2001 From: Rob Selway Date: Sun, 14 Feb 2021 14:52:13 +0000 Subject: [PATCH 045/175] Revert "Cloudflare fix for deletion of entry with casing difference" This reverts commit 261779c468c9600088c15290dfa20bfa1fdcb5fc. --- provider/cloudflare/cloudflare_test.go | 46 -------------------------- provider/provider.go | 4 +-- provider/provider_test.go | 9 ----- 3 files changed, 2 insertions(+), 57 deletions(-) diff --git a/provider/cloudflare/cloudflare_test.go b/provider/cloudflare/cloudflare_test.go index 9295d6828..fae840b2b 100644 --- a/provider/cloudflare/cloudflare_test.go +++ b/provider/cloudflare/cloudflare_test.go @@ -709,52 +709,6 @@ func TestCloudflareApplyChanges(t *testing.T) { } } -func TestCloudflareApplyChangesUpsertOnly(t *testing.T) { - changes := &plan.Changes{} - client := NewMockCloudFlareClient() - provider := &CloudFlareProvider{ - Client: client, - } - changes.Create = []*endpoint.Endpoint{} - changes.Delete = []*endpoint.Endpoint{} - changes.UpdateOld = []*endpoint.Endpoint{{ - DNSName: "foobar.bar.com", - Targets: endpoint.Targets{"target-foo"}, - }} - changes.UpdateNew = []*endpoint.Endpoint{{ - DNSName: "new.bar.com", - Targets: endpoint.Targets{"target-new"}, - }} - err := provider.ApplyChanges(context.Background(), changes) - - if err != nil { - t.Errorf("should not fail, %s", err) - } - - td.Cmp(t, client.Actions, []MockAction{ - { - Name: "Create", - ZoneId: "001", - RecordData: cloudflare.DNSRecord{ - Name: "new.bar.com", - Content: "target-new", - TTL: 1, - }, - }, - }) - - // empty changes - changes.Create = []*endpoint.Endpoint{} - changes.Delete = []*endpoint.Endpoint{} - changes.UpdateOld = []*endpoint.Endpoint{} - changes.UpdateNew = []*endpoint.Endpoint{} - - err = provider.ApplyChanges(context.Background(), changes) - if err != nil { - t.Errorf("should not fail, %s", err) - } -} - func TestCloudflareGetRecordID(t *testing.T) { p := &CloudFlareProvider{} records := []cloudflare.DNSRecord{ diff --git a/provider/provider.go b/provider/provider.go index 648e888a5..c0c66cff0 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -73,9 +73,9 @@ func Difference(current, desired []string) ([]string, []string, []string) { index[x] = struct{}{} } for _, x := range desired { - if _, found := index[strings.ToLower(x)]; found { + if _, found := index[x]; found { leave = append(leave, x) - delete(index, strings.ToLower(x)) + delete(index, x) } else { add = append(add, x) delete(index, x) diff --git a/provider/provider_test.go b/provider/provider_test.go index b6c3d7f52..0e24ca4f0 100644 --- a/provider/provider_test.go +++ b/provider/provider_test.go @@ -55,15 +55,6 @@ func TestDifference(t *testing.T) { assert.Equal(t, leave, []string{"bar"}) } -func TestDifferenceCaseInsensitivity(t *testing.T) { - current := []string{"foo", "bar"} - desired := []string{"BAR", "baz"} - add, remove, leave := Difference(current, desired) - assert.Equal(t, []string{"baz"}, add) - assert.Equal(t, []string{"foo"}, remove) - assert.Equal(t, []string{"BAR"}, leave) -} - func TestBaseProviderPropertyEquality(t *testing.T) { p := BaseProvider{} assert.True(t, p.PropertyValuesEqual("some.property", "", ""), "Both properties not present") From e39d09f7a6523bd3d9f7273f129416ac5b0a6ca3 Mon Sep 17 00:00:00 2001 From: brumhard Date: Tue, 16 Feb 2021 10:36:34 +0100 Subject: [PATCH 046/175] Add info in FAQ on how to enable new traefik chart --- docs/faq.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/faq.md b/docs/faq.md index 0037e8f9a..b53c24995 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -75,7 +75,9 @@ Regarding Ingress, we'll support: * Google's Ingress Controller on GKE that integrates with their Layer 7 load balancers (GLBC) * nginx-ingress-controller v0.9.x with a fronting Service * Zalando's [AWS Ingress controller](https://github.com/zalando-incubator/kube-ingress-aws-controller), based on AWS ALBs and [Skipper](https://github.com/zalando/skipper) -* [Traefik](https://github.com/containous/traefik) 1.7 and above, when [`kubernetes.ingressEndpoint`](https://docs.traefik.io/v1.7/configuration/backends/kubernetes/#ingressendpoint) is configured (`kubernetes.ingressEndpoint.useDefaultPublishedService` in the [Helm chart](https://github.com/helm/charts/tree/HEAD/stable/traefik#configuration)) +* [Traefik](https://github.com/containous/traefik) + * version 1.7, when [`kubernetes.ingressEndpoint`](https://docs.traefik.io/v1.7/configuration/backends/kubernetes/#ingressendpoint) is configured (`kubernetes.ingressEndpoint.useDefaultPublishedService` in the [Helm chart](https://github.com/helm/charts/tree/HEAD/stable/traefik#configuration)) + * versions \>=2.0, when [`providers.kubernetesIngress.ingressEndpoint`](https://doc.traefik.io/traefik/providers/kubernetes-ingress/#ingressendpoint) is configured (`providers.kubernetesIngress.publishedService.enabled` is set to `true` in the [new Helm chart](https://github.com/traefik/traefik-helm-chart)) ### Are other Ingress Controllers supported? @@ -192,7 +194,7 @@ You can use the host label in the metric to figure out if the request was agains Here is the full list of available metrics provided by ExternalDNS: | Name | Description | Type | -|-----------------------------------------------------|---------------------------------------------------------|---------| +| --------------------------------------------------- | ------------------------------------------------------- | ------- | | external_dns_controller_last_sync_timestamp_seconds | Timestamp of last successful sync with the DNS provider | Gauge | | external_dns_registry_endpoints_total | Number of Endpoints in all sources | Gauge | | external_dns_registry_errors_total | Number of Registry errors | Counter | From 3826d236a6ec4989003dd29dd93d60bf72c98ed2 Mon Sep 17 00:00:00 2001 From: Raffaele Di Fazio Date: Wed, 17 Feb 2021 10:00:08 +0100 Subject: [PATCH 047/175] Fix typo in scaleway provider --- provider/scaleway/scaleway.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/provider/scaleway/scaleway.go b/provider/scaleway/scaleway.go index df4677a79..77e9e5654 100644 --- a/provider/scaleway/scaleway.go +++ b/provider/scaleway/scaleway.go @@ -136,7 +136,7 @@ func (p *ScalewayProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, e // In this case, we juste take the first one. if existingEndpoint, ok := endpoints[record.Type.String()+"/"+fullRecordName]; ok { existingEndpoint.Targets = append(existingEndpoint.Targets, record.Data) - log.Infof("Appending target %s to record %s, using TTL and priotiry of target %s", record.Data, fullRecordName, existingEndpoint.Targets[0]) + log.Infof("Appending target %s to record %s, using TTL and priority of target %s", record.Data, fullRecordName, existingEndpoint.Targets[0]) } else { ep := endpoint.NewEndpointWithTTL(fullRecordName, record.Type.String(), endpoint.TTL(record.TTL), record.Data) ep = ep.WithProviderSpecific(scalewayPriorityKey, fmt.Sprintf("%d", record.Priority)) From 5146c6e7e1401bf6f4a88bfec3d2ce9627ed2fd9 Mon Sep 17 00:00:00 2001 From: Brett Polivka Date: Wed, 17 Feb 2021 15:32:08 +0000 Subject: [PATCH 048/175] rename appendIfMissing to appendUnique and add comment --- source/virtualservice.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/virtualservice.go b/source/virtualservice.go index d9b720112..f62ef6df7 100644 --- a/source/virtualservice.go +++ b/source/virtualservice.go @@ -317,7 +317,8 @@ func (sc *virtualServiceSource) setResourceLabel(virtualservice networkingv1alph } } -func appendIfMissing(targets []string, target string) []string { +// append a target to the list of targets unless it's already in the list +func appendUnique(targets []string, target string) []string { for _, element := range targets { if element == target { return targets @@ -342,7 +343,7 @@ func (sc *virtualServiceSource) targetsFromVirtualService(ctx context.Context, v return targets, err } for _, target := range tgs { - targets = appendIfMissing(targets, target) + targets = appendUnique(targets, target) } } From eba31ec0d8a9e67b3f2755457da9f232a753e494 Mon Sep 17 00:00:00 2001 From: Joshua Stern Date: Thu, 18 Feb 2021 12:54:33 -0500 Subject: [PATCH 049/175] Add support for aws eu-south-1 region --- provider/aws/aws.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/provider/aws/aws.go b/provider/aws/aws.go index 744b945c9..2581af2a1 100644 --- a/provider/aws/aws.go +++ b/provider/aws/aws.go @@ -74,6 +74,7 @@ var ( "eu-west-2.elb.amazonaws.com": "ZHURV8PSTC4K8", "eu-west-3.elb.amazonaws.com": "Z3Q77PNBQS71R4", "eu-north-1.elb.amazonaws.com": "Z23TAZ6LKFMNIO", + "eu-south-1.elb.amazonaws.com": "Z3ULH7SSC9OV64", "sa-east-1.elb.amazonaws.com": "Z2P70J7HTTTPLU", "cn-north-1.elb.amazonaws.com.cn": "Z1GDH35T77C1KE", "cn-northwest-1.elb.amazonaws.com.cn": "ZM7IZAIOVVDZF", @@ -98,6 +99,7 @@ var ( "elb.eu-west-2.amazonaws.com": "ZD4D7Y8KGAS4G", "elb.eu-west-3.amazonaws.com": "Z1CMS0P5QUZ6D5", "elb.eu-north-1.amazonaws.com": "Z1UDT6IFJ4EJM", + "elb.eu-south-1.amazonaws.com": "Z23146JA1KNAFP", "elb.sa-east-1.amazonaws.com": "ZTK26PT1VY4CU", "elb.cn-north-1.amazonaws.com.cn": "Z3QFB96KMJ7ED6", "elb.cn-northwest-1.amazonaws.com.cn": "ZQEIKTCZ8352D", From 444f5d5a9dd041206a141322bb0e3d233cd90dc5 Mon Sep 17 00:00:00 2001 From: Patrik Cyvoct Date: Thu, 28 Jan 2021 07:25:46 +0100 Subject: [PATCH 050/175] Bump Scaleway DNS API to v2beta1 Signed-off-by: Patrik Cyvoct --- CHANGELOG.md | 1 + go.mod | 2 +- go.sum | 4 +-- provider/scaleway/interface.go | 2 +- provider/scaleway/scaleway.go | 18 ++++++----- provider/scaleway/scaleway_test.go | 52 ++++++++++++++++++------------ 6 files changed, 47 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74bee768a..9b99a6114 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - Option to cache AWS zones list @bpineau - Refactor, enhance and test Akamai provider and documentation (#1846) @edglynes - Fix: only use absolute CNAMEs in Scaleway provider (#1859) @Sh4d1 +- Change Scaleway DNS API version from v2alpha2 to v2beta1 (#1938) @Sh4d1 ## v0.7.3 - 2020-08-05 diff --git a/go.mod b/go.mod index 3c11ba851..c28b520bf 100644 --- a/go.mod +++ b/go.mod @@ -45,7 +45,7 @@ require ( github.com/projectcontour/contour v1.5.0 github.com/prometheus/client_golang v1.7.1 github.com/sanyu/dynectsoap v0.0.0-20181203081243-b83de5edc4e0 - github.com/scaleway/scaleway-sdk-go v1.0.0-beta.6.0.20200623155123-84df6c4b5301 + github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f github.com/sirupsen/logrus v1.6.0 github.com/smartystreets/gunit v1.3.4 // indirect github.com/stretchr/testify v1.6.1 diff --git a/go.sum b/go.sum index d9e31a4a0..c0c41bd25 100644 --- a/go.sum +++ b/go.sum @@ -789,8 +789,8 @@ github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0 github.com/sanyu/dynectsoap v0.0.0-20181203081243-b83de5edc4e0 h1:vOcHdR1nu7DO4BAx1rwzdHV7jQTzW3gqcBT5qxHSc6A= github.com/sanyu/dynectsoap v0.0.0-20181203081243-b83de5edc4e0/go.mod h1:FeplEtXXejBYC4NPAFTrs5L7KuK+5RL9bf5nB2vZe9o= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.6.0.20200623155123-84df6c4b5301 h1:qj0du14RIOnmePII/eTlw1aHKDYL6zxDIk/Dq7Tef9k= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.6.0.20200623155123-84df6c4b5301/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f h1:WSnaD0/cvbKJgSTYbjAPf4RJXVvNNDAwVm+W8wEmnGE= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= diff --git a/provider/scaleway/interface.go b/provider/scaleway/interface.go index 671b05b43..75366bbe6 100644 --- a/provider/scaleway/interface.go +++ b/provider/scaleway/interface.go @@ -17,7 +17,7 @@ limitations under the License. package scaleway import ( - domain "github.com/scaleway/scaleway-sdk-go/api/domain/v2alpha2" + domain "github.com/scaleway/scaleway-sdk-go/api/domain/v2beta1" "github.com/scaleway/scaleway-sdk-go/scw" ) diff --git a/provider/scaleway/scaleway.go b/provider/scaleway/scaleway.go index 77e9e5654..66f505ced 100644 --- a/provider/scaleway/scaleway.go +++ b/provider/scaleway/scaleway.go @@ -22,7 +22,7 @@ import ( "strconv" "strings" - domain "github.com/scaleway/scaleway-sdk-go/api/domain/v2alpha2" + domain "github.com/scaleway/scaleway-sdk-go/api/domain/v2beta1" "github.com/scaleway/scaleway-sdk-go/scw" log "github.com/sirupsen/logrus" @@ -297,9 +297,11 @@ func endpointToScalewayRecordsChangeDelete(zoneName string, ep *endpoint.Endpoin records = append(records, &domain.RecordChange{ Delete: &domain.RecordChangeDelete{ - Data: finalTargetName, - Name: strings.Trim(strings.TrimSuffix(ep.DNSName, zoneName), ". "), - Type: domain.RecordType(ep.RecordType), + IDFields: &domain.RecordIdentifier{ + Data: &finalTargetName, + Name: strings.Trim(strings.TrimSuffix(ep.DNSName, zoneName), ". "), + Type: domain.RecordType(ep.RecordType), + }, }, }) } @@ -330,15 +332,15 @@ func logChanges(req *domain.UpdateDNSZoneRecordsRequest) { log.WithFields(logFields).Info("Adding record") } } else if change.Delete != nil { - name := change.Delete.Name + "." - if change.Delete.Name == "" { + name := change.Delete.IDFields.Name + "." + if change.Delete.IDFields.Name == "" { name = "" } logFields := log.Fields{ "record": name + req.DNSZone, - "type": change.Delete.Type.String(), - "data": change.Delete.Data, + "type": change.Delete.IDFields.Type.String(), + "data": *change.Delete.IDFields.Data, } log.WithFields(logFields).Info("Deleting record") diff --git a/provider/scaleway/scaleway_test.go b/provider/scaleway/scaleway_test.go index a0a67461e..3db50301b 100644 --- a/provider/scaleway/scaleway_test.go +++ b/provider/scaleway/scaleway_test.go @@ -22,7 +22,7 @@ import ( "reflect" "testing" - domain "github.com/scaleway/scaleway-sdk-go/api/domain/v2alpha2" + domain "github.com/scaleway/scaleway-sdk-go/api/domain/v2beta1" "github.com/scaleway/scaleway-sdk-go/scw" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -302,23 +302,29 @@ func TestScalewayProvider_generateApplyRequests(t *testing.T) { }, { Delete: &domain.RecordChangeDelete{ - Data: "3.3.3.3", - Name: "me", - Type: domain.RecordTypeA, + IDFields: &domain.RecordIdentifier{ + Data: scw.StringPtr("3.3.3.3"), + Name: "me", + Type: domain.RecordTypeA, + }, }, }, { Delete: &domain.RecordChangeDelete{ - Data: "1.1.1.1", - Name: "here", - Type: domain.RecordTypeA, + IDFields: &domain.RecordIdentifier{ + Data: scw.StringPtr("1.1.1.1"), + Name: "here", + Type: domain.RecordTypeA, + }, }, }, { Delete: &domain.RecordChangeDelete{ - Data: "1.1.1.2", - Name: "here", - Type: domain.RecordTypeA, + IDFields: &domain.RecordIdentifier{ + Data: scw.StringPtr("1.1.1.2"), + Name: "here", + Type: domain.RecordTypeA, + }, }, }, }, @@ -355,23 +361,29 @@ func TestScalewayProvider_generateApplyRequests(t *testing.T) { }, { Delete: &domain.RecordChangeDelete{ - Data: "1.1.1.1", - Name: "here.is.my", - Type: domain.RecordTypeA, + IDFields: &domain.RecordIdentifier{ + Data: scw.StringPtr("1.1.1.1"), + Name: "here.is.my", + Type: domain.RecordTypeA, + }, }, }, { Delete: &domain.RecordChangeDelete{ - Data: "4.4.4.4", - Name: "my", - Type: domain.RecordTypeA, + IDFields: &domain.RecordIdentifier{ + Data: scw.StringPtr("4.4.4.4"), + Name: "my", + Type: domain.RecordTypeA, + }, }, }, { Delete: &domain.RecordChangeDelete{ - Data: "5.5.5.5", - Name: "my", - Type: domain.RecordTypeA, + IDFields: &domain.RecordIdentifier{ + Data: scw.StringPtr("5.5.5.5"), + Name: "my", + Type: domain.RecordTypeA, + }, }, }, }, @@ -488,7 +500,7 @@ func checkScalewayReqChanges(r1, r2 *domain.UpdateDNSZoneRecordsRequest) bool { if c1.Add != nil && c2.Add != nil && checkScalewayRecords(c1.Add.Records, c2.Add.Records) { total-- } else if c1.Delete != nil && c2.Delete != nil { - if c1.Delete.Data == c2.Delete.Data && c1.Delete.Name == c2.Delete.Name && c1.Delete.Type == c2.Delete.Type { + if *c1.Delete.IDFields.Data == *c2.Delete.IDFields.Data && c1.Delete.IDFields.Name == c2.Delete.IDFields.Name && c1.Delete.IDFields.Type == c2.Delete.IDFields.Type { total-- } } From cece24dbc84632eb68b80d882c6600fe5ef7c9f5 Mon Sep 17 00:00:00 2001 From: Patrik Cyvoct Date: Thu, 28 Jan 2021 17:09:38 +0100 Subject: [PATCH 051/175] Use AdjustEndpoint method for Scaleway DNS Signed-off-by: Patrik Cyvoct --- provider/scaleway/scaleway.go | 26 ++++++++- provider/scaleway/scaleway_test.go | 84 ++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/provider/scaleway/scaleway.go b/provider/scaleway/scaleway.go index 66f505ced..12cbf1620 100644 --- a/provider/scaleway/scaleway.go +++ b/provider/scaleway/scaleway.go @@ -84,6 +84,21 @@ func NewScalewayProvider(ctx context.Context, domainFilter endpoint.DomainFilter }, nil } +// AdjustEndpoints is used to normalize the endoints +func (p *ScalewayProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) []*endpoint.Endpoint { + eps := make([]*endpoint.Endpoint, len(endpoints)) + for i := range endpoints { + eps[i] = endpoints[i] + if !eps[i].RecordTTL.IsConfigured() { + eps[i].RecordTTL = endpoint.TTL(scalewyRecordTTL) + } + if _, ok := eps[i].GetProviderSpecificProperty(scalewayPriorityKey); !ok { + eps[i] = eps[i].WithProviderSpecific(scalewayPriorityKey, fmt.Sprintf("%d", scalewayDefaultPriority)) + } + } + return eps +} + // Zones returns the list of hosted zones. func (p *ScalewayProvider) Zones(ctx context.Context) ([]*domain.DNSZone, error) { res := []*domain.DNSZone{} @@ -192,6 +207,7 @@ func (p *ScalewayProvider) generateApplyRequests(ctx context.Context, changes *p recordsToDelete[zoneName] = []*domain.RecordChange{} } + log.Debugf("Following records present in updateOld") for _, c := range changes.UpdateOld { zone, _ := zoneNameMapper.FindZone(c.DNSName) if zone == "" { @@ -199,8 +215,10 @@ func (p *ScalewayProvider) generateApplyRequests(ctx context.Context, changes *p continue } recordsToDelete[zone] = append(recordsToDelete[zone], endpointToScalewayRecordsChangeDelete(zone, c)...) + log.Debugf("%s", c.String()) } + log.Debugf("Following records present in delete") for _, c := range changes.Delete { zone, _ := zoneNameMapper.FindZone(c.DNSName) if zone == "" { @@ -208,8 +226,10 @@ func (p *ScalewayProvider) generateApplyRequests(ctx context.Context, changes *p continue } recordsToDelete[zone] = append(recordsToDelete[zone], endpointToScalewayRecordsChangeDelete(zone, c)...) + log.Debugf("%s", c.String()) } + log.Debugf("Following records present in create") for _, c := range changes.Create { zone, _ := zoneNameMapper.FindZone(c.DNSName) if zone == "" { @@ -217,7 +237,10 @@ func (p *ScalewayProvider) generateApplyRequests(ctx context.Context, changes *p continue } recordsToAdd[zone].Records = append(recordsToAdd[zone].Records, endpointToScalewayRecords(zone, c)...) + log.Debugf("%s", c.String()) } + + log.Debugf("Following records present in updateNew") for _, c := range changes.UpdateNew { zone, _ := zoneNameMapper.FindZone(c.DNSName) if zone == "" { @@ -225,6 +248,7 @@ func (p *ScalewayProvider) generateApplyRequests(ctx context.Context, changes *p continue } recordsToAdd[zone].Records = append(recordsToAdd[zone].Records, endpointToScalewayRecords(zone, c)...) + log.Debugf("%s", c.String()) } for _, zone := range dnsZones { @@ -310,10 +334,10 @@ func endpointToScalewayRecordsChangeDelete(zoneName string, ep *endpoint.Endpoin } func logChanges(req *domain.UpdateDNSZoneRecordsRequest) { - log.Infof("Updating zone %s", req.DNSZone) if !log.IsLevelEnabled(log.InfoLevel) { return } + log.Infof("Updating zone %s", req.DNSZone) for _, change := range req.Changes { if change.Add != nil { for _, add := range change.Add.Records { diff --git a/provider/scaleway/scaleway_test.go b/provider/scaleway/scaleway_test.go index 3db50301b..c9ca99112 100644 --- a/provider/scaleway/scaleway_test.go +++ b/provider/scaleway/scaleway_test.go @@ -158,6 +158,90 @@ func TestScalewayProvider_NewScalewayProvider(t *testing.T) { } } +func TestScalewayProvider_AdjustEndpoints(t *testing.T) { + provider := &ScalewayProvider{} + + before := []*endpoint.Endpoint{ + { + DNSName: "one.example.com", + RecordTTL: 300, + RecordType: "A", + Targets: []string{"1.1.1.1"}, + ProviderSpecific: endpoint.ProviderSpecific{ + { + Name: scalewayPriorityKey, + Value: "0", + }, + }, + }, + { + DNSName: "two.example.com", + RecordTTL: 0, + RecordType: "A", + Targets: []string{"1.1.1.1"}, + ProviderSpecific: endpoint.ProviderSpecific{ + { + Name: scalewayPriorityKey, + Value: "10", + }, + }, + }, + { + DNSName: "three.example.com", + RecordTTL: 600, + RecordType: "A", + Targets: []string{"1.1.1.1"}, + ProviderSpecific: endpoint.ProviderSpecific{}, + }, + } + + expected := []*endpoint.Endpoint{ + { + DNSName: "one.example.com", + RecordTTL: 300, + RecordType: "A", + Targets: []string{"1.1.1.1"}, + ProviderSpecific: endpoint.ProviderSpecific{ + { + Name: scalewayPriorityKey, + Value: "0", + }, + }, + }, + { + DNSName: "two.example.com", + RecordTTL: 300, + RecordType: "A", + Targets: []string{"1.1.1.1"}, + ProviderSpecific: endpoint.ProviderSpecific{ + { + Name: scalewayPriorityKey, + Value: "10", + }, + }, + }, + { + DNSName: "three.example.com", + RecordTTL: 600, + RecordType: "A", + Targets: []string{"1.1.1.1"}, + ProviderSpecific: endpoint.ProviderSpecific{ + { + Name: scalewayPriorityKey, + Value: "0", + }, + }, + }, + } + + after := provider.AdjustEndpoints(before) + for i := range after { + if !checkRecordEquality(after[i], expected[i]) { + t.Errorf("got record %s instead of %s", after[i], expected[i]) + } + } +} + func TestScalewayProvider_Zones(t *testing.T) { mocked := mockScalewayDomain{nil} provider := &ScalewayProvider{ From 94b86178897b754c0b0e0cf0d14eac6db5f5359b Mon Sep 17 00:00:00 2001 From: Dave Salisbury Date: Thu, 25 Feb 2021 17:49:16 +1100 Subject: [PATCH 052/175] pdns: create one endpoint per-rrset not one per-record If you had an RRSet that contained multiple records, the provider would end up generating multiple endpoints where really it needs to produce a single endpoint with multiple targets. --- provider/pdns/pdns.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/provider/pdns/pdns.go b/provider/pdns/pdns.go index 8ecd9d823..a609b281e 100644 --- a/provider/pdns/pdns.go +++ b/provider/pdns/pdns.go @@ -257,13 +257,16 @@ func NewPDNSProvider(ctx context.Context, config PDNSConfig) (*PDNSProvider, err func (p *PDNSProvider) convertRRSetToEndpoints(rr pgo.RrSet) (endpoints []*endpoint.Endpoint, _ error) { endpoints = []*endpoint.Endpoint{} + var targets = []string{} for _, record := range rr.Records { // If a record is "Disabled", it's not supposed to be "visible" if !record.Disabled { - endpoints = append(endpoints, endpoint.NewEndpointWithTTL(rr.Name, rr.Type_, endpoint.TTL(rr.Ttl), record.Content)) + targets = append(targets, record.Content) } } + + endpoints = append(endpoints, endpoint.NewEndpointWithTTL(rr.Name, rr.Type_, endpoint.TTL(rr.Ttl), targets...)) return endpoints, nil } From f4a1b675a9b9f6cb64b04a47c746b27616c9e07d Mon Sep 17 00:00:00 2001 From: Dave Salisbury Date: Thu, 25 Feb 2021 17:49:20 +1100 Subject: [PATCH 053/175] pdns_test: update multiple/mixed record expected values --- provider/pdns/pdns_test.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/provider/pdns/pdns_test.go b/provider/pdns/pdns_test.go index cfd0b099b..4fc2dc61a 100644 --- a/provider/pdns/pdns_test.go +++ b/provider/pdns/pdns_test.go @@ -125,17 +125,13 @@ var ( endpoint.NewEndpointWithTTL("does.not.exist.com", endpoint.RecordTypeTXT, endpoint.TTL(300), "\"heritage=external-dns,external-dns/owner=tower-pdns\""), } endpointsMultipleRecords = []*endpoint.Endpoint{ - endpoint.NewEndpointWithTTL("example.com", endpoint.RecordTypeA, endpoint.TTL(300), "8.8.8.8"), - endpoint.NewEndpointWithTTL("example.com", endpoint.RecordTypeA, endpoint.TTL(300), "8.8.4.4"), - endpoint.NewEndpointWithTTL("example.com", endpoint.RecordTypeA, endpoint.TTL(300), "4.4.4.4"), + endpoint.NewEndpointWithTTL("example.com", endpoint.RecordTypeA, endpoint.TTL(300), "8.8.8.8", "8.8.4.4", "4.4.4.4"), } endpointsMixedRecords = []*endpoint.Endpoint{ endpoint.NewEndpointWithTTL("cname.example.com", endpoint.RecordTypeCNAME, endpoint.TTL(300), "example.by.any.other.name.com"), endpoint.NewEndpointWithTTL("example.com", endpoint.RecordTypeTXT, endpoint.TTL(300), "'would smell as sweet'"), - endpoint.NewEndpointWithTTL("example.com", endpoint.RecordTypeA, endpoint.TTL(300), "8.8.8.8"), - endpoint.NewEndpointWithTTL("example.com", endpoint.RecordTypeA, endpoint.TTL(300), "8.8.4.4"), - endpoint.NewEndpointWithTTL("example.com", endpoint.RecordTypeA, endpoint.TTL(300), "4.4.4.4"), + endpoint.NewEndpointWithTTL("example.com", endpoint.RecordTypeA, endpoint.TTL(300), "8.8.8.8", "8.8.4.4", "4.4.4.4"), } endpointsMultipleZones = []*endpoint.Endpoint{ From 2f220603a430d6bf0744b0628a8149b91b589903 Mon Sep 17 00:00:00 2001 From: Kundan Kumar Date: Fri, 26 Feb 2021 13:56:13 +0530 Subject: [PATCH 054/175] update external-dns image versiona nd ingress api version --- docs/tutorials/akamai-edgedns.md | 4 ++-- docs/tutorials/alb-ingress.md | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/tutorials/akamai-edgedns.md b/docs/tutorials/akamai-edgedns.md index c817aa137..09b4478f3 100644 --- a/docs/tutorials/akamai-edgedns.md +++ b/docs/tutorials/akamai-edgedns.md @@ -61,7 +61,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.5 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # or ingress or both - --provider=akamai @@ -145,7 +145,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.5 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # or ingress or both - --provider=akamai diff --git a/docs/tutorials/alb-ingress.md b/docs/tutorials/alb-ingress.md index eb7a19139..0d818ac54 100644 --- a/docs/tutorials/alb-ingress.md +++ b/docs/tutorials/alb-ingress.md @@ -75,7 +75,7 @@ type `LoadBalancer` here, since we will be using an Ingress to create an ALB. Create the following Ingress to expose the echoserver application to the Internet. ```yaml -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: @@ -110,7 +110,7 @@ this Ingress object will only be fronting one backend Service, we might instead create the following: ```yaml -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: @@ -145,7 +145,7 @@ and one AAAA record) for each hostname associated with the Ingress object. Example: ```yaml -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: From 7c82d15f3320a1ec25f8f9fc2a96533493840e48 Mon Sep 17 00:00:00 2001 From: Raffaele Di Fazio Date: Wed, 3 Mar 2021 09:40:30 +0100 Subject: [PATCH 055/175] Delete CHANGELOG.md --- CHANGELOG.md | 571 --------------------------------------------------- 1 file changed, 571 deletions(-) delete mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 9b99a6114..000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,571 +0,0 @@ -## Unreleased - -- Add quick start section to contributing docs (#1766) @seanmalloy -- Enhance pull request template @seanmalloy -- Improve errors context for AWS provider -- Scaleway Provider (#1643) @Sh4d1 -- Enable azure_private_dns to work with non "AzurePublicCloud" clouds (#1578) @daddonpa -- Fix typos in documentation @ddymko -- Add Cloudflare documentation on use of `--zone-id-filter` (#1751) @loozhengyuan -- Fix: alibaba cloud keeping create record (#1682) @LXM -- Update all container registry references to use k8s.gcr.io @seanmalloy -- Provide available prometheus metrics in documentation @vinny-sabatini -- Fix index out of range when hostname has no dots (#1756) @chemasan -- Fixes test coverage with coveralls (#1755) @jgrumboe -- Add tutorial for GKE with workload identity (#1765) @ddgenome -- Fix NodePort with externaltrafficpolicy targets duplication @codearky -- Update contributing section in README (#1760) @seanmalloy -- Option to cache AWS zones list @bpineau -- Refactor, enhance and test Akamai provider and documentation (#1846) @edglynes -- Fix: only use absolute CNAMEs in Scaleway provider (#1859) @Sh4d1 -- Change Scaleway DNS API version from v2alpha2 to v2beta1 (#1938) @Sh4d1 - -## v0.7.3 - 2020-08-05 - -- Fix: add serviceaccount name in kustomize deployment (#1689) @jmthvt -- Updates Oracle OCI SDK to latest (#1687) @ericrrath -- UltraDNS Provider (#1635) @kbhandari -- Update apiVersions in docs (#1690) @ddgenome -- use the github actions build status badge (#1702) @tariq1890 -- Upgrade Oracle OCI SDK (#1688) @ericrrath -- update dependencies and minor dep tree cleanup (#1692) @tariq1890 -- Update link for linode cloud manager (#1661) @phillc -- Remove occurrences of "master" from the project (#1636) @Raffo -- Create pull_request_template (#1662) @njuettner -- dependencies: Upgrade all k8s client-go dependent sources to v1.18.X (#1627) @josephglanville -- add GitHub Actions (#1657) @Raffo -- add new source for istio virtual services (#1607) @tariq1890 -- use latest Alpine version in ExternalDNS dockerfile (#1655) @tariq1890 -- Update TTL docs to confirm DNSimple support (#1547) @weppos -- rm unused flag param istio-ingressgateways (#1649) @tariq1890 -- Upgrade istio httpbin from 1.0 to 1.6 version (#1640) @ikovnatskymiacar -- Add endpoints to kustomize base (#1638) @Raffo -- DigitalOcean: support multiple targets per endpoint (#1595) @tdyas -- Vultr : Version bump + changes (#1637) @ddymko -- Hetzner DNS service support (#1570) @21h -- Add OVH API rate limiting option (Fix #1546) (#1619) @Hugome -- Add kustomize base (#1631) @Raffo -- increase test timeout to fix intermittent failures of ingress tests (#1612) @tdyas -- AWS: change the order of the actions, DELETE before CREATE fixes #1411 (#1555) @OmerKahani -- Fix handling of DNS updates for RFC2136 provider. (#1613) @dmayle -- digitalocean: increase API page size (#1611) @tdyas -- improve linter quality for external-dns (#1618) @njuettner -- fix convert int to string bug (#1620) @tariq1890 - -## v0.7.2 - 2020-06-03 - -- Update blogpost in README (#1610) @vanhumbeecka -- Support for AWS Route53 in China (#1603) @greenu -- Update Govcloud provider hosted zones (#1592) @clhuang -- Fix issue with too large DNS messages (#1590) @dmayle -- use the latest linode go version (#1587) @tariq1890 -- use istio client-go and clean up k8s deps (#1584) @tariq1890 -- Add owners for cloudflare and coredns providers (#1582) @Raffo -- remove some code duplication in gateway source (#1575) @tariq1890 -- update Contour IngressRoute deps (#1569) @stevesloka -- Make tests faster (#1568) @sheerun -- Fix scheduling of reconciliation (#1567) @sheerun -- fix minor typos in istio gateway source docs (#1566) @tariq1890 -- Provider structure refactor (#1565) @Raffo -- Fix typo in ttl.md (#1564) @rtnpro -- Fix goreportcard warnings (#1561) @squat -- Use consistent headless service name in example (#1559) @lowkeyliesmyth -- Update go versions to 1.14.x that were missed in commit 99cebfcf from PR #1476 (#1554) @stealthybox -- Remove duplicate selector from DigitalOcean manifest (#1553) @ggordan -- Upgrade DNSimple client and add support for contexts (#1551) @weppos -- Upgrade github.com/miekg/dns to v1.1.25 (#1545) @davidcollom -- Fix updates in CloudFlare provider (#1542) @sheerun -- update readme for latest version (#1539) @elsesiy -- Improve Cloudflare tests in preparation to fix other issues (#1537) @sheerun -- Allow for custom property comparators (#1536) @sheerun -- fix typo (#1535) @tmatias -- Bump github.com/pkg/errors from 0.8.1 to 0.9.1 (#1531) @njuettner -- Bump github.com/digitalocean/godo from 1.19.0 to 1.34.0 (#1530) @njuettner -- Bump github.com/prometheus/client_golang from 1.0.0 to 1.5.1 (#1529) @njuettner -- Bump github.com/akamai/AkamaiOPEN-edgegrid-golang from 0.9.10 to 0.9.11 (#1528) @njuettner -- Fix RFC2316 Windows Documentation (#1516) @scottd018 -- remove dependency on kubernetes/kubernetes (#1513) @tariq1890 -- update akamai openapi dependency (#1511) @tariq1890 -- Vultr Provider (#1509) @ddymko -- Add AWS region ap-east-1(HK) (#1497) @lovemai073 -- Fix: file coredns.go is not `goimports`-ed (#1496) @njuettner -- Allow ZoneIDFilter for Cloudflare (#1494) @james-callahan -- update etcd dependency to latest version (#1485) @tariq1890 -- Support for openshift routes (#1484) @jgrumboe -- add --txt-suffix feature (#1483) @jgrumboe -- update to go 1.14 (#1476) @jochen42 -- Multiple A records support for the same FQDN (#1475) @ytsarev -- Implement annotation filter for CRD source (#1399) @ytsarev - -## v0.7.1 - 2020-04-01 - - - Prometheus metric: timestamp of last successful sync with the DNS provider (#1480) @njuettner - - Bump alpine base image to 3.11.5 (#1477) @Annegies - - Docs: Add first maintainers in list (#1472) @Raffo - - Fix DomainFilter type in OVH provider (#1469) @ytsarev - - New provider: OVH (#1439) @Hugome - -## v0.7.0 - 2020-03-10 - - - New source: Add support for Skipper's RouteGroup CRD (#1444) @szuecs - - Change DomainFilter to apply to records as well (#1442) @bl1nk - - Docs: Update docker image references of ExternalDNS (#1427) @tariq1890 - - Remove duplicate targets from endpoints for headless services (#1426) @thomasv314 - - Add issue templates to Github (#1424) @njuettner - - Azure: Don't use SPN to authenticate when clientid or secret is 'msi' (#1422) @norshtein - - Rfc2136: Add option to define minimum TTL (#1412) @ouzklcn - - Azure Private DNS: Fix updates of unchanged records (#1377) @jasper-d - - Headless service: Retrieve endpoints via Endpoints resource (#1005) @devkid - -## v0.6.0 - 2020-02-11 - - - Azure Private DNS: Fix endless loop in zone-detection (#1397) @saidst - - Uprade golangci-lint and add megacheck & interface linters (#1390) @tariq1890 - - Update alpine base image to 3.11 (#1387) @tariq1890 - - New provider: Akamai FastDNS (#1384) @KarstenSiemer - - Docs: Fix broken links (#1382) @ttonline6 - - Docs: Fix broken links (#1381) @ttonline6 - - Docs: Update AWS documentation (#1380) @otterley - - Docs: istio.md: update existing external-dns to enable Istio Gateway DNS for customers (#1378) @marcellodesales - - Remove context.TODO()s in external-dns (#1374) @tariq1890 - - Docs: add region for aws-sd external-dns deployment (#1367) @guitarrapc - - Docs: a how-to of a working GCP GKE app demo (#1365) @jpantsjoha - - Add ctx parameter to provider interface and AWS API (#1364) @tariq1890 - - Add version to binary for --version flag (#1361) @linki - - Update aws sdk dep and golangci-lint release (#1360) @tariq1890 - - Add support for human-friendly TTL values (#1237) @hypnoglow - - Change ApplyChanges in RFC2136 to batch update (#1164) @h3ndrk - - Add --watchers flag to allow controller to respond automatically to Ingress or Service updates (#687) @jlamillan - -## v0.5.18 - 2020-01-09 - - - Use correct link to contributors guide (#1349) @szuecs - - AWS-SD: Rebrand AWS Auto Naming to Cloud Map (#1348) @vanekjar - - Add more linters and improve code quality (#1347) @tariq1890 - - Suppress noisy logging of klog (#1344) @saidst - - Update VinylDNS documentation (#1342) @dgrizzanti - - Remove incubator references in README (#1341) @Raffo - - Rename project root package to sigs.k8s.io (#1334) @tariq1890 - - Add CRD documentation and fix samples (#1332) @ytsarev - - Add support for multiple Istio ingress gateways (#1328) @ashleyschuett - - Enable image publishing to gcr.io via cloudbuild (#1326) @njuettner - - Corrected a typo in the Readme (#1323) @drewhemm - - Rework tutorial for Azure Private DNS (#1319) @saidst - - Correct typos and superflous spaces in the provider code (#1315) @stensonb - - Add missing bracket in CLI help output (#1308) @ekeih - - Add missing service account to deployment spec in the docs (#1305) @linki - - Bump the version of golangci-lint (#1296) @njuettner - - Fix broken link of ingress-gce and ingress-nginx (#1290) @sivanzcw - - Use apps/v1 for the deployment to be compatible with Kubernetes 1.16 (#1279) @scholzj - - Normalize function return and comments on exported type (#1277) @sivanzcw - - Use non-deprecated initializer with go context (#1271) @linki - - Fix several golint errors (#1270) @bysph - - Add Azure Private DNS Provider (#1269) @saidst - - Fix tutorial for kubernetes 1.16+ (#1268) @yujunz - - Add me-south region to list of canonical hosted zones (#1266) @poweroftrue - - Add gov region to list of canonical hosted zones (#1260) @helgi - - Update broken links to RDNS (#1259) @Slach - - Designate: add snippet for RBAC environment (#1254) @bavarianbidi - - Fix log-level parameter in tutorials (#1253) @bavarianbidi - - Improve RFC2136 documentation (#1251) @alex-orange - - Google Provider: Add support for batching updates (#1248) @vdesjardins - - Azure: add support for specifying user assigned identity's clientID to authenticate (#1247) @norshtein - - Automatically add provider labels on pull requests via Github actions (#1242) @njuettner - - Improve documentation for nginx ingress controller on AWS (#1234) @PiotrJander - - Use apps/v1 instead of extensions/v1beta1 in Deployment examples (#1225) @reegnz - - Add documentation to make the use of namespaces clearer (#1223) @dgrizzanti - - Add support for using Nodes as Source (#1218) @skoef - - Add missing RBAC permissions for the ServiceAccount in the docs (#1206) @dooman87 - - Upgrade client-go + azure sdk (#1195) @timja - - RFC2136: Add support for batching updates (#1164) @h3ndrk - - Fix confusing arrow direction in the Azure tutorial (#1163) @adipascu - - Route53: Add RBAC manifest and update wording around IAM policy (#1149) @dkeightley - - Route53: Add support for all AWS Route53 routing policies; add additional Setldentifier abstraction layer (#1008) @devkid - -## v0.5.17 - 2019-09-17 - - - Exoscale: add context support (#1193) @greut - - Cloudflare: Support API Token Auth (#1189) @Evesy - - AWS: Fix IAM Roles for Service Accounts permission problem (#1185) @serialx - - Core: Upgrade go version to 1.13 in external-dns (#1184) @tariq1890 - - AWS: Update the AWS SDK to support Web Identity providers for IAM credentials (#1182) @MarcusNoble - - Docs: Update rfc2136 tutorial for use with Microsoft DNS (#1178) @bjschafer - - AWS: Update the AWS go SDK to support AWS IAM for Service Accounts (#1172) @micahhausler - - AWS-SD: Add support for AWS Network Load Balancers (#1170) @vanekjar - - Core: Add create-only policy (#1160) @danieldabate - - AWS: Fix --aws-api-retries (#1158) @coreypobrien - - Source: Support delegate Heptio Contour IngressRoutes (#1144) @jonasrmichel - - Core: TXTRegistry: do not overwrite labels of records returned by the provider (#1136) @multi-io - - Infoblox: Fixing incorrect match of zone dns names (#1128) @gregsidelinger - - Source: Improvements to the source CRD (#1107) @JoaoBraveCoding - - Core: Fix txt prefix bug (#1013) @p53 - -## v0.5.16 - 2019-08-16 - - - Fix flaky unit test in provider package (#1151) @tariq1890 - - Dockerfile: Update version of base images (#1148) @tariq1890 - - DigitalOcean: Update `godo` to the latest stable version (#1145) @tariq1890 - - Fix build pipeline for Go v1.13 (#1142) @linki - - AWS: Add Hosted Zone ID to logging output (#1129) @helgi - - IstioGateway: Support namespaces on hostnames (#1124) @dcherman - - AWS: Document `--prefer-cname` flag (#1123) @dbluxo - - Add Tutorial for DNSimple provider (#1121) @marc-sensenich - - Update Go version and golangci-lint to the latest release (#1120) @njuettner - - Allow compilation on 32bit machines (#1116) @mylesagray - - AWS: Allow to force usage of CNAME over ALIAS (#1103) @linki - - CoreDNS: add option to specify prefix name (#1102) @xunpan - - New provider: Rancher DNS (RDNS) (#1098) @Jason-ZW - - Document where e2e tests are currently located (#1094) @jaypipes - - Add initial KEP for ExternalDNS (#1092) @Raffo - - Update Dockerfiles to follow best practices (#1091) @taharah - - New Source: Heptio Contour IngressRoute (#1084) @jonasrmichel - - AWS: Add dualstack support with ALB ingress controllers (#1079) @twilfong - - Allow handling of multiple Oracle Cloud (OCI) zones (#1061) @suman-ganta - - Namespace exposed metrics with the external_dns prefix (#794) @linki - -## v0.5.15 - 2019-07-03 - - - RFC2136: Fix when merging multiple targets (#1082) @hachh - - New provider VinylDNS (#1080) @dgrizzanti - - Core: Fix for DomainFilter exclusions (#1059) @cmattoon - - Core: Update aws-go-sdk to be compatible with kube-aws-iam-controller (#1054) @mikkeloscar - - RFC2136: Log RR adds/deletes as Info (#1041) @gclawes - - Docs: Cloudflare set ttl annotation for proxied entries to 1 (#1039) @MiniJerome - - Core: Install ca-certificates (#1038) @dryewo - - Cloudflare: Fix provider to return a single endpoint for each name/type (#1034) @shasderias - - Core: Sanitize dockerfiles for external-dns (#1033) @tariq1890 - - Core: Add empty source (#1032) @anandkumarpatel - - Google: Zones should be filter by their ID and Name (#1031) @simonswine - - Core: Fix panic on empty targets for custom resources (#1029) @arturo-c - - Core: Support externalTrafficPolicy annotation with "local" mode for NodePort service (#1023) @yverbin - - Core: Add support for ExternalName services (#1018) @mironov - -## v0.5.14 - 2019-05-14 - - - Docs: Update aws.md (#1009) @pawelprazak - - New provider TransIP (#1007) @skoef - - Docs: Add docker image faq (#1006) @Raffo - - DNSimple: Support apex records (#1004) @jbowes - - NS1: Add --ns1-endpoint and --ns1-ignoressl flags (#1002) @mburtless - - AWS: Cache the endpoints on the controller loop (#1001) @fraenkel - - Core: Supress Kubernetes logs (#991) @njuettner - - Core: distroless/static image (#989) @jharshman - - Core: Headless service missing DNS entry (#984) @yverbin - - New provider NS1 (#963) @mburtless - - Core: Add Cloud Foundry routes as a source (#955) @dgrizzanti - -## v0.5.13 - 2019-04-18 - - - Azure: Support multiple A targets (#987) @michaelfig - - Core: Fixing what seems an obvious omission of /github.com/ dir in Dockerfile (#985) @llamahunter - - Docs: GKE tutorial remove disable-addon argument (#978) @ggordan - - Docs: Alibaba Cloud config file missing by enable sts token (#977) @xianlubird - - Docs: Alibaba Cloud fix wrong arg in manifest (#976) @iamzhout - - AWS: Set a default TTL for Alias records (#975) @fraenkel - - Cloudflare: Add support for multiple target addresses (#970) @nta - - AWS: Adding China ELB endpoints and hosted zone id's (#968) @jfillo - - AWS: Streamline ApplyChanges (#966) @fraenkel - - Core: Switch to go modules (#960) @njuettner - - Docs: AWS how to check if your cluster has a RBAC (#959) @confiq - - Docs: AWS remove superfluous trailing period from hostname (#952) @hobti01 - - Core: Add generic logic to remove secrets from logs (#951) @dsbrng25b - - RFC2136: Remove unnecessary parameter (#948) @ChristianMoesl - - Infoblox: Reduce verbosity of logs (#945) @dsbrng25b - -## v0.5.12 - 2019-03-26 - - - Bumping istio to 1.1.0 (#942) @venezia - - Docs: Added stability matrix and minor improvements to README (#938) @Raffo - - Docs: Added a reference to a blogpost which uses ExternalDNS in a CI/CD setup (#928) @vanhumbeecka - - Use k8s informer cache instead of making active API GET requests (#917) @jlamillan - - Docs: Tiny clarification about two available deployment methods (#935) @przemolb - - Add support for multiple Istio IngressGateway LoadBalancer Services (#907) @LorbusChris - - Set log level to debug when axfr is disabled (#932) @arief-hidayat - - Infoblox provider support for DNS view (#895) @dsbrng25b - - Add RcodeZero Anycast DNS provider (#874) @dklesev - - Docs: Dropping owners (#929) @njuettner - - Docs: Added description for multiple dns name (#911) @st1t - - Docs: Clarify that hosted zone identifier is to be used (#915) @dirkgomez - - Docs: Make dep step which may be needed to run make build (#913) @dirkgomez - - PowerDNS: Fixed Domain Filter Bug (#827) @anandsinghkunwar - - Allow hostname annotations to be ignored (#745) @anandkumarpatel - - RFC2136: Fixed typo in debug output (#899) @hpandeycodeit - -## v0.5.11 - 2019-02-11 - - - Fix constant updating issue introduced with v0.5.10 (#886) @jhohertz - - Ignore evaluate target health for calculating changes for AWS (#880) @linki - - Pagination for cloudflare zones (#873) @njuettner - -## v0.5.10 - 2019-01-28 - - - Docs: Improve documentation regarding Alias (#868) @alexnederlof - - Adds a new flag `--aws-api-retries` which allows overriding the number of retries (#858) @viafoura - - Docs: Make awscli commands use JSON output (#849) @ifosch - - Docs: Add missing apiVersion to Ingress resource (#847) @shlao - - Fix for AWS private DNS zone (#844) @xianlubird - - Add support for AWS ELBs in eu-north-1 (#843) @argoyle - - Create a SECURITY_CONTACTS file (#842) @njuettner - - Use correct product name for Google Cloud DNS (#841) @seils - - Change default AWSBatchChangeSize to 1000 (#839) @medzin - - Fix dry-run mode in rfc2136 provider (#838) @lachlancooper - - Fix typos in rfc2136 provider (#837) @lachlancooper - - rfc2136 provider: one IP Target per RRSET (#836) @ivanfilippov - - Normalize DNS names during planning (#833) @justinsb - - Implement Stringer for planTableRow (#832) @justinsb - - Docs: Better security granularity concerning external dns service principal for Azure (#829) @DenisBiondic - - Docs: Update links in Cloudflare docs (#824) @PascalKu - - Docs: Add metrics info to FAQ (#822) @zachyam - - Docs: Update nameserver IPs in coredns.md (#820) @mozhuli - - Docs: Fix commands to cleanup Cloudflare (#818) @acrogenesis - - Avoid unnecessary updating for CRD resource (#810) @xunpan - - Fix issues with CoreDNS provider and more than 1 targets (#807) @xunpan - - AWS: Add zone tag filter (#804) @csrwng - - Docs: Update CoreDNS tutorial with RBAC manifest (#803) @Lujeni - - Use SOAP API to improve DYN's provider's performance (#799) @sanyu - - Expose managed resources and records as metrics (#793) @linki - - Docs: Updating Azure tutorial (#788) @pelithne - - Improve errors in Records() of Infoblox provider (#785) @dsbrng25b - - Change default apiVersion of CRD Source (#774) @dsbrng25b - - Allow setting Cloudflare proxying on a per-Ingress basis (#650) @eswets - - Support A record for multiple IPs for headless services (#645) @toshipp - -## v0.5.9 - 2018-11-22 - - - Core: Update delivery.yaml to new format (#782) @linki - - Core: Adjust gometalinter timeout by setting env var (#778) @njuettner - - Provider **Google**: Panic assignment to entry in nil map (#776) @njuettner - - Docs: Fix typos (#769) @mooncak - - Docs: Remove duplicated words (#768) @mooncak - - Provider **Alibaba**: Alibaba Cloud Provider Fix Multiple Subdomains Bug (#767) @xianlubird - - Core: Add Traefik to the supported list of ingress controllers (#764) @coderanger - - Provider **Dyn**: Fix some typos in returned messages in dyn.go (#760) @AdamDang - - Docs: Update Azure documentation (#756) @pascalgn - - Provider **Oracle**: Oracle doc fix (add "key:" to secret) (#750) @CaptTofu - - Core: Docker MAINTAINER is deprecated - using LABEL instead (#747) @helgi - - Core: Feature add alias annotation (#742) @vaegt - - Provider **RFC2136**: Fix rfc2136 - setup fails issue and small docs (#741) @antlad - - Core: Fix nil map access of endpoint labels (#739) @shashidharatd - - Provider **PowerDNS**: PowerDNS Add DomainFilter support (#737) @ottoyiu - - Core: Fix domain-filter matching logic to not match similar domain names (#736) @ottoyiu - - Core: Matching entire string for wildcard in txt records with prefixes (#727) @etopeter - - Provider **Designate**: Fix TLS issue with OpenStack auth (#717) @FestivalBobcats - - Provider **AWS**: Add helper script to update route53 txt owner entries (#697) @efranford - - Provider **CoreDNS**: Migrate to use etcd client v3 for CoreDNS provider (#686) @shashidharatd - - Core: Create a non-root user to run the container process (#684) @coderanger - - Core: Do not replace TXT records with A/CNAME records in planner (#581) @jchv - -## v0.5.8 - 2018-10-11 - - - New Provider: RFC2136 (#702) @antlad - - Add Linode to list of supported providers (#730) @cliedeman - - Correctly populate target health check on existing records (#724) @linki - - Don't erase Endpoint labels (#713) @sebastien-prudhomme - -## v0.5.7 - 2018-09-27 - - - Pass all relevant CLI flags to AWS provider (#719) @linki - - Replace glog with a noop logger (#714) @linki - - Fix handling of custom TTL values with Google DNS. (#704) @kevinmdavis - - Continue even if node listing fails (#701) @pascalgn - - Fix Host field in HTTP request when using pdns provider (#700) @peterbale - - Allow AWS batching to fully sync on each run (#699) @bartelsielski - -## v0.5.6 - 2018-09-07 - - - Alibaba Cloud (#696) @xianlubird - - Add Source implementation for Istio Gateway (#694) @jonasrmichel - - CRD source based on getting endpoints from CRD (#657) @shashidharatd - - Add filter by service type feature (#653) @Devatoria - - Add generic metrics for Source & Registry Errors (#652) @wleese - -## v0.5.5 - 2018-08-17 - - - Configure req timeout calling k8s APIs (#681) @jvassev - - Adding assume role to aws_sd provider (#676) @lb-saildrone - - Dyn: cache records per zone using zone's serial number (#675) @jvassev - - Linode provider (#674) @cliedeman - - Cloudflare Link Language Specificity (#673) @christopherhein - - Retry calls to dyn on ErrRateLimited (#671) @jvassev - - Add support to configure TTLs on DigitalOcean (#667) @andrewsomething - - Log level warning option (#664) @george-angel - - Fix usage of k8s.io/client-go package (#655) @shashidharatd - - Fix for empty target annotation (#647) @rdrgmnzs - - Fix log message for #592 when no updates in hosted zones (#634) @audip - - Add aws-evaluate-target-health flag (#628) @peterbale - - Exoscale provider (#625) @FaKod @greut - - Oracle Cloud Infrastructure DNS provider (#626) @prydie - - Update DO CNAME type API request to prevent error 422 (#624) @nenadilic84 - - Fix typo in cloudflare.md (#623) @derekperkins - - Infoblox-go-client was only setting timeout for http.Transport.ResponseHeaderTimeout instead of for http.Client (#615) @khrisrichardson - - Adding a flag to optionally publish hostIP instead of podIP for headless services (#597) @Arttii - -## v0.5.4 - 2018-06-28 - - - Only store endpoints with their labels in the cache (#612) @njuettner - - Read hostnames from spec.tls.hosts on Ingress object (#611) @ysoldak - - Reorder provider/aws suitable-zones tests (#608) @elordahl - - Adds TLS flags for pdns provider (#607) @jhoch-palantir - - Update RBAC for external-dns to list nodes (#600) @njuettner - - Add aws max change count flag (#596) @peterbale - - AWS provider: Properly check suitable domains (#594) @elordahl - - Annotation with upper-case hostnames block further updates (#579) @njuettner - -## v0.5.3 - 2018-06-15 - - - Print a message if no hosted zones match (aws provider) (#592) @svend - - Add support for NodePort services (#559) @grimmy - - Update azure.md to fix protocol value (#593) @JasonvanBrackel - - Add cache to limit calls to providers (#589) @jessfraz - - Add Azure MSI support (#578) @r7vme - - CoreDNS/SkyDNS provider (#253) @istalker2 - -## v0.5.2 - 2018-05-31 - - - DNSimple: Make DNSimple tolerant of unknown zones (#574) @jbowes - - Cloudflare: Custom record TTL (#572) @njuettner - - AWS ServiceDiscovery: Implementation of AWS ServiceDiscovery provider (#483) @vanekjar - - Update docs to latest changes (#563) @Raffo - - New source - connector (#552) @shashidharatd - - Update AWS SDK dependency to v1.13.7 @vanekjar - -## v0.5.1 - 2018-05-16 - - - Refactor implementation of sync loop to use `time.Ticker` (#553) @r0fls - - Document how ExternalDNS gets permission to change AWS Route53 entries (#557) @hjacobs - - Fix CNAME support for the PowerDNS provider (#547) @kciredor - - Add support for hostname annotation in Ingress resource (#545) @rajatjindal - - Fix for TTLs being ignored on headless Services (#546) @danbondd - - Fix failing tests by giving linters more time to do their work (#548) @linki - - Fix misspelled flag for the OpenStack Designate provider (#542) @zentale - - Document additional RBAC rules needed to read Pods (#538) @danbondd - -## v0.5.0 - 2018-04-23 - - - Google: Correctly filter records that don't match all filters (#533) @prydie @linki - - AWS: add support for AWS Network Load Balancers (#531) @linki - - Add a flag that allows FQDN template and annotations to combine (#513) @helgi - - Fix: Use PodIP instead of HostIP for headless Services (#498) @nrobert13 - - Support a comma separated list for the FQDN template (#512) @helgi - - Google Provider: Add auto-detection of Google Project when running on GCP (#492) @drzero42 - - Add custom TTL support for DNSimple (#477) @jbowes - - Fix docker build and delete vendor files which were not deleted (#473) @njuettner - - DigitalOcean: DigitalOcean creates entries with host in them twice (#459) @njuettner - - Bugfix: Retrive all DNSimple response pages (#468) @jbowes - - external-dns does now provide support for multiple targets for A records. This is currently only supported by the Google Cloud DNS provider (#418) @dereulenspiegel - - Graceful handling of misconfigure password for dyn provider (#470) @jvassev - - Don't log sensitive data on start (#463) @jvassev - - Google: Improve logging to help trace misconfigurations (#388) @stealthybox - - AWS: In addition to the one best public hosted zone, records will be added to all matching private hosted zones (#356) @coreypobrien - - Every record managed by External DNS is now mapped to a kubernetes resource (service/ingress) @ideahitme - - New field is stored in TXT DNS record which reflects which kubernetes resource has acquired the DNS name - - Target of DNS record is changed only if corresponding kubernetes resource target changes - - If kubernetes resource is deleted, then another resource may acquire DNS name - - "Flapping" target issue is resolved by providing a consistent and defined mechanism for choosing a target - - New `--zone-id-filter` parameter allows filtering by zone id (#422) @vboginskey - - TTL annotation check for azure records (#436) @stromming - - Switch from glide to dep (#435) @bkochendorfer - -## v0.4.8 - 2017-11-22 - - - Allow filtering by source annotation via `--annotation-filter` (#354) @khrisrichardson - - Add support for Headless hostPort services (#324) @Arttii - - AWS: Added change batch limiting to a maximum of 4000 Route53 updates in one API call. Changes exceeding the limit will be dropped but all related changes by hostname are preserved within the limit. (#368) @bitvector2 - - Google: Support configuring TTL by annotation: `external-dns.alpha.kubernetes.io/ttl`. (#389) @stealthybox - - Infoblox: add option `--no-infoblox-ssl-verify` (#378) @khrisrichardson - - Inmemory: add support to specify zones for inmemory provider via command line (#366) @ffledgling - -## v0.4.7 - 2017-10-18 - - - CloudFlare: Disable proxy mode for TXT and others (#361) @dunglas - -## v0.4.6 - 2017-10-12 - - - [AWS Route53 provider] Support customization of DNS record TTL through the use of annotation `external-dns.alpha.kubernetes.io/ttl` on services or ingresses (#320) @kevinjqiu - - Added support for [DNSimple](https://dnsimple.com/) as DNS provider (#224) @jose5918 - - Added support for [Infoblox](https://www.infoblox.com/products/dns/) as DNS provider (#349) @khrisrichardson - -## v0.4.5 - 2017-09-24 - - - Add `--log-level` flag to control log verbosity and remove `--debug` flag in favour of `--log-level=debug` (#339) @ultimateboy - - AWS: Allow filtering for private and public zones via `--aws-zone-type` flag (#329) @linki - - CloudFlare: Add `--cloudflare-proxied` flag to toggle CloudFlare proxy feature (#340) @dunglas - - Kops Compatibility: Isolate ALIAS type in AWS provider (#248) @sethpollack - -## v0.4.4 - 2017-08-17 - - - ExternalDNS now services of type `ClusterIP` with the use of the `--publish-internal-services`. Enabling this will now create the apprioriate A records for the given service's internal ip. @jrnt30 - - Fix to have external target annotations on ingress resources replace existing endpoints instead of appending to them (#318) - -## v0.4.3 - 2017-08-10 - - - Support new `external-dns.alpha.kubernetes.io/target` annotation for Ingress (#312) - - Fix for wildcard domains in Route53 (#302) - -## v0.4.2 - 2017-08-03 - - - Fix to support multiple hostnames for Molecule Software's [route53-kubernetes](https://github.com/wearemolecule/route53-kubernetes) compatibility (#301) - -## v0.4.1 - 2017-07-28 - - - Fix incorrect order of constructor parameters (#298) - -## v0.4.0 - 2017-07-21 - - - ExternalDNS now supports three more DNS providers: - * [AzureDNS](https://azure.microsoft.com/en-us/services/dns) @peterhuene - * [CloudFlare](https://www.cloudflare.com/de/dns) @njuettner - * [DigitalOcean](https://www.digitalocean.com/products/networking) @njuettner - - Fixed a bug that prevented ExternalDNS to be run on Tectonic clusters @sstarcher - - ExternalDNS is now a full replace for Molecule Software's `route53-kubernetes` @iterion - - The `external-dns.alpha.kubernetes.io/hostname` annotation accepts now a comma separated list of hostnames and a trailing period is not required anymore. @totallyunknown - - The flag `--domain-filter` can be repeated multiple times like `--domain-filter=example.com --domain-filter=company.org.`. @totallyunknown - - A trailing period is not required anymore for `--domain-filter` when AWS (or any other) provider is used. @totallyunknown - - We added a FakeSource that generates random endpoints and allows to run ExternalDNS without a Kubernetes cluster (e.g. for testing providers) @ismith - - All HTTP requests to external APIs (e.g. DNS providers) generate client side metrics. @linki - - The `--zone` parameter was removed in favor of a provider independent `--domain-filter` flag. @linki - - All flags can now also be set via environment variables. @linki - -## v0.3.0 - 2017-05-08 - -Features: - - - Changed the flags to the v0.3 semantics, the following has changed: - 1. The TXT registry is used by default and has an owner ID of `default` - 2. `--dry-run` is disabled by default - 3. The `--compatibility` flag was added and takes a string instead of a boolean - 4. The `--in-cluster` flag has been dropped for auto-detection - 5. The `--zone` specifier has been replaced by a `--domain-filter` that filters domains by suffix - - Improved logging output - - Generate DNS Name from template for services/ingress if annotation is missing but `--fqdn-template` is specified - - Route 53, Google CloudDNS: Support creation of records in multiple hosted zones. - - Route 53: Support creation of ALIAS records when endpoint target is a ELB/ALB. - - Ownership via TXT records - 1. Create TXT records to mark the records managed by External DNS - 2. Supported for AWS Route53 and Google CloudDNS - 3. Configurable TXT record DNS name format - - Add support for altering the DNS record modification behavior via policies. - -## v0.2.0 - 2017-04-07 - -Features: - - - Support creation of CNAME records when endpoint target is a hostname. - - Allow omitting the trailing dot in Service annotations. - - Expose basic Go metrics via Prometheus. - -Documentation: - - - Add documentation on how to setup ExternalDNS for Services on AWS. - -## v0.1.1 - 2017-04-03 - -Bug fixes: - - - AWS Route 53: Do not submit request when there are no changes. - -## v0.1.0 - 2017-03-30 (KubeCon) - -Features: - - - Manage DNS records for Services with `Type=LoadBalancer` on Google CloudDNS. From fa857131c2c5a5c8b24dd9f74f5287beb69e1429 Mon Sep 17 00:00:00 2001 From: Brock Alberry <61976254+ba-work@users.noreply.github.com> Date: Wed, 3 Mar 2021 21:28:11 +0000 Subject: [PATCH 056/175] add krb5 realm support --- .gitignore | 3 +++ docs/tutorials/rfc2136.md | 3 ++- main.go | 2 +- pkg/apis/externaldns/types.go | 2 ++ provider/rfc2136/rfc2136.go | 4 ++-- provider/rfc2136/rfc2136_test.go | 2 +- 6 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 30adb371d..db4b5e4c8 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,6 @@ external-dns vendor/ profile.cov + +# github codespaces +.venv/ \ No newline at end of file diff --git a/docs/tutorials/rfc2136.md b/docs/tutorials/rfc2136.md index 10210dd91..aba5c0053 100644 --- a/docs/tutorials/rfc2136.md +++ b/docs/tutorials/rfc2136.md @@ -379,9 +379,10 @@ You'll want to configure `external-dns` similarly to the following: - --rfc2136-gss-tsig - --rfc2136-host=123.123.123.123 - --rfc2136-port=53 - - --rfc2136-zone=your-domain.com + - --rfc2136-zone=your-zone.com - --rfc2136-kerberos-username=your-domain-account - --rfc2136-kerberos-password=your-domain-password + - --rfc2136-kerberos-realm=your-domain.com - --rfc2136-tsig-axfr # needed to enable zone transfers, which is required for deletion of records. ... ``` \ No newline at end of file diff --git a/main.go b/main.go index 09860c08d..22613cf2f 100644 --- a/main.go +++ b/main.go @@ -283,7 +283,7 @@ func main() { p, err = oci.NewOCIProvider(*config, domainFilter, zoneIDFilter, cfg.DryRun) } case "rfc2136": - p, err = rfc2136.NewRfc2136Provider(cfg.RFC2136Host, cfg.RFC2136Port, cfg.RFC2136Zone, cfg.RFC2136Insecure, cfg.RFC2136TSIGKeyName, cfg.RFC2136TSIGSecret, cfg.RFC2136TSIGSecretAlg, cfg.RFC2136TAXFR, domainFilter, cfg.DryRun, cfg.RFC2136MinTTL, cfg.RFC2136GSSTSIG, cfg.RFC2136KerberosUsername, cfg.RFC2136KerberosPassword, nil) + p, err = rfc2136.NewRfc2136Provider(cfg.RFC2136Host, cfg.RFC2136Port, cfg.RFC2136Zone, cfg.RFC2136Insecure, cfg.RFC2136TSIGKeyName, cfg.RFC2136TSIGSecret, cfg.RFC2136TSIGSecretAlg, cfg.RFC2136TAXFR, domainFilter, cfg.DryRun, cfg.RFC2136MinTTL, cfg.RFC2136GSSTSIG, cfg.RFC2136KerberosUsername, cfg.RFC2136KerberosPassword, cfg.RFC2136KerberosRealm, nil) case "ns1": p, err = ns1.NewNS1Provider( ns1.NS1Config{ diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index b8d43f462..9aba7355c 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -144,6 +144,7 @@ type Config struct { RFC2136GSSTSIG bool RFC2136KerberosUsername string RFC2136KerberosPassword string + RFC2136KerberosRealm string RFC2136TSIGKeyName string RFC2136TSIGSecret string `secure:"yes"` RFC2136TSIGSecretAlg string @@ -436,6 +437,7 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("rfc2136-gss-tsig", "When using the RFC2136 provider, specify whether to use secure updates with GSS-TSIG using Kerberos (default: false, requires --rfc2136-kerberos-username and rfc2136-kerberos-password)").Default(strconv.FormatBool(defaultConfig.RFC2136GSSTSIG)).BoolVar(&cfg.RFC2136GSSTSIG) app.Flag("rfc2136-kerberos-username", "When using the RFC2136 provider with GSS-TSIG, specify the username of the user with permissions to update DNS records (required when --rfc2136-gss-tsig=true)").Default(defaultConfig.RFC2136KerberosUsername).StringVar(&cfg.RFC2136KerberosUsername) app.Flag("rfc2136-kerberos-password", "When using the RFC2136 provider with GSS-TSIG, specify the password of the user with permissions to update DNS records (required when --rfc2136-gss-tsig=true)").Default(defaultConfig.RFC2136KerberosPassword).StringVar(&cfg.RFC2136KerberosPassword) + app.Flag("rfc2136-kerberos-realm", "When using the RFC2136 provider with GSS-TSIG, specify the realm of the user with permissions to update DNS records (required when --rfc2136-gss-tsig=true)").Default(defaultConfig.RFC2136KerberosRealm).StringVar(&cfg.RFC2136KerberosRealm) // Flags related to TransIP provider app.Flag("transip-account", "When using the TransIP provider, specify the account name (required when --provider=transip)").Default(defaultConfig.TransIPAccountName).StringVar(&cfg.TransIPAccountName) diff --git a/provider/rfc2136/rfc2136.go b/provider/rfc2136/rfc2136.go index 611261160..643acab21 100644 --- a/provider/rfc2136/rfc2136.go +++ b/provider/rfc2136/rfc2136.go @@ -85,7 +85,7 @@ type rfc2136Actions interface { } // NewRfc2136Provider is a factory function for OpenStack rfc2136 providers -func NewRfc2136Provider(host string, port int, zoneName string, insecure bool, keyName string, secret string, secretAlg string, axfr bool, domainFilter endpoint.DomainFilter, dryRun bool, minTTL time.Duration, gssTsig bool, krb5Username string, krb5Password string, actions rfc2136Actions) (provider.Provider, error) { +func NewRfc2136Provider(host string, port int, zoneName string, insecure bool, keyName string, secret string, secretAlg string, axfr bool, domainFilter endpoint.DomainFilter, dryRun bool, minTTL time.Duration, gssTsig bool, krb5Username string, krb5Password string, krb5Realm string, actions rfc2136Actions) (provider.Provider, error) { secretAlgChecked, ok := tsigAlgs[secretAlg] if !ok && !insecure && !gssTsig { return nil, errors.Errorf("%s is not supported TSIG algorithm", secretAlg) @@ -98,7 +98,7 @@ func NewRfc2136Provider(host string, port int, zoneName string, insecure bool, k gssTsig: gssTsig, krb5Username: krb5Username, krb5Password: krb5Password, - krb5Realm: strings.ToUpper(zoneName), + krb5Realm: strings.ToUpper(krb5Realm), domainFilter: domainFilter, dryRun: dryRun, axfr: axfr, diff --git a/provider/rfc2136/rfc2136_test.go b/provider/rfc2136/rfc2136_test.go index 1df3ea1c6..59d3ea818 100644 --- a/provider/rfc2136/rfc2136_test.go +++ b/provider/rfc2136/rfc2136_test.go @@ -95,7 +95,7 @@ func (r *rfc2136Stub) IncomeTransfer(m *dns.Msg, a string) (env chan *dns.Envelo } func createRfc2136StubProvider(stub *rfc2136Stub) (provider.Provider, error) { - return NewRfc2136Provider("", 0, "", false, "key", "secret", "hmac-sha512", true, endpoint.DomainFilter{}, false, 300*time.Second, false, "", "", stub) + return NewRfc2136Provider("", 0, "", false, "key", "secret", "hmac-sha512", true, endpoint.DomainFilter{}, false, 300*time.Second, false, "", "", "", stub) } func extractAuthoritySectionFromMessage(msg fmt.Stringer) []string { From 5221b1d5257820d2721c98ef5c8d319220b49023 Mon Sep 17 00:00:00 2001 From: Hugome Date: Wed, 29 Jul 2020 03:25:23 +0200 Subject: [PATCH 057/175] feat: add gloo proxy source --- docs/tutorials/gloo-proxy.md | 101 +++++++++ main.go | 1 + pkg/apis/externaldns/types.go | 8 +- pkg/apis/externaldns/types_test.go | 4 + source/gloo.go | 200 ++++++++++++++++++ source/gloo_test.go | 320 +++++++++++++++++++++++++++++ source/store.go | 11 + 7 files changed, 643 insertions(+), 2 deletions(-) create mode 100644 docs/tutorials/gloo-proxy.md create mode 100644 source/gloo.go create mode 100644 source/gloo_test.go diff --git a/docs/tutorials/gloo-proxy.md b/docs/tutorials/gloo-proxy.md new file mode 100644 index 000000000..4938feb21 --- /dev/null +++ b/docs/tutorials/gloo-proxy.md @@ -0,0 +1,101 @@ +# Configuring ExternalDNS to use the Gloo Proxy Source +This tutorial describes how to configure ExternalDNS to use the Gloo Proxy source. +It is meant to supplement the other provider-specific setup tutorials. + +### Manifest (for clusters without RBAC enabled) +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: external-dns +spec: + strategy: + type: Recreate + selector: + matchLabels: + app: external-dns + template: + metadata: + labels: + app: external-dns + spec: + containers: + - name: external-dns + # update this to the desired external-dns version + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 + args: + - --source=gloo-proxy + - --gloo-namespace=custom-gloo-system # gloo system namespace. Omit to use the default (gloo-system) + - --provider=aws + - --registry=txt + - --txt-owner-id=my-identifier +``` + +### Manifest (for clusters with RBAC enabled) +Could be change if you have mulitple sources + +```yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: external-dns +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: external-dns +rules: +- apiGroups: [""] + resources: ["services","endpoints","pods"] + verbs: ["get","watch","list"] +- apiGroups: [""] + resources: ["nodes"] + verbs: ["list","watch"] +- apiGroups: ["gloo.solo.io"] + resources: ["proxies"] + verbs: ["get","watch","list"] +- apiGroups: ["gateway.solo.io"] + resources: ["virtualservices"] + verbs: ["get", "list", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: external-dns-viewer +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: external-dns +subjects: +- kind: ServiceAccount + name: external-dns + namespace: default +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: external-dns +spec: + strategy: + type: Recreate + selector: + matchLabels: + app: external-dns + template: + metadata: + labels: + app: external-dns + spec: + serviceAccountName: external-dns + containers: + - name: external-dns + # update this to the desired external-dns version + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 + args: + - --source=gloo-proxy + - --gloo-namespace=custom-gloo-system # gloo system namespace. Omit to use the default (gloo-system) + - --provider=aws + - --registry=txt + - --txt-owner-id=my-identifier +``` + diff --git a/main.go b/main.go index 09860c08d..75dc33868 100644 --- a/main.go +++ b/main.go @@ -120,6 +120,7 @@ func main() { CFUsername: cfg.CFUsername, CFPassword: cfg.CFPassword, ContourLoadBalancerService: cfg.ContourLoadBalancerService, + GlooNamespace: cfg.GlooNamespace, SkipperRouteGroupVersion: cfg.SkipperRouteGroupVersion, RequestTimeout: cfg.RequestTimeout, } diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index b8d43f462..1384730d6 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -45,6 +45,7 @@ type Config struct { KubeConfig string RequestTimeout time.Duration ContourLoadBalancerService string + GlooNamespace string SkipperRouteGroupVersion string Sources []string Namespace string @@ -167,6 +168,7 @@ var defaultConfig = &Config{ KubeConfig: "", RequestTimeout: time.Second * 30, ContourLoadBalancerService: "heptio-contour/contour", + GlooNamespace: "gloo-system", SkipperRouteGroupVersion: "zalando.org/v1", Sources: nil, Namespace: "", @@ -328,12 +330,14 @@ func (cfg *Config) ParseFlags(args []string) error { // Flags related to Contour app.Flag("contour-load-balancer", "The fully-qualified name of the Contour load balancer service. (default: heptio-contour/contour)").Default("heptio-contour/contour").StringVar(&cfg.ContourLoadBalancerService) + // Flags related to Gloo + app.Flag("gloo-namespace", "Gloo namespace. (default: gloo-system)").Default("gloo-system").StringVar(&cfg.GlooNamespace) + // Flags related to Skipper RouteGroup app.Flag("skipper-routegroup-groupversion", "The resource version for skipper routegroup").Default(source.DefaultRoutegroupVersion).StringVar(&cfg.SkipperRouteGroupVersion) // Flags related to processing sources - app.Flag("source", "The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress, node, fake, connector, istio-gateway, istio-virtualservice, cloudfoundry, contour-ingressroute, contour-httpproxy, crd, empty, skipper-routegroup, openshift-route, ambassador-host)").Required().PlaceHolder("source").EnumsVar(&cfg.Sources, "service", "ingress", "node", "istio-gateway", "istio-virtualservice", "cloudfoundry", "contour-ingressroute", "contour-httpproxy", "fake", "connector", "crd", "empty", "skipper-routegroup", "openshift-route", "ambassador-host") - + app.Flag("source", "The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress, node, fake, connector, istio-gateway, istio-virtualservice, cloudfoundry, contour-ingressroute, contour-httpproxy, gloo-proxy, crd, empty, skipper-routegroup, openshift-route, ambassador-host)").Required().PlaceHolder("source").EnumsVar(&cfg.Sources, "service", "ingress", "node", "istio-gateway", "istio-virtualservice", "cloudfoundry", "contour-ingressroute", "contour-httpproxy", "gloo-proxy", "fake", "connector", "crd", "empty", "skipper-routegroup", "openshift-route", "ambassador-host") app.Flag("namespace", "Limit sources of endpoints to a specific namespace (default: all namespaces)").Default(defaultConfig.Namespace).StringVar(&cfg.Namespace) app.Flag("annotation-filter", "Filter sources managed by external-dns via annotation using label selector semantics (default: all sources)").Default(defaultConfig.AnnotationFilter).StringVar(&cfg.AnnotationFilter) app.Flag("label-filter", "Filter sources managed by external-dns via label selector when listing all resources; currently only supported by source CRD").Default(defaultConfig.LabelFilter).StringVar(&cfg.LabelFilter) diff --git a/pkg/apis/externaldns/types_test.go b/pkg/apis/externaldns/types_test.go index df37180d4..83f853692 100644 --- a/pkg/apis/externaldns/types_test.go +++ b/pkg/apis/externaldns/types_test.go @@ -35,6 +35,7 @@ var ( KubeConfig: "", RequestTimeout: time.Second * 30, ContourLoadBalancerService: "heptio-contour/contour", + GlooNamespace: "gloo-system", SkipperRouteGroupVersion: "zalando.org/v1", Sources: []string{"service"}, Namespace: "", @@ -114,6 +115,7 @@ var ( KubeConfig: "/some/path", RequestTimeout: time.Second * 77, ContourLoadBalancerService: "heptio-contour-other/contour-other", + GlooNamespace: "gloo-not-system", SkipperRouteGroupVersion: "zalando.org/v2", Sources: []string{"service", "ingress", "connector"}, Namespace: "namespace", @@ -220,6 +222,7 @@ func TestParseFlags(t *testing.T) { "--kubeconfig=/some/path", "--request-timeout=77s", "--contour-load-balancer=heptio-contour-other/contour-other", + "--gloo-namespace=gloo-not-system", "--skipper-routegroup-groupversion=zalando.org/v2", "--source=service", "--source=ingress", @@ -317,6 +320,7 @@ func TestParseFlags(t *testing.T) { "EXTERNAL_DNS_KUBECONFIG": "/some/path", "EXTERNAL_DNS_REQUEST_TIMEOUT": "77s", "EXTERNAL_DNS_CONTOUR_LOAD_BALANCER": "heptio-contour-other/contour-other", + "EXTERNAL_DNS_GLOO_NAMESPACE": "gloo-not-system", "EXTERNAL_DNS_SKIPPER_ROUTEGROUP_GROUPVERSION": "zalando.org/v2", "EXTERNAL_DNS_SOURCE": "service\ningress\nconnector", "EXTERNAL_DNS_NAMESPACE": "namespace", diff --git a/source/gloo.go b/source/gloo.go new file mode 100644 index 000000000..845ccdee0 --- /dev/null +++ b/source/gloo.go @@ -0,0 +1,200 @@ +/* +Copyright 2020n The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package source + +import ( + "context" + "encoding/json" + "strings" + + log "github.com/sirupsen/logrus" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/kubernetes" + + "sigs.k8s.io/external-dns/endpoint" +) + +var ( + proxyGVR = schema.GroupVersionResource{ + Group: "gloo.solo.io", + Version: "v1", + Resource: "proxies", + } + virtualServiceGVR = schema.GroupVersionResource{ + Group: "gateway.solo.io", + Version: "v1", + Resource: "virtualservices", + } +) + +// Basic redefinition of "Proxy" CRD : https://github.com/solo-io/gloo/blob/v1.4.6/projects/gloo/pkg/api/v1/proxy.pb.go +type proxy struct { + metav1.TypeMeta `json:",inline"` + Metadata metav1.ObjectMeta `json:"metadata,omitempty"` + Spec proxySpec `json:"spec,omitempty"` +} + +type proxySpec struct { + Listeners []proxySpecListener `json:"listeners,omitempty"` +} + +type proxySpecListener struct { + HTTPListener proxySpecHTTPListener `json:"httpListener,omitempty"` +} + +type proxySpecHTTPListener struct { + VirtualHosts []proxyVirtualHost `json:"virtualHosts,omitempty"` +} + +type proxyVirtualHost struct { + Domains []string `json:"domains,omitempty"` + Metadata proxyVirtualHostMetadata `json:"metadata,omitempty"` +} + +type proxyVirtualHostMetadata struct { + Source []proxyVirtualHostMetadataSource `json:"sources,omitempty"` +} + +type proxyVirtualHostMetadataSource struct { + Kind string `json:"kind,omitempty"` + Name string `json:"name,omitempty"` + Namespace string `json:"namespace,omitempty"` +} + +type glooSource struct { + dynamicKubeClient dynamic.Interface + kubeClient kubernetes.Interface + glooNamespace string +} + +// NewGlooSource creates a new glooSource with the given config +func NewGlooSource(dynamicKubeClient dynamic.Interface, kubeClient kubernetes.Interface, glooNamespace string) (Source, error) { + return &glooSource{ + dynamicKubeClient, + kubeClient, + glooNamespace, + }, nil +} + +func (gs *glooSource) AddEventHandler(ctx context.Context, handler func()) { +} + +// Endpoints returns endpoint objects +func (gs *glooSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error) { + endpoints := []*endpoint.Endpoint{} + + proxies, err := gs.dynamicKubeClient.Resource(proxyGVR).Namespace(gs.glooNamespace).List(ctx, metav1.ListOptions{}) + if err != nil { + return nil, err + } + for _, obj := range proxies.Items { + proxy := proxy{} + jsonString, err := obj.MarshalJSON() + if err != nil { + return nil, err + } + err = json.Unmarshal(jsonString, &proxy) + if err != nil { + return nil, err + } + log.Debugf("Gloo: Find %s proxy", proxy.Metadata.Name) + proxyTargets, err := gs.proxyTargets(ctx, proxy.Metadata.Name) + if err != nil { + return nil, err + } + log.Debugf("Gloo[%s]: Find %d target(s) (%+v)", proxy.Metadata.Name, len(proxyTargets), proxyTargets) + proxyEndpoints, err := gs.generateEndpointsFromProxy(ctx, &proxy, proxyTargets) + if err != nil { + return nil, err + } + log.Debugf("Gloo[%s]: Generate %d endpoint(s)", proxy.Metadata.Name, len(proxyEndpoints)) + endpoints = append(endpoints, proxyEndpoints...) + } + return endpoints, nil +} + +func (gs *glooSource) generateEndpointsFromProxy(ctx context.Context, proxy *proxy, targets endpoint.Targets) ([]*endpoint.Endpoint, error) { + endpoints := []*endpoint.Endpoint{} + for _, listener := range proxy.Spec.Listeners { + for _, virtualHost := range listener.HTTPListener.VirtualHosts { + annotations, err := gs.annotationsFromProxySource(ctx, virtualHost) + if err != nil { + return nil, err + } + ttl, err := getTTLFromAnnotations(annotations) + if err != nil { + return nil, err + } + providerSpecific, setIdentifier := getProviderSpecificAnnotations(annotations) + for _, domain := range virtualHost.Domains { + endpoints = append(endpoints, endpointsForHostname(strings.TrimSuffix(domain, "."), targets, ttl, providerSpecific, setIdentifier)...) + } + } + } + return endpoints, nil +} + +func (gs *glooSource) annotationsFromProxySource(ctx context.Context, virtualHost proxyVirtualHost) (map[string]string, error) { + annotations := map[string]string{} + for _, src := range virtualHost.Metadata.Source { + kind := sourceKind(src.Kind) + if kind != nil { + source, err := gs.dynamicKubeClient.Resource(*kind).Namespace(src.Namespace).Get(ctx, src.Name, metav1.GetOptions{}) + if err != nil { + return nil, err + } + for key, value := range source.GetAnnotations() { + annotations[key] = value + } + } + } + return annotations, nil +} + +func (gs *glooSource) proxyTargets(ctx context.Context, name string) (endpoint.Targets, error) { + svc, err := gs.kubeClient.CoreV1().Services(gs.glooNamespace).Get(ctx, name, metav1.GetOptions{}) + if err != nil { + return nil, err + } + + var targets endpoint.Targets + switch svc.Spec.Type { + case corev1.ServiceTypeLoadBalancer: + for _, lb := range svc.Status.LoadBalancer.Ingress { + if lb.IP != "" { + targets = append(targets, lb.IP) + } + if lb.Hostname != "" { + targets = append(targets, lb.Hostname) + } + } + default: + log.WithField("gateway", name).WithField("service", svc).Warn("Gloo: Proxy service type not supported") + } + return targets, nil +} + +func sourceKind(kind string) *schema.GroupVersionResource { + switch kind { + case "*v1.VirtualService": + return &virtualServiceGVR + } + return nil +} diff --git a/source/gloo_test.go b/source/gloo_test.go new file mode 100644 index 000000000..dfc4d9436 --- /dev/null +++ b/source/gloo_test.go @@ -0,0 +1,320 @@ +/* +Copyright 2020n The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package source + +import ( + "context" + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + fakeDynamic "k8s.io/client-go/dynamic/fake" + fakeKube "k8s.io/client-go/kubernetes/fake" + "sigs.k8s.io/external-dns/endpoint" +) + +// This is a compile-time validation that glooSource is a Source. +var _ Source = &glooSource{} + +const defaultGlooNamespace = "gloo-system" + +// Internal proxy test +var internalProxy = proxy{ + TypeMeta: metav1.TypeMeta{ + APIVersion: proxyGVR.GroupVersion().String(), + Kind: "Proxy", + }, + Metadata: metav1.ObjectMeta{ + Name: "internal", + Namespace: defaultGlooNamespace, + }, + Spec: proxySpec{ + Listeners: []proxySpecListener{ + { + HTTPListener: proxySpecHTTPListener{ + VirtualHosts: []proxyVirtualHost{ + { + Domains: []string{"a.test", "b.test"}, + Metadata: proxyVirtualHostMetadata{ + Source: []proxyVirtualHostMetadataSource{ + { + Kind: "*v1.Unknown", + Name: "my-unknown-svc", + Namespace: "unknown", + }, + }, + }, + }, + { + Domains: []string{"c.test"}, + Metadata: proxyVirtualHostMetadata{ + Source: []proxyVirtualHostMetadataSource{ + { + Kind: "*v1.VirtualService", + Name: "my-internal-svc", + Namespace: "internal", + }, + }, + }, + }, + }, + }, + }, + }, + }, +} + +var internalProxySvc = corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: internalProxy.Metadata.Name, + Namespace: internalProxy.Metadata.Namespace, + }, + Spec: corev1.ServiceSpec{ + Type: corev1.ServiceTypeLoadBalancer, + }, + Status: corev1.ServiceStatus{ + LoadBalancer: corev1.LoadBalancerStatus{ + Ingress: []corev1.LoadBalancerIngress{ + corev1.LoadBalancerIngress{ + IP: "203.0.113.1", + }, + corev1.LoadBalancerIngress{ + IP: "203.0.113.2", + }, + corev1.LoadBalancerIngress{ + IP: "203.0.113.3", + }, + }, + }, + }, +} + +var internalProxySource = metav1.PartialObjectMetadata{ + TypeMeta: metav1.TypeMeta{ + APIVersion: virtualServiceGVR.GroupVersion().String(), + Kind: "VirtualService", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: internalProxy.Spec.Listeners[0].HTTPListener.VirtualHosts[1].Metadata.Source[0].Name, + Namespace: internalProxy.Spec.Listeners[0].HTTPListener.VirtualHosts[1].Metadata.Source[0].Namespace, + Annotations: map[string]string{ + "external-dns.alpha.kubernetes.io/ttl": "42", + "external-dns.alpha.kubernetes.io/aws-geolocation-country-code": "LU", + "external-dns.alpha.kubernetes.io/set-identifier": "identifier", + }, + }, +} + +// External proxy test +var externalProxy = proxy{ + TypeMeta: metav1.TypeMeta{ + APIVersion: proxyGVR.GroupVersion().String(), + Kind: "Proxy", + }, + Metadata: metav1.ObjectMeta{ + Name: "external", + Namespace: defaultGlooNamespace, + }, + Spec: proxySpec{ + Listeners: []proxySpecListener{ + { + HTTPListener: proxySpecHTTPListener{ + VirtualHosts: []proxyVirtualHost{ + { + Domains: []string{"d.test"}, + Metadata: proxyVirtualHostMetadata{ + Source: []proxyVirtualHostMetadataSource{ + { + Kind: "*v1.Unknown", + Name: "my-unknown-svc", + Namespace: "unknown", + }, + }, + }, + }, + { + Domains: []string{"e.test"}, + Metadata: proxyVirtualHostMetadata{ + Source: []proxyVirtualHostMetadataSource{ + { + Kind: "*v1.VirtualService", + Name: "my-external-svc", + Namespace: "external", + }, + }, + }, + }, + }, + }, + }, + }, + }, +} + +var externalProxySvc = corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: externalProxy.Metadata.Name, + Namespace: externalProxy.Metadata.Namespace, + }, + Spec: corev1.ServiceSpec{ + Type: corev1.ServiceTypeLoadBalancer, + }, + Status: corev1.ServiceStatus{ + LoadBalancer: corev1.LoadBalancerStatus{ + Ingress: []corev1.LoadBalancerIngress{ + corev1.LoadBalancerIngress{ + Hostname: "a.example.org", + }, + corev1.LoadBalancerIngress{ + Hostname: "b.example.org", + }, + corev1.LoadBalancerIngress{ + Hostname: "c.example.org", + }, + }, + }, + }, +} + +var externalProxySource = metav1.PartialObjectMetadata{ + TypeMeta: metav1.TypeMeta{ + APIVersion: virtualServiceGVR.GroupVersion().String(), + Kind: "VirtualService", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: externalProxy.Spec.Listeners[0].HTTPListener.VirtualHosts[1].Metadata.Source[0].Name, + Namespace: externalProxy.Spec.Listeners[0].HTTPListener.VirtualHosts[1].Metadata.Source[0].Namespace, + Annotations: map[string]string{ + "external-dns.alpha.kubernetes.io/ttl": "24", + "external-dns.alpha.kubernetes.io/aws-geolocation-country-code": "JP", + "external-dns.alpha.kubernetes.io/set-identifier": "identifier-external", + }, + }, +} + +func TestGlooSource(t *testing.T) { + fakeKubernetesClient := fakeKube.NewSimpleClientset() + fakeDynamicClient := fakeDynamic.NewSimpleDynamicClient(runtime.NewScheme()) + + source, err := NewGlooSource(fakeDynamicClient, fakeKubernetesClient, defaultGlooNamespace) + assert.NoError(t, err) + assert.NotNil(t, source) + + internalProxyUnstructured := unstructured.Unstructured{} + externalProxyUnstructured := unstructured.Unstructured{} + + internalProxySourceUnstructured := unstructured.Unstructured{} + externalProxySourceUnstructured := unstructured.Unstructured{} + + internalProxyAsJSON, err := json.Marshal(internalProxy) + assert.NoError(t, err) + + externalProxyAsJSON, err := json.Marshal(externalProxy) + assert.NoError(t, err) + + internalProxySvcAsJSON, err := json.Marshal(internalProxySource) + assert.NoError(t, err) + + externalProxySvcAsJSON, err := json.Marshal(externalProxySource) + assert.NoError(t, err) + + assert.NoError(t, internalProxyUnstructured.UnmarshalJSON(internalProxyAsJSON)) + assert.NoError(t, externalProxyUnstructured.UnmarshalJSON(externalProxyAsJSON)) + + assert.NoError(t, internalProxySourceUnstructured.UnmarshalJSON(internalProxySvcAsJSON)) + assert.NoError(t, externalProxySourceUnstructured.UnmarshalJSON(externalProxySvcAsJSON)) + + // Create proxy resources + _, err = fakeDynamicClient.Resource(proxyGVR).Namespace(defaultGlooNamespace).Create(context.Background(), &internalProxyUnstructured, metav1.CreateOptions{}) + assert.NoError(t, err) + _, err = fakeDynamicClient.Resource(proxyGVR).Namespace(defaultGlooNamespace).Create(context.Background(), &externalProxyUnstructured, metav1.CreateOptions{}) + assert.NoError(t, err) + + // Create proxy source + _, err = fakeDynamicClient.Resource(virtualServiceGVR).Namespace(internalProxySource.Namespace).Create(context.Background(), &internalProxySourceUnstructured, metav1.CreateOptions{}) + assert.NoError(t, err) + _, err = fakeDynamicClient.Resource(virtualServiceGVR).Namespace(externalProxySource.Namespace).Create(context.Background(), &externalProxySourceUnstructured, metav1.CreateOptions{}) + assert.NoError(t, err) + + // Create proxy service resources + _, err = fakeKubernetesClient.CoreV1().Services(internalProxySvc.GetNamespace()).Create(context.Background(), &internalProxySvc, metav1.CreateOptions{}) + assert.NoError(t, err) + _, err = fakeKubernetesClient.CoreV1().Services(externalProxySvc.GetNamespace()).Create(context.Background(), &externalProxySvc, metav1.CreateOptions{}) + assert.NoError(t, err) + + endpoints, err := source.Endpoints(context.Background()) + assert.NoError(t, err) + assert.Len(t, endpoints, 5) + assert.Equal(t, endpoints, []*endpoint.Endpoint{ + &endpoint.Endpoint{ + DNSName: "a.test", + Targets: []string{internalProxySvc.Status.LoadBalancer.Ingress[0].IP, internalProxySvc.Status.LoadBalancer.Ingress[1].IP, internalProxySvc.Status.LoadBalancer.Ingress[2].IP}, + RecordType: endpoint.RecordTypeA, + RecordTTL: 0, + Labels: endpoint.Labels{}, + ProviderSpecific: endpoint.ProviderSpecific{}, + }, + &endpoint.Endpoint{ + DNSName: "b.test", + Targets: []string{internalProxySvc.Status.LoadBalancer.Ingress[0].IP, internalProxySvc.Status.LoadBalancer.Ingress[1].IP, internalProxySvc.Status.LoadBalancer.Ingress[2].IP}, + RecordType: endpoint.RecordTypeA, + RecordTTL: 0, + Labels: endpoint.Labels{}, + ProviderSpecific: endpoint.ProviderSpecific{}, + }, + &endpoint.Endpoint{ + DNSName: "c.test", + Targets: []string{internalProxySvc.Status.LoadBalancer.Ingress[0].IP, internalProxySvc.Status.LoadBalancer.Ingress[1].IP, internalProxySvc.Status.LoadBalancer.Ingress[2].IP}, + RecordType: endpoint.RecordTypeA, + SetIdentifier: "identifier", + RecordTTL: 42, + Labels: endpoint.Labels{}, + ProviderSpecific: endpoint.ProviderSpecific{ + endpoint.ProviderSpecificProperty{ + Name: "aws/geolocation-country-code", + Value: "LU", + }, + }, + }, + &endpoint.Endpoint{ + DNSName: "d.test", + Targets: []string{externalProxySvc.Status.LoadBalancer.Ingress[0].Hostname, externalProxySvc.Status.LoadBalancer.Ingress[1].Hostname, externalProxySvc.Status.LoadBalancer.Ingress[2].Hostname}, + RecordType: endpoint.RecordTypeCNAME, + RecordTTL: 0, + Labels: endpoint.Labels{}, + ProviderSpecific: endpoint.ProviderSpecific{}, + }, + &endpoint.Endpoint{ + DNSName: "e.test", + Targets: []string{externalProxySvc.Status.LoadBalancer.Ingress[0].Hostname, externalProxySvc.Status.LoadBalancer.Ingress[1].Hostname, externalProxySvc.Status.LoadBalancer.Ingress[2].Hostname}, + RecordType: endpoint.RecordTypeCNAME, + SetIdentifier: "identifier-external", + RecordTTL: 24, + Labels: endpoint.Labels{}, + ProviderSpecific: endpoint.ProviderSpecific{ + endpoint.ProviderSpecificProperty{ + Name: "aws/geolocation-country-code", + Value: "JP", + }, + }, + }, + }) +} diff --git a/source/store.go b/source/store.go index 0cb6641fb..0c934c407 100644 --- a/source/store.go +++ b/source/store.go @@ -61,6 +61,7 @@ type Config struct { CFUsername string CFPassword string ContourLoadBalancerService string + GlooNamespace string SkipperRouteGroupVersion string RequestTimeout time.Duration } @@ -239,6 +240,16 @@ func BuildWithConfig(source string, p ClientGenerator, cfg *Config) (Source, err return nil, err } return NewContourHTTPProxySource(dynamicClient, cfg.Namespace, cfg.AnnotationFilter, cfg.FQDNTemplate, cfg.CombineFQDNAndAnnotation, cfg.IgnoreHostnameAnnotation) + case "gloo-proxy": + kubernetesClient, err := p.KubeClient() + if err != nil { + return nil, err + } + dynamicClient, err := p.DynamicKubernetesClient() + if err != nil { + return nil, err + } + return NewGlooSource(dynamicClient, kubernetesClient, cfg.GlooNamespace) case "openshift-route": ocpClient, err := p.OpenShiftClient() if err != nil { From df6ae8c15fa4a4aa73cc422a32efe9022e6c043c Mon Sep 17 00:00:00 2001 From: Nick Nellis Date: Mon, 8 Mar 2021 10:47:08 -0600 Subject: [PATCH 058/175] updated to latest Istio 1.7 libs --- go.mod | 4 ++-- go.sum | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index c28b520bf..feff79fa2 100644 --- a/go.mod +++ b/go.mod @@ -64,8 +64,8 @@ require ( gopkg.in/ns1/ns1-go.v2 v2.0.0-20190322154155-0dafb5275fd1 gopkg.in/yaml.v2 v2.3.0 honnef.co/go/tools v0.0.1-2020.1.4 // indirect - istio.io/api v0.0.0-20200529165953-72dad51d4ffc - istio.io/client-go v0.0.0-20200529172309-31c16ea3f751 + istio.io/api v0.0.0-20210128181506-0c4b8e54850f + istio.io/client-go v0.0.0-20210128182905-ee2edd059e02 k8s.io/api v0.18.8 k8s.io/apimachinery v0.18.8 k8s.io/client-go v0.18.8 diff --git a/go.sum b/go.sum index c0c41bd25..23127e8a7 100644 --- a/go.sum +++ b/go.sum @@ -1227,8 +1227,12 @@ honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= istio.io/api v0.0.0-20200529165953-72dad51d4ffc h1:cR9GmbIBAz3FnY3tgs1SRn/uiznhtvG+mZBfD1p2vIA= istio.io/api v0.0.0-20200529165953-72dad51d4ffc/go.mod h1:kyq3g5w42zl/AKlbzDGppYpGMQYMYMyZKeq0/eexML8= +istio.io/api v0.0.0-20210128181506-0c4b8e54850f h1:zUFsawgPj5oI9p5cf91YCExRlxLIVsEkIunN9ODUSJs= +istio.io/api v0.0.0-20210128181506-0c4b8e54850f/go.mod h1:88HN3o1fSD1jo+Z1WTLlJfMm9biopur6Ct9BFKjiB64= istio.io/client-go v0.0.0-20200529172309-31c16ea3f751 h1:yH62fTmV+5l1XVTWcomsc1jjH/oH9u/tTgn5NVmdIac= istio.io/client-go v0.0.0-20200529172309-31c16ea3f751/go.mod h1:4SGvmmus5HNFdqQsIL+uQO1PbAhjQKtSjMTqwsvYHlg= +istio.io/client-go v0.0.0-20210128182905-ee2edd059e02 h1:ZA8Y2gKkKtEeYuKfqlEzIBDfU4IE5uIAdsXDeD41T9w= +istio.io/client-go v0.0.0-20210128182905-ee2edd059e02/go.mod h1:oXMjFUWhxlReUSbg4i3GjKgOhSX1WgD68ZNlHQEcmQg= istio.io/gogo-genproto v0.0.0-20190904133402-ee07f2785480/go.mod h1:uKtbae4K9k2rjjX4ToV0l6etglbc1i7gqQ94XdkshzY= istio.io/gogo-genproto v0.0.0-20190930162913-45029607206a h1:w7zILua2dnYo9CxImhpNW4NE/8ZxEoc/wfBfHrhUhrE= istio.io/gogo-genproto v0.0.0-20190930162913-45029607206a/go.mod h1:OzpAts7jljZceG4Vqi5/zXy/pOg1b209T3jb7Nv5wIs= From a143a6cd59177f1f72e2f173bc5cfdbe8d723157 Mon Sep 17 00:00:00 2001 From: Dinar Valeev Date: Mon, 8 Mar 2021 19:57:24 +0100 Subject: [PATCH 059/175] Generate CRD with controller-gen Signed-off-by: Dinar Valeev --- Makefile | 22 ++++++++++ .../contributing/crd-source/crd-manifest.yaml | 40 +++++++++++++++++-- endpoint/endpoint.go | 5 +++ 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 0f2b274e8..1818baac1 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,23 @@ cover: cover-html: cover go tool cover -html cover.out +# find or download controller-gen +# download controller-gen if necessary +controller-gen: +ifeq (, $(shell which controller-gen)) + @{ \ + set -e ;\ + CONTROLLER_GEN_TMP_DIR=$$(mktemp -d) ;\ + cd $$CONTROLLER_GEN_TMP_DIR ;\ + go mod init tmp ;\ + go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.5.0 ;\ + rm -rf $$CONTROLLER_GEN_TMP_DIR ;\ + } +CONTROLLER_GEN=$(GOBIN)/controller-gen +else +CONTROLLER_GEN=$(shell which controller-gen) +endif + .PHONY: go-lint # Run the golangci-lint tool @@ -51,6 +68,11 @@ licensecheck: # Run all the linters lint: licensecheck go-lint +.PHONY: crd + +# generates CRD using controller-gen +crd: controller-gen + ${CONTROLLER_GEN} crd:crdVersions=v1beta1 paths="./endpoint/..." output:crd:stdout > docs/contributing/crd-source/crd-manifest.yaml # The verify target runs tasks similar to the CI tasks, but without code coverage .PHONY: verify test diff --git a/docs/contributing/crd-source/crd-manifest.yaml b/docs/contributing/crd-source/crd-manifest.yaml index 842928690..ea801b11b 100644 --- a/docs/contributing/crd-source/crd-manifest.yaml +++ b/docs/contributing/crd-source/crd-manifest.yaml @@ -1,16 +1,19 @@ + +--- apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.5.0 creationTimestamp: null - labels: - api: externaldns - kubebuilder.k8s.io: 1.0.0 name: dnsendpoints.externaldns.k8s.io spec: group: externaldns.k8s.io names: kind: DNSEndpoint + listKind: DNSEndpointList plural: dnsendpoints + singular: dnsendpoint scope: Namespaced subresources: status: {} @@ -18,35 +21,51 @@ spec: openAPIV3Schema: properties: apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' type: string kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' type: string metadata: type: object spec: + description: DNSEndpointSpec defines the desired state of DNSEndpoint properties: endpoints: items: + description: Endpoint is a high-level way of a connection between a service and an IP properties: dnsName: + description: The hostname of the DNS record type: string labels: + additionalProperties: + type: string + description: Labels stores labels defined for the Endpoint type: object providerSpecific: + description: ProviderSpecific stores provider specific config items: + description: ProviderSpecificProperty holds the name and value of a configuration which is specific to individual DNS providers properties: - name: + name: type: string value: type: string type: object type: array recordTTL: + description: TTL for the record format: int64 type: integer recordType: + description: RecordType type of record, e.g. CNAME, A, SRV, TXT etc + type: string + setIdentifier: + description: Identifier to distinguish multiple records with the same name and type (e.g. Route53 records with routing policies other than 'simple') type: string targets: + description: The targets the DNS record points to items: type: string type: array @@ -54,9 +73,22 @@ spec: type: array type: object status: + description: DNSEndpointStatus defines the observed state of DNSEndpoint properties: observedGeneration: + description: The generation observed by the external-dns controller. format: int64 type: integer type: object + type: object version: v1alpha1 + versions: + - name: v1alpha1 + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/endpoint/endpoint.go b/endpoint/endpoint.go index 07bd3ea4b..7d7be8e00 100644 --- a/endpoint/endpoint.go +++ b/endpoint/endpoint.go @@ -213,8 +213,12 @@ type DNSEndpointStatus struct { // DNSEndpoint is a contract that a user-specified CRD must implement to be used as a source for external-dns. // The user-specified CRD should also have the status sub-resource. // +k8s:openapi-gen=true +// +groupName=externaldns.k8s.io // +kubebuilder:resource:path=dnsendpoints +// +kubebuilder:object:root=true // +kubebuilder:subresource:status +// +versionName=v1alpha1 + type DNSEndpoint struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` @@ -223,6 +227,7 @@ type DNSEndpoint struct { Status DNSEndpointStatus `json:"status,omitempty"` } +// +kubebuilder:object:root=true // DNSEndpointList is a list of DNSEndpoint objects type DNSEndpointList struct { metav1.TypeMeta `json:",inline"` From 544d245464bfda2d61b986c4e9a5cb8bca0e2056 Mon Sep 17 00:00:00 2001 From: Dinar Valeev Date: Mon, 8 Mar 2021 20:04:09 +0100 Subject: [PATCH 060/175] Update apiextentions to v1 v1 is available since kubernetes 1.16, since then v1beta1 is deprecated and will be dropped in kubernetes 1.22 Signed-off-by: Dinar Valeev --- Makefile | 2 +- .../contributing/crd-source/crd-manifest.yaml | 135 +++++++++--------- 2 files changed, 68 insertions(+), 69 deletions(-) diff --git a/Makefile b/Makefile index 1818baac1..fa6f2bd85 100644 --- a/Makefile +++ b/Makefile @@ -72,7 +72,7 @@ lint: licensecheck go-lint # generates CRD using controller-gen crd: controller-gen - ${CONTROLLER_GEN} crd:crdVersions=v1beta1 paths="./endpoint/..." output:crd:stdout > docs/contributing/crd-source/crd-manifest.yaml + ${CONTROLLER_GEN} crd:crdVersions=v1 paths="./endpoint/..." output:crd:stdout > docs/contributing/crd-source/crd-manifest.yaml # The verify target runs tasks similar to the CI tasks, but without code coverage .PHONY: verify test diff --git a/docs/contributing/crd-source/crd-manifest.yaml b/docs/contributing/crd-source/crd-manifest.yaml index ea801b11b..4fb16468a 100644 --- a/docs/contributing/crd-source/crd-manifest.yaml +++ b/docs/contributing/crd-source/crd-manifest.yaml @@ -1,6 +1,6 @@ --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: @@ -15,77 +15,76 @@ spec: plural: dnsendpoints singular: dnsendpoint scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: DNSEndpointSpec defines the desired state of DNSEndpoint - properties: - endpoints: - items: - description: Endpoint is a high-level way of a connection between a service and an IP - properties: - dnsName: - description: The hostname of the DNS record - type: string - labels: - additionalProperties: - type: string - description: Labels stores labels defined for the Endpoint - type: object - providerSpecific: - description: ProviderSpecific stores provider specific config - items: - description: ProviderSpecificProperty holds the name and value of a configuration which is specific to individual DNS providers - properties: - name: - type: string - value: - type: string - type: object - type: array - recordTTL: - description: TTL for the record - format: int64 - type: integer - recordType: - description: RecordType type of record, e.g. CNAME, A, SRV, TXT etc - type: string - setIdentifier: - description: Identifier to distinguish multiple records with the same name and type (e.g. Route53 records with routing policies other than 'simple') - type: string - targets: - description: The targets the DNS record points to - items: - type: string - type: array - type: object - type: array - type: object - status: - description: DNSEndpointStatus defines the observed state of DNSEndpoint - properties: - observedGeneration: - description: The generation observed by the external-dns controller. - format: int64 - type: integer - type: object - type: object - version: v1alpha1 versions: - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: DNSEndpointSpec defines the desired state of DNSEndpoint + properties: + endpoints: + items: + description: Endpoint is a high-level way of a connection between a service and an IP + properties: + dnsName: + description: The hostname of the DNS record + type: string + labels: + additionalProperties: + type: string + description: Labels stores labels defined for the Endpoint + type: object + providerSpecific: + description: ProviderSpecific stores provider specific config + items: + description: ProviderSpecificProperty holds the name and value of a configuration which is specific to individual DNS providers + properties: + name: + type: string + value: + type: string + type: object + type: array + recordTTL: + description: TTL for the record + format: int64 + type: integer + recordType: + description: RecordType type of record, e.g. CNAME, A, SRV, TXT etc + type: string + setIdentifier: + description: Identifier to distinguish multiple records with the same name and type (e.g. Route53 records with routing policies other than 'simple') + type: string + targets: + description: The targets the DNS record points to + items: + type: string + type: array + type: object + type: array + type: object + status: + description: DNSEndpointStatus defines the observed state of DNSEndpoint + properties: + observedGeneration: + description: The generation observed by the external-dns controller. + format: int64 + type: integer + type: object + type: object served: true storage: true + subresources: + status: {} status: acceptedNames: kind: "" From 75bfb2c86ecc76de2ec7a03953ad15b0487ea6cb Mon Sep 17 00:00:00 2001 From: Thomas Stig Jacobsen Date: Mon, 8 Mar 2021 20:35:13 +0100 Subject: [PATCH 061/175] Bump alpine base image to 3.13.2 --- Dockerfile | 2 +- Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8e71170b0..48e243f41 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,7 +27,7 @@ COPY . . RUN make test build.$ARCH # final image -FROM $ARCH/alpine:3.12 +FROM $ARCH/alpine:3.13.2 COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt COPY --from=builder /sigs.k8s.io/external-dns/build/external-dns /bin/external-dns diff --git a/Makefile b/Makefile index 0f2b274e8..1a8c2932a 100644 --- a/Makefile +++ b/Makefile @@ -82,7 +82,7 @@ build.push/multiarch: for arch in $(ARCHS); do \ image="$(IMAGE):$(VERSION)-$${arch}" ;\ # pre-pull due to https://github.com/kubernetes-sigs/cluster-addons/pull/84/files ;\ - docker pull $${arch}/alpine:3.12 ;\ + docker pull $${arch}/alpine:3.13.2 ;\ DOCKER_BUILDKIT=1 docker build --rm --tag $${image} --build-arg VERSION="$(VERSION)" --build-arg ARCH="$${arch}" . ;\ docker push $${image} ;\ arch_specific_tags+=( "--amend $${image}" ) ;\ From c97614906e18368e624cd0734c9a82758d4ebfe0 Mon Sep 17 00:00:00 2001 From: Thomas Stig Jacobsen Date: Tue, 9 Mar 2021 09:31:16 +0100 Subject: [PATCH 062/175] Using the minor version instead of the patch version --- Dockerfile | 2 +- Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 48e243f41..27715b433 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,7 +27,7 @@ COPY . . RUN make test build.$ARCH # final image -FROM $ARCH/alpine:3.13.2 +FROM $ARCH/alpine:3.13 COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt COPY --from=builder /sigs.k8s.io/external-dns/build/external-dns /bin/external-dns diff --git a/Makefile b/Makefile index 1a8c2932a..af56de8d1 100644 --- a/Makefile +++ b/Makefile @@ -82,7 +82,7 @@ build.push/multiarch: for arch in $(ARCHS); do \ image="$(IMAGE):$(VERSION)-$${arch}" ;\ # pre-pull due to https://github.com/kubernetes-sigs/cluster-addons/pull/84/files ;\ - docker pull $${arch}/alpine:3.13.2 ;\ + docker pull $${arch}/alpine:3.13 ;\ DOCKER_BUILDKIT=1 docker build --rm --tag $${image} --build-arg VERSION="$(VERSION)" --build-arg ARCH="$${arch}" . ;\ docker push $${image} ;\ arch_specific_tags+=( "--amend $${image}" ) ;\ From 1c4d47444080211f9cfa84316e2292a887c33033 Mon Sep 17 00:00:00 2001 From: Thomas Stig Jacobsen Date: Tue, 9 Mar 2021 11:02:00 +0100 Subject: [PATCH 063/175] Update to Go 1.16 --- .github/workflows/ci.yml | 2 +- Dockerfile | 2 +- Dockerfile.mini | 2 +- docs/contributing/getting-started.md | 2 +- go.mod | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b7ac22236..19266d35f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: - name: Set up Go 1.x uses: actions/setup-go@v2 with: - go-version: ^1.15 + go-version: ^1.16 id: go - name: Check out code into the Go module directory diff --git a/Dockerfile b/Dockerfile index 27715b433..dd9e80552 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,7 @@ # builder image ARG ARCH -FROM golang:1.15 as builder +FROM golang:1.16 as builder ARG ARCH WORKDIR /sigs.k8s.io/external-dns diff --git a/Dockerfile.mini b/Dockerfile.mini index 1f7633006..d3b02877f 100644 --- a/Dockerfile.mini +++ b/Dockerfile.mini @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM golang:1.15 as builder +FROM golang:1.16 as builder WORKDIR /sigs.k8s.io/external-dns diff --git a/docs/contributing/getting-started.md b/docs/contributing/getting-started.md index 37b2dc4a3..9a51861b4 100644 --- a/docs/contributing/getting-started.md +++ b/docs/contributing/getting-started.md @@ -1,7 +1,7 @@ # Quick Start - [Git](https://git-scm.com/downloads) -- [Go 1.15+](https://golang.org/dl/) +- [Go 1.16+](https://golang.org/dl/) - [Go modules](https://github.com/golang/go/wiki/Modules) - [golangci-lint](https://github.com/golangci/golangci-lint) - [Docker](https://docs.docker.com/install/) diff --git a/go.mod b/go.mod index feff79fa2..28644e915 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module sigs.k8s.io/external-dns -go 1.15 +go 1.16 require ( cloud.google.com/go v0.50.0 From 277ddc274bbec3ceac115d06bdd94b598cca0fcc Mon Sep 17 00:00:00 2001 From: pg2000 Date: Tue, 2 Mar 2021 13:35:30 +0100 Subject: [PATCH 064/175] feat: move from dynectsoap to dynsoap --- go.mod | 4 ++-- go.sum | 22 +++++++------------ provider/dyn/dyn.go | 52 ++++++++++++++++++++++++++++----------------- 3 files changed, 43 insertions(+), 35 deletions(-) diff --git a/go.mod b/go.mod index feff79fa2..c2161ea9e 100644 --- a/go.mod +++ b/go.mod @@ -41,11 +41,11 @@ require ( github.com/openshift/client-go v0.0.0-20200608144219-584632b8fc73 github.com/oracle/oci-go-sdk v21.4.0+incompatible github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014 + github.com/pg2000/dynsoap v0.0.0-20210302131910-d513cf169ae8 github.com/pkg/errors v0.9.1 github.com/projectcontour/contour v1.5.0 github.com/prometheus/client_golang v1.7.1 - github.com/sanyu/dynectsoap v0.0.0-20181203081243-b83de5edc4e0 - github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f + github.com/scaleway/scaleway-sdk-go v1.0.0-beta.6.0.20200623155123-84df6c4b5301 github.com/sirupsen/logrus v1.6.0 github.com/smartystreets/gunit v1.3.4 // indirect github.com/stretchr/testify v1.6.1 diff --git a/go.sum b/go.sum index 23127e8a7..51835d8ed 100644 --- a/go.sum +++ b/go.sum @@ -92,6 +92,7 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5 h1:P5U+E4x5OkVEKQDklVPmzs71WM56RTTRqV4OrDC//Y4= github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5/go.mod h1:976q2ETgjT2snVCf2ZaBnyBbVoPERGjUz+0sofzEfro= github.com/aliyun/alibaba-cloud-sdk-go v1.61.357 h1:3ynCSeUh9OtJLd/OzLapM1DLDv2g+0yyDdkLqSfZCaQ= github.com/aliyun/alibaba-cloud-sdk-go v1.61.357/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA= @@ -127,8 +128,6 @@ github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bodgit/tsig v0.0.2 h1:seNt23SrPW8dkWoyRYzdeuqFEzr+lDc0dAJvo94xB8U= github.com/bodgit/tsig v0.0.2/go.mod h1:0mYe0t9it36SOvDQyeFekc7bLtvljFz7H9vHS/nYbgc= -github.com/bodgit/tsig v1.1.1 h1:SViReRa8KyaweqdJ3ojdYqIE3xDyJlR3G+6wAsSbLCo= -github.com/bodgit/tsig v1.1.1/go.mod h1:8LZ3Mn7AVZHH8GN2ArvzB7msHfLjoptWsdPEJRSw/uo= github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= @@ -427,7 +426,9 @@ github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ= github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= @@ -483,6 +484,8 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hooklift/gowsdl v0.4.0 h1:luskQG8h3M0CYrcSFl9ObpWs3pzIsEfYou1cuSwKiCk= +github.com/hooklift/gowsdl v0.4.0/go.mod h1:TYmt7jpe3F5zLlMtKGetjHLwUBIAF5JCd+NYq+mQ/Zk= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= @@ -510,8 +513,6 @@ github.com/jcmturner/gokrb5/v8 v8.4.1/go.mod h1:T1hnNppQsBtxW0tCHMHTkAt8n/sABdzZ github.com/jcmturner/rpc/v2 v2.0.2 h1:gMB4IwRXYsWw4Bc6o/az2HJgFUA1ffSh90i26ZJ6Xl0= github.com/jcmturner/rpc/v2 v2.0.2/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jinzhu/copier v0.1.0 h1:Vh8xALtH3rrKGB/XIRe5d0yCTHPZFauWPLvdpDAbi88= -github.com/jinzhu/copier v0.1.0/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -599,8 +600,6 @@ github.com/maxatome/go-testdeep v1.4.0/go.mod h1:011SgQ6efzZYAen6fDn4BqQ+lUR72ys github.com/mholt/archiver/v3 v3.3.0/go.mod h1:YnQtqsp+94Rwd0D/rk5cnLrxusUBUXg+08Ebtr1Mqao= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.6/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.30 h1:Qww6FseFn8PRfw07jueqIXqodm0JKiiKuK0DeXSqfyo= -github.com/miekg/dns v1.1.30/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.36-0.20210109083720-731b191cabd1 h1:kZZmnTeY2r+88mDNCVV/uCXL2gG3rkVPTN9jcYfGQcI= github.com/miekg/dns v1.1.36-0.20210109083720-731b191cabd1/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= @@ -690,6 +689,7 @@ github.com/openshift/api v0.0.0-20200605231317-fb2a6ca106ae/go.mod h1:l6TGeqJ92D github.com/openshift/build-machinery-go v0.0.0-20200424080330-082bf86082cc/go.mod h1:1CkcsT3aVebzRBzVTSbiKSkJMsC/CASqxesfqEMfJEc= github.com/openshift/client-go v0.0.0-20200608144219-584632b8fc73 h1:JePLt9EpNLF/30KsSsArrzxGWPaUIvYUt8Fwnw9wlgM= github.com/openshift/client-go v0.0.0-20200608144219-584632b8fc73/go.mod h1:+66gk3dEqw9e+WoiXjJFzWlS1KGhj9ZRHi/RI/YG/ZM= +github.com/openshift/gssapi v0.0.0-20161010215902-5fb4217df13b h1:it0YPE/evO6/m8t8wxis9KFI2F/aleOKsI6d9uz0cEk= github.com/openshift/gssapi v0.0.0-20161010215902-5fb4217df13b/go.mod h1:tNrEB5k8SI+g5kOlsCmL2ELASfpqEofI0+FLBgBdN08= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= @@ -713,6 +713,8 @@ github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pg2000/dynsoap v0.0.0-20210302131910-d513cf169ae8 h1:9LDPod2FvUWpuyIa+CbmHZ9MX+sY65sVzlGMdixdZrs= +github.com/pg2000/dynsoap v0.0.0-20210302131910-d513cf169ae8/go.mod h1:Q5lQc3H1nziGjQSmVSWjDS13pOkDnqZH/6Qli1GygSo= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= @@ -786,8 +788,6 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= -github.com/sanyu/dynectsoap v0.0.0-20181203081243-b83de5edc4e0 h1:vOcHdR1nu7DO4BAx1rwzdHV7jQTzW3gqcBT5qxHSc6A= -github.com/sanyu/dynectsoap v0.0.0-20181203081243-b83de5edc4e0/go.mod h1:FeplEtXXejBYC4NPAFTrs5L7KuK+5RL9bf5nB2vZe9o= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f h1:WSnaD0/cvbKJgSTYbjAPf4RJXVvNNDAwVm+W8wEmnGE= github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8= @@ -948,8 +948,6 @@ golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1062,7 +1060,6 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1073,9 +1070,6 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78 h1:nVuTkr9L6Bq62qpUqKo/RnZCFfzDBL0bYo6w9OJUqZY= -golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/provider/dyn/dyn.go b/provider/dyn/dyn.go index b83a178db..6c59c8a5a 100644 --- a/provider/dyn/dyn.go +++ b/provider/dyn/dyn.go @@ -24,10 +24,11 @@ import ( "strings" "time" + "github.com/pg2000/dynsoap/pkg/dynsoap" + log "github.com/sirupsen/logrus" "github.com/nesv/go-dynect/dynect" - "github.com/sanyu/dynectsoap/dynectsoap" "sigs.k8s.io/external-dns/endpoint" "sigs.k8s.io/external-dns/plan" @@ -250,7 +251,7 @@ func apiRetryLoop(f func() error) error { return err } -func (d *dynProviderState) allRecordsToEndpoints(records *dynectsoap.GetAllRecordsResponseType) []*endpoint.Endpoint { +func (d *dynProviderState) allRecordsToEndpoints(records *dynsoap.GetAllRecordsResponseType) []*endpoint.Endpoint { result := []*endpoint.Endpoint{} //Convert each record to an endpoint @@ -330,20 +331,23 @@ func (d *dynProviderState) fetchZoneSerial(client *dynect.Client, zone string) ( } //Use SOAP to fetch all records with a single call -func (d *dynProviderState) fetchAllRecordsInZone(zone string) (*dynectsoap.GetAllRecordsResponseType, error) { +func (d *dynProviderState) fetchAllRecordsInZone(zone string) (*dynsoap.GetAllRecordsResponseType, error) { var err error - client := dynectsoap.NewClient("https://api2.dynect.net/SOAP/") - service := dynectsoap.NewDynect(client) - sessionRequest := dynectsoap.SessionLoginRequestType{ + service := dynsoap.NewDynectClient("https://api2.dynect.net/SOAP/") + + sessionRequest := dynsoap.SessionLoginRequestType{ Customer_name: d.CustomerName, User_name: d.Username, Password: d.Password, Fault_incompat: 0, } - resp := dynectsoap.SessionLoginResponseType{} + + var resp *dynsoap.SessionLoginResponseType + err = apiRetryLoop(func() error { - return service.Do(&sessionRequest, &resp) + resp, err = service.SessionLogin(&sessionRequest) + return err }) if err != nil { @@ -352,46 +356,56 @@ func (d *dynProviderState) fetchAllRecordsInZone(zone string) (*dynectsoap.GetAl token := resp.Data.Token - logoutRequest := dynectsoap.SessionLogoutRequestType{ + logoutRequest := &dynsoap.SessionLogoutRequestType{ Token: token, Fault_incompat: 0, } - logoutResponse := dynectsoap.SessionLogoutResponseType{} - defer service.Do(&logoutRequest, &logoutResponse) - req := dynectsoap.GetAllRecordsRequestType{ + defer service.SessionLogout(logoutRequest) + + req := dynsoap.GetAllRecordsRequestType{ Token: token, Zone: zone, Fault_incompat: 0, } - records := dynectsoap.GetAllRecordsResponseType{} + + var records = &dynsoap.GetAllRecordsResponseType{} + err = apiRetryLoop(func() error { - return service.Do(&req, &records) + records, err = service.GetAllRecords(&req) + return err }) if err != nil { return nil, err } + log.Debugf("Got all Records, status is %s", records.Status) if strings.ToLower(records.Status) == "incomplete" { - jobRequest := dynectsoap.GetJobRequestType{ + jobRequest := dynsoap.GetJobRequestType{ Token: token, Job_id: records.Job_id, Fault_incompat: 0, } - jobResults := dynectsoap.GetJobResponseType{} + var jobResults = dynsoap.GetJobResponseType{} err = apiRetryLoop(func() error { - return service.GetJobRetry(&jobRequest, &jobResults) + jobResults, err := service.GetJob(&jobRequest) + if strings.ToLower(jobResults.Status) == "incomplete" { + return fmt.Errorf("job is incomplete") + } + return err }) + if err != nil { return nil, err } - return jobResults.Data.(*dynectsoap.GetAllRecordsResponseType), nil + + return jobResults.Data.(*dynsoap.GetAllRecordsResponseType), nil } - return &records, nil + return records, nil } // buildLinkToRecord build a resource link. The symmetry of the dyn API is used to save From ecc83973b02cb71e42a8570ad7930ae71f5c8339 Mon Sep 17 00:00:00 2001 From: pg2000 Date: Tue, 9 Mar 2021 11:28:20 +0100 Subject: [PATCH 065/175] feat: add move from dynectsoap to dynsoap --- go.mod | 4 ++-- go.sum | 22 ++++++++++++++-------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index c2161ea9e..feff79fa2 100644 --- a/go.mod +++ b/go.mod @@ -41,11 +41,11 @@ require ( github.com/openshift/client-go v0.0.0-20200608144219-584632b8fc73 github.com/oracle/oci-go-sdk v21.4.0+incompatible github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014 - github.com/pg2000/dynsoap v0.0.0-20210302131910-d513cf169ae8 github.com/pkg/errors v0.9.1 github.com/projectcontour/contour v1.5.0 github.com/prometheus/client_golang v1.7.1 - github.com/scaleway/scaleway-sdk-go v1.0.0-beta.6.0.20200623155123-84df6c4b5301 + github.com/sanyu/dynectsoap v0.0.0-20181203081243-b83de5edc4e0 + github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f github.com/sirupsen/logrus v1.6.0 github.com/smartystreets/gunit v1.3.4 // indirect github.com/stretchr/testify v1.6.1 diff --git a/go.sum b/go.sum index 51835d8ed..23127e8a7 100644 --- a/go.sum +++ b/go.sum @@ -92,7 +92,6 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5 h1:P5U+E4x5OkVEKQDklVPmzs71WM56RTTRqV4OrDC//Y4= github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5/go.mod h1:976q2ETgjT2snVCf2ZaBnyBbVoPERGjUz+0sofzEfro= github.com/aliyun/alibaba-cloud-sdk-go v1.61.357 h1:3ynCSeUh9OtJLd/OzLapM1DLDv2g+0yyDdkLqSfZCaQ= github.com/aliyun/alibaba-cloud-sdk-go v1.61.357/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA= @@ -128,6 +127,8 @@ github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bodgit/tsig v0.0.2 h1:seNt23SrPW8dkWoyRYzdeuqFEzr+lDc0dAJvo94xB8U= github.com/bodgit/tsig v0.0.2/go.mod h1:0mYe0t9it36SOvDQyeFekc7bLtvljFz7H9vHS/nYbgc= +github.com/bodgit/tsig v1.1.1 h1:SViReRa8KyaweqdJ3ojdYqIE3xDyJlR3G+6wAsSbLCo= +github.com/bodgit/tsig v1.1.1/go.mod h1:8LZ3Mn7AVZHH8GN2ArvzB7msHfLjoptWsdPEJRSw/uo= github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= @@ -426,9 +427,7 @@ github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= -github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ= github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= @@ -484,8 +483,6 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hooklift/gowsdl v0.4.0 h1:luskQG8h3M0CYrcSFl9ObpWs3pzIsEfYou1cuSwKiCk= -github.com/hooklift/gowsdl v0.4.0/go.mod h1:TYmt7jpe3F5zLlMtKGetjHLwUBIAF5JCd+NYq+mQ/Zk= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= @@ -513,6 +510,8 @@ github.com/jcmturner/gokrb5/v8 v8.4.1/go.mod h1:T1hnNppQsBtxW0tCHMHTkAt8n/sABdzZ github.com/jcmturner/rpc/v2 v2.0.2 h1:gMB4IwRXYsWw4Bc6o/az2HJgFUA1ffSh90i26ZJ6Xl0= github.com/jcmturner/rpc/v2 v2.0.2/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jinzhu/copier v0.1.0 h1:Vh8xALtH3rrKGB/XIRe5d0yCTHPZFauWPLvdpDAbi88= +github.com/jinzhu/copier v0.1.0/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -600,6 +599,8 @@ github.com/maxatome/go-testdeep v1.4.0/go.mod h1:011SgQ6efzZYAen6fDn4BqQ+lUR72ys github.com/mholt/archiver/v3 v3.3.0/go.mod h1:YnQtqsp+94Rwd0D/rk5cnLrxusUBUXg+08Ebtr1Mqao= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.6/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.30 h1:Qww6FseFn8PRfw07jueqIXqodm0JKiiKuK0DeXSqfyo= +github.com/miekg/dns v1.1.30/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.36-0.20210109083720-731b191cabd1 h1:kZZmnTeY2r+88mDNCVV/uCXL2gG3rkVPTN9jcYfGQcI= github.com/miekg/dns v1.1.36-0.20210109083720-731b191cabd1/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= @@ -689,7 +690,6 @@ github.com/openshift/api v0.0.0-20200605231317-fb2a6ca106ae/go.mod h1:l6TGeqJ92D github.com/openshift/build-machinery-go v0.0.0-20200424080330-082bf86082cc/go.mod h1:1CkcsT3aVebzRBzVTSbiKSkJMsC/CASqxesfqEMfJEc= github.com/openshift/client-go v0.0.0-20200608144219-584632b8fc73 h1:JePLt9EpNLF/30KsSsArrzxGWPaUIvYUt8Fwnw9wlgM= github.com/openshift/client-go v0.0.0-20200608144219-584632b8fc73/go.mod h1:+66gk3dEqw9e+WoiXjJFzWlS1KGhj9ZRHi/RI/YG/ZM= -github.com/openshift/gssapi v0.0.0-20161010215902-5fb4217df13b h1:it0YPE/evO6/m8t8wxis9KFI2F/aleOKsI6d9uz0cEk= github.com/openshift/gssapi v0.0.0-20161010215902-5fb4217df13b/go.mod h1:tNrEB5k8SI+g5kOlsCmL2ELASfpqEofI0+FLBgBdN08= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= @@ -713,8 +713,6 @@ github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/pg2000/dynsoap v0.0.0-20210302131910-d513cf169ae8 h1:9LDPod2FvUWpuyIa+CbmHZ9MX+sY65sVzlGMdixdZrs= -github.com/pg2000/dynsoap v0.0.0-20210302131910-d513cf169ae8/go.mod h1:Q5lQc3H1nziGjQSmVSWjDS13pOkDnqZH/6Qli1GygSo= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= @@ -788,6 +786,8 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/sanyu/dynectsoap v0.0.0-20181203081243-b83de5edc4e0 h1:vOcHdR1nu7DO4BAx1rwzdHV7jQTzW3gqcBT5qxHSc6A= +github.com/sanyu/dynectsoap v0.0.0-20181203081243-b83de5edc4e0/go.mod h1:FeplEtXXejBYC4NPAFTrs5L7KuK+5RL9bf5nB2vZe9o= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f h1:WSnaD0/cvbKJgSTYbjAPf4RJXVvNNDAwVm+W8wEmnGE= github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8= @@ -948,6 +948,8 @@ golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1060,6 +1062,7 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1070,6 +1073,9 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78 h1:nVuTkr9L6Bq62qpUqKo/RnZCFfzDBL0bYo6w9OJUqZY= +golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From 425e8773ccc69b626547aaf10608a6d10f471673 Mon Sep 17 00:00:00 2001 From: pg2000 Date: Tue, 9 Mar 2021 11:29:52 +0100 Subject: [PATCH 066/175] feat: add move from dynectsoap to dynsoap --- go.mod | 2 +- go.sum | 26 ++++++++------------------ 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/go.mod b/go.mod index feff79fa2..1fd1dbfd4 100644 --- a/go.mod +++ b/go.mod @@ -41,10 +41,10 @@ require ( github.com/openshift/client-go v0.0.0-20200608144219-584632b8fc73 github.com/oracle/oci-go-sdk v21.4.0+incompatible github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014 + github.com/pg2000/dynsoap v0.0.0-20210302131910-d513cf169ae8 github.com/pkg/errors v0.9.1 github.com/projectcontour/contour v1.5.0 github.com/prometheus/client_golang v1.7.1 - github.com/sanyu/dynectsoap v0.0.0-20181203081243-b83de5edc4e0 github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f github.com/sirupsen/logrus v1.6.0 github.com/smartystreets/gunit v1.3.4 // indirect diff --git a/go.sum b/go.sum index 23127e8a7..b4df6053a 100644 --- a/go.sum +++ b/go.sum @@ -92,6 +92,7 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5 h1:P5U+E4x5OkVEKQDklVPmzs71WM56RTTRqV4OrDC//Y4= github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5/go.mod h1:976q2ETgjT2snVCf2ZaBnyBbVoPERGjUz+0sofzEfro= github.com/aliyun/alibaba-cloud-sdk-go v1.61.357 h1:3ynCSeUh9OtJLd/OzLapM1DLDv2g+0yyDdkLqSfZCaQ= github.com/aliyun/alibaba-cloud-sdk-go v1.61.357/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA= @@ -127,8 +128,6 @@ github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bodgit/tsig v0.0.2 h1:seNt23SrPW8dkWoyRYzdeuqFEzr+lDc0dAJvo94xB8U= github.com/bodgit/tsig v0.0.2/go.mod h1:0mYe0t9it36SOvDQyeFekc7bLtvljFz7H9vHS/nYbgc= -github.com/bodgit/tsig v1.1.1 h1:SViReRa8KyaweqdJ3ojdYqIE3xDyJlR3G+6wAsSbLCo= -github.com/bodgit/tsig v1.1.1/go.mod h1:8LZ3Mn7AVZHH8GN2ArvzB7msHfLjoptWsdPEJRSw/uo= github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= @@ -427,7 +426,9 @@ github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ= github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= @@ -483,6 +484,8 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hooklift/gowsdl v0.4.0 h1:luskQG8h3M0CYrcSFl9ObpWs3pzIsEfYou1cuSwKiCk= +github.com/hooklift/gowsdl v0.4.0/go.mod h1:TYmt7jpe3F5zLlMtKGetjHLwUBIAF5JCd+NYq+mQ/Zk= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= @@ -510,8 +513,6 @@ github.com/jcmturner/gokrb5/v8 v8.4.1/go.mod h1:T1hnNppQsBtxW0tCHMHTkAt8n/sABdzZ github.com/jcmturner/rpc/v2 v2.0.2 h1:gMB4IwRXYsWw4Bc6o/az2HJgFUA1ffSh90i26ZJ6Xl0= github.com/jcmturner/rpc/v2 v2.0.2/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jinzhu/copier v0.1.0 h1:Vh8xALtH3rrKGB/XIRe5d0yCTHPZFauWPLvdpDAbi88= -github.com/jinzhu/copier v0.1.0/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -599,8 +600,6 @@ github.com/maxatome/go-testdeep v1.4.0/go.mod h1:011SgQ6efzZYAen6fDn4BqQ+lUR72ys github.com/mholt/archiver/v3 v3.3.0/go.mod h1:YnQtqsp+94Rwd0D/rk5cnLrxusUBUXg+08Ebtr1Mqao= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.6/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.30 h1:Qww6FseFn8PRfw07jueqIXqodm0JKiiKuK0DeXSqfyo= -github.com/miekg/dns v1.1.30/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.36-0.20210109083720-731b191cabd1 h1:kZZmnTeY2r+88mDNCVV/uCXL2gG3rkVPTN9jcYfGQcI= github.com/miekg/dns v1.1.36-0.20210109083720-731b191cabd1/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= @@ -690,6 +689,7 @@ github.com/openshift/api v0.0.0-20200605231317-fb2a6ca106ae/go.mod h1:l6TGeqJ92D github.com/openshift/build-machinery-go v0.0.0-20200424080330-082bf86082cc/go.mod h1:1CkcsT3aVebzRBzVTSbiKSkJMsC/CASqxesfqEMfJEc= github.com/openshift/client-go v0.0.0-20200608144219-584632b8fc73 h1:JePLt9EpNLF/30KsSsArrzxGWPaUIvYUt8Fwnw9wlgM= github.com/openshift/client-go v0.0.0-20200608144219-584632b8fc73/go.mod h1:+66gk3dEqw9e+WoiXjJFzWlS1KGhj9ZRHi/RI/YG/ZM= +github.com/openshift/gssapi v0.0.0-20161010215902-5fb4217df13b h1:it0YPE/evO6/m8t8wxis9KFI2F/aleOKsI6d9uz0cEk= github.com/openshift/gssapi v0.0.0-20161010215902-5fb4217df13b/go.mod h1:tNrEB5k8SI+g5kOlsCmL2ELASfpqEofI0+FLBgBdN08= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= @@ -713,6 +713,8 @@ github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pg2000/dynsoap v0.0.0-20210302131910-d513cf169ae8 h1:9LDPod2FvUWpuyIa+CbmHZ9MX+sY65sVzlGMdixdZrs= +github.com/pg2000/dynsoap v0.0.0-20210302131910-d513cf169ae8/go.mod h1:Q5lQc3H1nziGjQSmVSWjDS13pOkDnqZH/6Qli1GygSo= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= @@ -786,8 +788,6 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= -github.com/sanyu/dynectsoap v0.0.0-20181203081243-b83de5edc4e0 h1:vOcHdR1nu7DO4BAx1rwzdHV7jQTzW3gqcBT5qxHSc6A= -github.com/sanyu/dynectsoap v0.0.0-20181203081243-b83de5edc4e0/go.mod h1:FeplEtXXejBYC4NPAFTrs5L7KuK+5RL9bf5nB2vZe9o= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f h1:WSnaD0/cvbKJgSTYbjAPf4RJXVvNNDAwVm+W8wEmnGE= github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8= @@ -948,8 +948,6 @@ golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1062,7 +1060,6 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1073,9 +1070,6 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78 h1:nVuTkr9L6Bq62qpUqKo/RnZCFfzDBL0bYo6w9OJUqZY= -golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1225,12 +1219,8 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -istio.io/api v0.0.0-20200529165953-72dad51d4ffc h1:cR9GmbIBAz3FnY3tgs1SRn/uiznhtvG+mZBfD1p2vIA= -istio.io/api v0.0.0-20200529165953-72dad51d4ffc/go.mod h1:kyq3g5w42zl/AKlbzDGppYpGMQYMYMyZKeq0/eexML8= istio.io/api v0.0.0-20210128181506-0c4b8e54850f h1:zUFsawgPj5oI9p5cf91YCExRlxLIVsEkIunN9ODUSJs= istio.io/api v0.0.0-20210128181506-0c4b8e54850f/go.mod h1:88HN3o1fSD1jo+Z1WTLlJfMm9biopur6Ct9BFKjiB64= -istio.io/client-go v0.0.0-20200529172309-31c16ea3f751 h1:yH62fTmV+5l1XVTWcomsc1jjH/oH9u/tTgn5NVmdIac= -istio.io/client-go v0.0.0-20200529172309-31c16ea3f751/go.mod h1:4SGvmmus5HNFdqQsIL+uQO1PbAhjQKtSjMTqwsvYHlg= istio.io/client-go v0.0.0-20210128182905-ee2edd059e02 h1:ZA8Y2gKkKtEeYuKfqlEzIBDfU4IE5uIAdsXDeD41T9w= istio.io/client-go v0.0.0-20210128182905-ee2edd059e02/go.mod h1:oXMjFUWhxlReUSbg4i3GjKgOhSX1WgD68ZNlHQEcmQg= istio.io/gogo-genproto v0.0.0-20190904133402-ee07f2785480/go.mod h1:uKtbae4K9k2rjjX4ToV0l6etglbc1i7gqQ94XdkshzY= From 6adbd4ec25d81f94afe6a9407197e1993818d971 Mon Sep 17 00:00:00 2001 From: Kundan Kumar Date: Tue, 9 Mar 2021 17:42:30 +0530 Subject: [PATCH 067/175] external-dns configuration update --- docs/tutorials/rfc2136.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/tutorials/rfc2136.md b/docs/tutorials/rfc2136.md index 10210dd91..923477813 100644 --- a/docs/tutorials/rfc2136.md +++ b/docs/tutorials/rfc2136.md @@ -376,7 +376,6 @@ You'll want to configure `external-dns` similarly to the following: ```text ... - --provider=rfc2136 - - --rfc2136-gss-tsig - --rfc2136-host=123.123.123.123 - --rfc2136-port=53 - --rfc2136-zone=your-domain.com @@ -384,4 +383,4 @@ You'll want to configure `external-dns` similarly to the following: - --rfc2136-kerberos-password=your-domain-password - --rfc2136-tsig-axfr # needed to enable zone transfers, which is required for deletion of records. ... -``` \ No newline at end of file +``` From add7a4102adc6d4bf8ce6ead81611f4cd60b7e91 Mon Sep 17 00:00:00 2001 From: Dinar Valeev Date: Wed, 10 Mar 2021 11:27:40 +0100 Subject: [PATCH 068/175] Approve crd v1 All CRDs under k8s.io and kubernetes.io API groups should go through API approval. Signed-off-by: Dinar Valeev --- docs/contributing/crd-source/crd-manifest.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/contributing/crd-source/crd-manifest.yaml b/docs/contributing/crd-source/crd-manifest.yaml index 4fb16468a..dc1a1a6f1 100644 --- a/docs/contributing/crd-source/crd-manifest.yaml +++ b/docs/contributing/crd-source/crd-manifest.yaml @@ -5,6 +5,7 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.5.0 + api-approved.kubernetes.io: "https://github.com/kubernetes-sigs/external-dns/pull/2007" creationTimestamp: null name: dnsendpoints.externaldns.k8s.io spec: From d0472db86647a1226bbeabc27ab7ec27b0e69683 Mon Sep 17 00:00:00 2001 From: Brock Alberry <61976254+ba-work@users.noreply.github.com> Date: Wed, 10 Mar 2021 14:41:02 +0000 Subject: [PATCH 069/175] add realm flag validation --- pkg/apis/externaldns/validation/validation.go | 4 +- .../externaldns/validation/validation_test.go | 45 +++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/pkg/apis/externaldns/validation/validation.go b/pkg/apis/externaldns/validation/validation.go index 81f27a34a..3251a7b09 100644 --- a/pkg/apis/externaldns/validation/validation.go +++ b/pkg/apis/externaldns/validation/validation.go @@ -92,8 +92,8 @@ func ValidateConfig(cfg *externaldns.Config) error { } if cfg.RFC2136GSSTSIG { - if cfg.RFC2136KerberosPassword == "" || cfg.RFC2136KerberosUsername == "" { - return errors.New("--rfc2136-kerberos-username and --rfc2136-kerberos-password both required when specifying --rfc2136-gss-tsig option") + if cfg.RFC2136KerberosPassword == "" || cfg.RFC2136KerberosUsername == "" || cfg.RFC2136KerberosRealm == "" { + return errors.New("--rfc2136-kerberos-realm, --rfc2136-kerberos-username, and --rfc2136-kerberos-password are required when specifying --rfc2136-gss-tsig option") } } } diff --git a/pkg/apis/externaldns/validation/validation_test.go b/pkg/apis/externaldns/validation/validation_test.go index 98c5a5068..8bb6fdafa 100644 --- a/pkg/apis/externaldns/validation/validation_test.go +++ b/pkg/apis/externaldns/validation/validation_test.go @@ -158,6 +158,7 @@ func TestValidateBadRfc2136GssTsigConfig(t *testing.T) { Sources: []string{"test-source"}, Provider: "rfc2136", RFC2136GSSTSIG: true, + RFC2136KerberosRealm: "test-realm", RFC2136KerberosUsername: "test-user", RFC2136KerberosPassword: "", RFC2136MinTTL: 3600, @@ -167,6 +168,7 @@ func TestValidateBadRfc2136GssTsigConfig(t *testing.T) { Sources: []string{"test-source"}, Provider: "rfc2136", RFC2136GSSTSIG: true, + RFC2136KerberosRealm: "test-realm", RFC2136KerberosUsername: "", RFC2136KerberosPassword: "test-pass", RFC2136MinTTL: 3600, @@ -177,6 +179,48 @@ func TestValidateBadRfc2136GssTsigConfig(t *testing.T) { Provider: "rfc2136", RFC2136GSSTSIG: true, RFC2136Insecure: true, + RFC2136KerberosRealm: "test-realm", + RFC2136KerberosUsername: "test-user", + RFC2136KerberosPassword: "test-pass", + RFC2136MinTTL: 3600, + }, + { + LogFormat: "json", + Sources: []string{"test-source"}, + Provider: "rfc2136", + RFC2136GSSTSIG: true, + RFC2136KerberosRealm: "", + RFC2136KerberosUsername: "test-user", + RFC2136KerberosPassword: "", + RFC2136MinTTL: 3600, + }, + { + LogFormat: "json", + Sources: []string{"test-source"}, + Provider: "rfc2136", + RFC2136GSSTSIG: true, + RFC2136KerberosRealm: "", + RFC2136KerberosUsername: "", + RFC2136KerberosPassword: "test-pass", + RFC2136MinTTL: 3600, + }, + { + LogFormat: "json", + Sources: []string{"test-source"}, + Provider: "rfc2136", + RFC2136GSSTSIG: true, + RFC2136Insecure: true, + RFC2136KerberosRealm: "", + RFC2136KerberosUsername: "test-user", + RFC2136KerberosPassword: "test-pass", + RFC2136MinTTL: 3600, + }, + { + LogFormat: "json", + Sources: []string{"test-source"}, + Provider: "rfc2136", + RFC2136GSSTSIG: true, + RFC2136KerberosRealm: "", RFC2136KerberosUsername: "test-user", RFC2136KerberosPassword: "test-pass", RFC2136MinTTL: 3600, @@ -198,6 +242,7 @@ func TestValidateGoodRfc2136GssTsigConfig(t *testing.T) { Provider: "rfc2136", RFC2136GSSTSIG: true, RFC2136Insecure: false, + RFC2136KerberosRealm: "test-realm", RFC2136KerberosUsername: "test-user", RFC2136KerberosPassword: "test-pass", RFC2136MinTTL: 3600, From dad038b7f01e98b77b63b7412b2b689375f071e1 Mon Sep 17 00:00:00 2001 From: Brock Alberry <61976254+ba-work@users.noreply.github.com> Date: Wed, 10 Mar 2021 16:19:57 +0000 Subject: [PATCH 070/175] corrected flag help output --- pkg/apis/externaldns/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 9aba7355c..210316f67 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -434,7 +434,7 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("rfc2136-tsig-secret-alg", "When using the RFC2136 provider, specify the TSIG (base64) value to attached to DNS messages (required when --rfc2136-insecure=false)").Default(defaultConfig.RFC2136TSIGSecretAlg).StringVar(&cfg.RFC2136TSIGSecretAlg) app.Flag("rfc2136-tsig-axfr", "When using the RFC2136 provider, specify the TSIG (base64) value to attached to DNS messages (required when --rfc2136-insecure=false)").BoolVar(&cfg.RFC2136TAXFR) app.Flag("rfc2136-min-ttl", "When using the RFC2136 provider, specify minimal TTL (in duration format) for records. This value will be used if the provided TTL for a service/ingress is lower than this").Default(defaultConfig.RFC2136MinTTL.String()).DurationVar(&cfg.RFC2136MinTTL) - app.Flag("rfc2136-gss-tsig", "When using the RFC2136 provider, specify whether to use secure updates with GSS-TSIG using Kerberos (default: false, requires --rfc2136-kerberos-username and rfc2136-kerberos-password)").Default(strconv.FormatBool(defaultConfig.RFC2136GSSTSIG)).BoolVar(&cfg.RFC2136GSSTSIG) + app.Flag("rfc2136-gss-tsig", "When using the RFC2136 provider, specify whether to use secure updates with GSS-TSIG using Kerberos (default: false, requires --rfc2136-kerberos-realm, --rfc2136-kerberos-username, and rfc2136-kerberos-password)").Default(strconv.FormatBool(defaultConfig.RFC2136GSSTSIG)).BoolVar(&cfg.RFC2136GSSTSIG) app.Flag("rfc2136-kerberos-username", "When using the RFC2136 provider with GSS-TSIG, specify the username of the user with permissions to update DNS records (required when --rfc2136-gss-tsig=true)").Default(defaultConfig.RFC2136KerberosUsername).StringVar(&cfg.RFC2136KerberosUsername) app.Flag("rfc2136-kerberos-password", "When using the RFC2136 provider with GSS-TSIG, specify the password of the user with permissions to update DNS records (required when --rfc2136-gss-tsig=true)").Default(defaultConfig.RFC2136KerberosPassword).StringVar(&cfg.RFC2136KerberosPassword) app.Flag("rfc2136-kerberos-realm", "When using the RFC2136 provider with GSS-TSIG, specify the realm of the user with permissions to update DNS records (required when --rfc2136-gss-tsig=true)").Default(defaultConfig.RFC2136KerberosRealm).StringVar(&cfg.RFC2136KerberosRealm) From b1dd82e8bab04cf3a5ae0049312690256398d1ca Mon Sep 17 00:00:00 2001 From: Thomas Stig Jacobsen Date: Thu, 11 Mar 2021 14:22:41 +0100 Subject: [PATCH 071/175] Further bump to 1.16.1 --- .github/workflows/ci.yml | 2 +- Dockerfile | 2 +- Dockerfile.mini | 2 +- docs/contributing/getting-started.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 19266d35f..f7d8114c6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: - name: Set up Go 1.x uses: actions/setup-go@v2 with: - go-version: ^1.16 + go-version: ^1.16.1 id: go - name: Check out code into the Go module directory diff --git a/Dockerfile b/Dockerfile index dd9e80552..31611d8d6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,7 @@ # builder image ARG ARCH -FROM golang:1.16 as builder +FROM golang:1.16.1 as builder ARG ARCH WORKDIR /sigs.k8s.io/external-dns diff --git a/Dockerfile.mini b/Dockerfile.mini index d3b02877f..c7122fcaf 100644 --- a/Dockerfile.mini +++ b/Dockerfile.mini @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM golang:1.16 as builder +FROM golang:1.16.1 as builder WORKDIR /sigs.k8s.io/external-dns diff --git a/docs/contributing/getting-started.md b/docs/contributing/getting-started.md index 9a51861b4..2fd7222c1 100644 --- a/docs/contributing/getting-started.md +++ b/docs/contributing/getting-started.md @@ -1,7 +1,7 @@ # Quick Start - [Git](https://git-scm.com/downloads) -- [Go 1.16+](https://golang.org/dl/) +- [Go 1.16.1+](https://golang.org/dl/) - [Go modules](https://github.com/golang/go/wiki/Modules) - [golangci-lint](https://github.com/golangci/golangci-lint) - [Docker](https://docs.docker.com/install/) From ca3d3f81e2be4bf8c94154fb77066691f86c301a Mon Sep 17 00:00:00 2001 From: pg2000 Date: Fri, 12 Mar 2021 06:59:46 +0100 Subject: [PATCH 072/175] feat: add move from dynectsoap to dynsoap --- go.mod | 2 +- go.sum | 2 - provider/dyn/dyn.go | 3 +- provider/dyn/soap/client.go | 44 + provider/dyn/soap/services.go | 32865 ++++++++++++++++++++++++++++++++ 5 files changed, 32911 insertions(+), 5 deletions(-) create mode 100644 provider/dyn/soap/client.go create mode 100644 provider/dyn/soap/services.go diff --git a/go.mod b/go.mod index 1fd1dbfd4..f23e8a1ee 100644 --- a/go.mod +++ b/go.mod @@ -30,6 +30,7 @@ require ( github.com/google/go-cmp v0.4.1 github.com/gophercloud/gophercloud v0.1.0 github.com/gorilla/mux v1.7.4 // indirect + github.com/hooklift/gowsdl v0.4.0 github.com/infobloxopen/infoblox-go-client v0.0.0-20180606155407-61dc5f9b0a65 github.com/linki/instrumented_http v0.2.0 github.com/linode/linodego v0.19.0 @@ -41,7 +42,6 @@ require ( github.com/openshift/client-go v0.0.0-20200608144219-584632b8fc73 github.com/oracle/oci-go-sdk v21.4.0+incompatible github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014 - github.com/pg2000/dynsoap v0.0.0-20210302131910-d513cf169ae8 github.com/pkg/errors v0.9.1 github.com/projectcontour/contour v1.5.0 github.com/prometheus/client_golang v1.7.1 diff --git a/go.sum b/go.sum index b4df6053a..c078abc24 100644 --- a/go.sum +++ b/go.sum @@ -713,8 +713,6 @@ github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/pg2000/dynsoap v0.0.0-20210302131910-d513cf169ae8 h1:9LDPod2FvUWpuyIa+CbmHZ9MX+sY65sVzlGMdixdZrs= -github.com/pg2000/dynsoap v0.0.0-20210302131910-d513cf169ae8/go.mod h1:Q5lQc3H1nziGjQSmVSWjDS13pOkDnqZH/6Qli1GygSo= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= diff --git a/provider/dyn/dyn.go b/provider/dyn/dyn.go index 6c59c8a5a..49da03651 100644 --- a/provider/dyn/dyn.go +++ b/provider/dyn/dyn.go @@ -24,8 +24,6 @@ import ( "strings" "time" - "github.com/pg2000/dynsoap/pkg/dynsoap" - log "github.com/sirupsen/logrus" "github.com/nesv/go-dynect/dynect" @@ -33,6 +31,7 @@ import ( "sigs.k8s.io/external-dns/endpoint" "sigs.k8s.io/external-dns/plan" "sigs.k8s.io/external-dns/provider" + dynsoap "sigs.k8s.io/external-dns/provider/dyn/soap" ) const ( diff --git a/provider/dyn/soap/client.go b/provider/dyn/soap/client.go new file mode 100644 index 000000000..4ec11c904 --- /dev/null +++ b/provider/dyn/soap/client.go @@ -0,0 +1,44 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package dynsoap + +import ( + "net/http" + "time" + + "github.com/hooklift/gowsdl/soap" +) + +// Returns a Dynect Client with a configured http.Client +// The default settings for the http.client are a timeout of +// 10 seconds and reading proxy variables from http.ProxyFromEnvironment +func NewDynectClient(url string) Dynect { + client := &http.Client{ + Timeout: time.Second * 10, + Transport: &http.Transport{ + Proxy: http.ProxyFromEnvironment, + }, + } + soapClient := soap.NewClient(url, soap.WithHTTPClient(client)) + return NewDynect(soapClient) +} + +// Returns a Dynect Client without a configured http.Client +func NewCustomDynectClient(url string, client http.Client) Dynect { + soapClient := soap.NewClient(url, soap.WithHTTPClient(&client)) + return NewDynect(soapClient) +} diff --git a/provider/dyn/soap/services.go b/provider/dyn/soap/services.go new file mode 100644 index 000000000..bb570e972 --- /dev/null +++ b/provider/dyn/soap/services.go @@ -0,0 +1,32865 @@ +// Code generated by gowsdl DO NOT EDIT. + +package dynsoap + +import ( + "context" + "encoding/xml" + "github.com/hooklift/gowsdl/soap" + "time" +) + +// against "unused imports" +var _ time.Time +var _ xml.Name + +type AnyType struct { + InnerXML string `xml:",innerxml"` +} + +type AnyURI string + +type NCName string + +type ErrorResponse ErrorResponseType + +type GetJobRequest GetJobRequestType + +type GetJobResponse GetJobResponseType + +type SessionLoginRequest SessionLoginRequestType + +type SessionLoginResponse SessionLoginResponseType + +type SessionLogoutRequest SessionLogoutRequestType + +type SessionLogoutResponse SessionLogoutResponseType + +type SessionIsAliveRequest SessionIsAliveRequestType + +type SessionIsAliveResponse SessionIsAliveResponseType + +type SessionKeepAliveRequest SessionKeepAliveRequestType + +type SessionKeepAliveResponse SessionKeepAliveResponseType + +type ScopeInRequest ScopeInRequestType + +type ScopeInResponse ScopeInResponseType + +type ScopeAsRequest ScopeAsRequestType + +type ScopeAsResponse ScopeAsResponseType + +type UnscopeRequest UnscopeRequestType + +type UnscopeResponse UnscopeResponseType + +type GetQueryStatsRequest GetQueryStatsRequestType + +type GetQueryStatsResponse GetQueryStatsResponseType + +type CreateGeoRequest CreateGeoRequestType + +type CreateGeoResponse CreateGeoResponseType + +type UpdateGeoRequest UpdateGeoRequestType + +type UpdateGeoResponse UpdateGeoResponseType + +type GetGeosRequest GetGeosRequestType + +type GetGeosResponse GetGeosResponseType + +type GetOneGeoRequest GetOneGeoRequestType + +type GetOneGeoResponse GetOneGeoResponseType + +type DeleteOneGeoRequest DeleteOneGeoRequestType + +type DeleteOneGeoResponse DeleteOneGeoResponseType + +type ActivateGeoRequest ActivateGeoRequestType + +type ActivateGeoResponse ActivateGeoResponseType + +type DeactivateGeoRequest DeactivateGeoRequestType + +type DeactivateGeoResponse DeactivateGeoResponseType + +type CreateGeoRegionGroupRequest CreateGeoRegionGroupRequestType + +type CreateGeoRegionGroupResponse CreateGeoRegionGroupResponseType + +type UpdateGeoRegionGroupRequest UpdateGeoRegionGroupRequestType + +type UpdateGeoRegionGroupResponse UpdateGeoRegionGroupResponseType + +type DeleteOneGeoRegionGroupRequest DeleteOneGeoRegionGroupRequestType + +type DeleteOneGeoRegionGroupResponse DeleteOneGeoRegionGroupResponseType + +type GetGeoRegionGroupsRequest GetGeoRegionGroupsRequestType + +type GetGeoRegionGroupsResponse GetGeoRegionGroupsResponseType + +type GetOneGeoRegionGroupRequest GetOneGeoRegionGroupRequestType + +type GetOneGeoRegionGroupResponse GetOneGeoRegionGroupResponseType + +type CreateGeoNodeRequest CreateGeoNodeRequestType + +type CreateGeoNodeResponse CreateGeoNodeResponseType + +type DeleteOneGeoNodeRequest DeleteOneGeoNodeRequestType + +type DeleteOneGeoNodeResponse DeleteOneGeoNodeResponseType + +type GetGeoNodesRequest GetGeoNodesRequestType + +type GetGeoNodesResponse GetGeoNodesResponseType + +type CreateDSFRequest CreateDSFRequestType + +type CreateDSFResponse CreateDSFResponseType + +type UpdateDSFRequest UpdateDSFRequestType + +type UpdateDSFResponse UpdateDSFResponseType + +type GetDSFsRequest GetDSFsRequestType + +type GetDSFsResponse GetDSFsResponseType + +type GetDSFNotifiersRequest GetDSFNotifiersRequestType + +type GetDSFNotifiersResponse GetDSFNotifiersResponseType + +type DeleteOneDSFRequest DeleteOneDSFRequestType + +type DeleteOneDSFResponse DeleteOneDSFResponseType + +type GetOneDSFRequest GetOneDSFRequestType + +type GetOneDSFResponse GetOneDSFResponseType + +type RevertDSFRequest RevertDSFRequestType + +type RevertDSFResponse RevertDSFResponseType + +type PublishDSFRequest PublishDSFRequestType + +type PublishDSFResponse PublishDSFResponseType + +type AddDSFNotifierRequest AddDSFNotifierRequestType + +type AddDSFNotifierResponse AddDSFNotifierResponseType + +type RemoveDSFNotifierRequest RemoveDSFNotifierRequestType + +type RemoveDSFNotifierResponse RemoveDSFNotifierResponseType + +type CreateDSFRulesetRequest CreateDSFRulesetRequestType + +type CreateDSFRulesetResponse CreateDSFRulesetResponseType + +type UpdateDSFRulesetRequest UpdateDSFRulesetRequestType + +type UpdateDSFRulesetResponse UpdateDSFRulesetResponseType + +type GetDSFRulesetsRequest GetDSFRulesetsRequestType + +type GetDSFRulesetsResponse GetDSFRulesetsResponseType + +type GetOneDSFRulesetRequest GetOneDSFRulesetRequestType + +type GetOneDSFRulesetResponse GetOneDSFRulesetResponseType + +type DeleteOneDSFRulesetRequest DeleteOneDSFRulesetRequestType + +type DeleteOneDSFRulesetResponse DeleteOneDSFRulesetResponseType + +type CreateDSFResponsePoolRequest CreateDSFResponsePoolRequestType + +type CreateDSFResponsePoolResponse CreateDSFResponsePoolResponseType + +type UpdateDSFResponsePoolRequest UpdateDSFResponsePoolRequestType + +type UpdateDSFResponsePoolResponse UpdateDSFResponsePoolResponseType + +type GetDSFResponsePoolsRequest GetDSFResponsePoolsRequestType + +type GetDSFResponsePoolsResponse GetDSFResponsePoolsResponseType + +type GetOneDSFResponsePoolRequest GetOneDSFResponsePoolRequestType + +type GetOneDSFResponsePoolResponse GetOneDSFResponsePoolResponseType + +type DeleteOneDSFResponsePoolRequest DeleteOneDSFResponsePoolRequestType + +type DeleteOneDSFResponsePoolResponse DeleteOneDSFResponsePoolResponseType + +type CreateDSFRecordSetFailoverChainRequest CreateDSFRecordSetFailoverChainRequestType + +type CreateDSFRecordSetFailoverChainResponse CreateDSFRecordSetFailoverChainResponseType + +type UpdateDSFRecordSetFailoverChainRequest UpdateDSFRecordSetFailoverChainRequestType + +type UpdateDSFRecordSetFailoverChainResponse UpdateDSFRecordSetFailoverChainResponseType + +type GetDSFRecordSetFailoverChainsRequest GetDSFRecordSetFailoverChainsRequestType + +type GetDSFRecordSetFailoverChainsResponse GetDSFRecordSetFailoverChainsResponseType + +type GetOneDSFRecordSetFailoverChainRequest GetOneDSFRecordSetFailoverChainRequestType + +type GetOneDSFRecordSetFailoverChainResponse GetOneDSFRecordSetFailoverChainResponseType + +type DeleteOneDSFRecordSetFailoverChainRequest DeleteOneDSFRecordSetFailoverChainRequestType + +type DeleteOneDSFRecordSetFailoverChainResponse DeleteOneDSFRecordSetFailoverChainResponseType + +type CreateDSFRecordSetRequest CreateDSFRecordSetRequestType + +type CreateDSFRecordSetResponse CreateDSFRecordSetResponseType + +type UpdateDSFRecordSetRequest UpdateDSFRecordSetRequestType + +type UpdateDSFRecordSetResponse UpdateDSFRecordSetResponseType + +type GetOneDSFRecordSetRequest GetOneDSFRecordSetRequestType + +type GetOneDSFRecordSetResponse GetOneDSFRecordSetResponseType + +type GetDSFRecordSetsRequest GetDSFRecordSetsRequestType + +type GetDSFRecordSetsResponse GetDSFRecordSetsResponseType + +type DeleteOneDSFRecordSetRequest DeleteOneDSFRecordSetRequestType + +type DeleteOneDSFRecordSetResponse DeleteOneDSFRecordSetResponseType + +type CreateDSFRecordRequest CreateDSFRecordRequestType + +type CreateDSFRecordResponse CreateDSFRecordResponseType + +type UpdateDSFRecordRequest UpdateDSFRecordRequestType + +type UpdateDSFRecordResponse UpdateDSFRecordResponseType + +type GetOneDSFRecordRequest GetOneDSFRecordRequestType + +type GetOneDSFRecordResponse GetOneDSFRecordResponseType + +type GetDSFRecordsRequest GetDSFRecordsRequestType + +type GetDSFRecordsResponse GetDSFRecordsResponseType + +type DeleteOneDSFRecordRequest DeleteOneDSFRecordRequestType + +type DeleteOneDSFRecordResponse DeleteOneDSFRecordResponseType + +type AddDSFNodeRequest AddDSFNodeRequestType + +type AddDSFNodeResponse AddDSFNodeResponseType + +type UpdateDSFNodesRequest UpdateDSFNodesRequestType + +type UpdateDSFNodesResponse UpdateDSFNodesResponseType + +type GetDSFNodesRequest GetDSFNodesRequestType + +type GetDSFNodesResponse GetDSFNodesResponseType + +type DeleteOneDSFNodeRequest DeleteOneDSFNodeRequestType + +type DeleteOneDSFNodeResponse DeleteOneDSFNodeResponseType + +type CreateDSFMonitorRequest CreateDSFMonitorRequestType + +type CreateDSFMonitorResponse CreateDSFMonitorResponseType + +type UpdateDSFMonitorRequest UpdateDSFMonitorRequestType + +type UpdateDSFMonitorResponse UpdateDSFMonitorResponseType + +type GetOneDSFMonitorRequest GetOneDSFMonitorRequestType + +type GetOneDSFMonitorResponse GetOneDSFMonitorResponseType + +type GetDSFMonitorsRequest GetDSFMonitorsRequestType + +type GetDSFMonitorsResponse GetDSFMonitorsResponseType + +type DeleteOneDSFMonitorRequest DeleteOneDSFMonitorRequestType + +type DeleteOneDSFMonitorResponse DeleteOneDSFMonitorResponseType + +type AddDSFMonitorNotifierRequest AddDSFMonitorNotifierRequestType + +type AddDSFMonitorNotifierResponse AddDSFMonitorNotifierResponseType + +type GetDSFMonitorSitesRequest GetDSFMonitorSitesRequestType + +type GetDSFMonitorSitesResponse GetDSFMonitorSitesResponseType + +type CreateNotifierRequest CreateNotifierRequestType + +type CreateNotifierResponse CreateNotifierResponseType + +type UpdateNotifierRequest UpdateNotifierRequestType + +type UpdateNotifierResponse UpdateNotifierResponseType + +type GetOneNotifierRequest GetOneNotifierRequestType + +type GetOneNotifierResponse GetOneNotifierResponseType + +type GetNotifiersRequest GetNotifiersRequestType + +type GetNotifiersResponse GetNotifiersResponseType + +type DeleteOneNotifierRequest DeleteOneNotifierRequestType + +type DeleteOneNotifierResponse DeleteOneNotifierResponseType + +type CreateConfigLimitRequest CreateConfigLimitRequestType + +type CreateConfigLimitResponse CreateConfigLimitResponseType + +type GetOneConfigLimitRequest GetOneConfigLimitRequestType + +type GetOneConfigLimitResponse GetOneConfigLimitResponseType + +type GetConfigLimitsRequest GetConfigLimitsRequestType + +type GetConfigLimitsResponse GetConfigLimitsResponseType + +type UpdateConfigLimitRequest UpdateConfigLimitRequestType + +type UpdateConfigLimitResponse UpdateConfigLimitResponseType + +type DeleteOneConfigLimitRequest DeleteOneConfigLimitRequestType + +type DeleteOneConfigLimitResponse DeleteOneConfigLimitResponseType + +type CreatePermissionGroupRequest CreatePermissionGroupRequestType + +type CreatePermissionGroupResponse CreatePermissionGroupResponseType + +type GetOnePermissionGroupRequest GetOnePermissionGroupRequestType + +type GetOnePermissionGroupResponse GetOnePermissionGroupResponseType + +type GetPermissionGroupsRequest GetPermissionGroupsRequestType + +type GetPermissionGroupsResponse GetPermissionGroupsResponseType + +type DeleteOnePermissionGroupRequest DeleteOnePermissionGroupRequestType + +type DeleteOnePermissionGroupResponse DeleteOnePermissionGroupResponseType + +type UpdatePermissionGroupRequest UpdatePermissionGroupRequestType + +type UpdatePermissionGroupResponse UpdatePermissionGroupResponseType + +type GetCustomerPermissionsRequest GetCustomerPermissionsRequestType + +type GetCustomerPermissionsResponse GetCustomerPermissionsResponseType + +type GetUserPermissionsRequest GetUserPermissionsRequestType + +type GetUserPermissionsResponse GetUserPermissionsResponseType + +type CheckPermissionsRequest CheckPermissionsRequestType + +type CheckPermissionsResponse CheckPermissionsResponseType + +type AddPermissionGroupUsersRequest AddPermissionGroupUsersRequestType + +type AddPermissionGroupUsersResponse AddPermissionGroupUsersResponseType + +type SetPermissionGroupUsersRequest SetPermissionGroupUsersRequestType + +type SetPermissionGroupUsersResponse SetPermissionGroupUsersResponseType + +type RemovePermissionGroupUsersRequest RemovePermissionGroupUsersRequestType + +type RemovePermissionGroupUsersResponse RemovePermissionGroupUsersResponseType + +type AddPermissionGroupSubgroupsRequest AddPermissionGroupSubgroupsRequestType + +type AddPermissionGroupSubgroupsResponse AddPermissionGroupSubgroupsResponseType + +type SetPermissionGroupSubgroupsRequest SetPermissionGroupSubgroupsRequestType + +type SetPermissionGroupSubgroupsResponse SetPermissionGroupSubgroupsResponseType + +type RemovePermissionGroupSubgroupsRequest RemovePermissionGroupSubgroupsRequestType + +type RemovePermissionGroupSubgroupsResponse RemovePermissionGroupSubgroupsResponseType + +type AddPermissionGroupPermissionsRequest AddPermissionGroupPermissionsRequestType + +type AddPermissionGroupPermissionsResponse AddPermissionGroupPermissionsResponseType + +type SetPermissionGroupPermissionsRequest SetPermissionGroupPermissionsRequestType + +type SetPermissionGroupPermissionsResponse SetPermissionGroupPermissionsResponseType + +type RemovePermissionGroupPermissionsRequest RemovePermissionGroupPermissionsRequestType + +type RemovePermissionGroupPermissionsResponse RemovePermissionGroupPermissionsResponseType + +type AddPermissionGroupZonesRequest AddPermissionGroupZonesRequestType + +type AddPermissionGroupZonesResponse AddPermissionGroupZonesResponseType + +type SetPermissionGroupZonesRequest SetPermissionGroupZonesRequestType + +type SetPermissionGroupZonesResponse SetPermissionGroupZonesResponseType + +type RemovePermissionGroupZonesRequest RemovePermissionGroupZonesRequestType + +type RemovePermissionGroupZonesResponse RemovePermissionGroupZonesResponseType + +type AddUserGroupsRequest AddUserGroupsRequestType + +type AddUserGroupsResponse AddUserGroupsResponseType + +type SetUserGroupsRequest SetUserGroupsRequestType + +type SetUserGroupsResponse SetUserGroupsResponseType + +type RemoveUserGroupsRequest RemoveUserGroupsRequestType + +type RemoveUserGroupsResponse RemoveUserGroupsResponseType + +type AddUserZonesRequest AddUserZonesRequestType + +type AddUserZonesResponse AddUserZonesResponseType + +type SetUserZonesRequest SetUserZonesRequestType + +type SetUserZonesResponse SetUserZonesResponseType + +type RemoveUserZonesRequest RemoveUserZonesRequestType + +type RemoveUserZonesResponse RemoveUserZonesResponseType + +type AddUserPermissionsRequest AddUserPermissionsRequestType + +type AddUserPermissionsResponse AddUserPermissionsResponseType + +type SetUserPermissionsRequest SetUserPermissionsRequestType + +type SetUserPermissionsResponse SetUserPermissionsResponseType + +type RemoveUserPermissionsRequest RemoveUserPermissionsRequestType + +type RemoveUserPermissionsResponse RemoveUserPermissionsResponseType + +type AddUserForbidsRequest AddUserForbidsRequestType + +type AddUserForbidsResponse AddUserForbidsResponseType + +type SetUserForbidsRequest SetUserForbidsRequestType + +type SetUserForbidsResponse SetUserForbidsResponseType + +type RemoveUserForbidsRequest RemoveUserForbidsRequestType + +type RemoveUserForbidsResponse RemoveUserForbidsResponseType + +type AddCustomerPermissionsRequest AddCustomerPermissionsRequestType + +type AddCustomerPermissionsResponse AddCustomerPermissionsResponseType + +type SetCustomerPermissionsRequest SetCustomerPermissionsRequestType + +type SetCustomerPermissionsResponse SetCustomerPermissionsResponseType + +type RemoveCustomerPermissionsRequest RemoveCustomerPermissionsRequestType + +type RemoveCustomerPermissionsResponse RemoveCustomerPermissionsResponseType + +type AddCustomerForbidsRequest AddCustomerForbidsRequestType + +type AddCustomerForbidsResponse AddCustomerForbidsResponseType + +type SetCustomerForbidsRequest SetCustomerForbidsRequestType + +type SetCustomerForbidsResponse SetCustomerForbidsResponseType + +type RemoveCustomerForbidsRequest RemoveCustomerForbidsRequestType + +type RemoveCustomerForbidsResponse RemoveCustomerForbidsResponseType + +type GetHostStatsFlagsRequest GetHostStatsFlagsRequestType + +type GetHostStatsFlagsResponse GetHostStatsFlagsResponseType + +type SetHostStatsFlagsRequest SetHostStatsFlagsRequestType + +type SetHostStatsFlagsResponse SetHostStatsFlagsResponseType + +type CreateTSIGKeyRequest CreateTSIGKeyRequestType + +type CreateTSIGKeyResponse CreateTSIGKeyResponseType + +type GetOneTSIGKeyRequest GetOneTSIGKeyRequestType + +type GetOneTSIGKeyResponse GetOneTSIGKeyResponseType + +type GetTSIGKeysRequest GetTSIGKeysRequestType + +type GetTSIGKeysResponse GetTSIGKeysResponseType + +type UpdateTSIGKeyRequest UpdateTSIGKeyRequestType + +type UpdateTSIGKeyResponse UpdateTSIGKeyResponseType + +type DeleteOneTSIGKeyRequest DeleteOneTSIGKeyRequestType + +type DeleteOneTSIGKeyResponse DeleteOneTSIGKeyResponseType + +type CreateZoneRequest CreateZoneRequestType + +type CreateZoneResponse CreateZoneResponseType + +type GetOneZoneRequest GetOneZoneRequestType + +type GetOneZoneResponse GetOneZoneResponseType + +type GetZonesRequest GetZonesRequestType + +type GetZonesResponse GetZonesResponseType + +type DeleteOneZoneRequest DeleteOneZoneRequestType + +type DeleteOneZoneResponse DeleteOneZoneResponseType + +type CreateSecondaryZoneRequest CreateSecondaryZoneRequestType + +type CreateSecondaryZoneResponse CreateSecondaryZoneResponseType + +type UpdateSecondaryRequest UpdateSecondaryRequestType + +type UpdateSecondaryResponse UpdateSecondaryResponseType + +type ActivateSecondaryRequest ActivateSecondaryRequestType + +type ActivateSecondaryResponse ActivateSecondaryResponseType + +type DeactivateSecondaryRequest DeactivateSecondaryRequestType + +type DeactivateSecondaryResponse DeactivateSecondaryResponseType + +type RetransferSecondaryRequest RetransferSecondaryRequestType + +type RetransferSecondaryResponse RetransferSecondaryResponseType + +type GetOneSecondaryRequest GetOneSecondaryRequestType + +type GetOneSecondaryResponse GetOneSecondaryResponseType + +type GetSecondariesRequest GetSecondariesRequestType + +type GetSecondariesResponse GetSecondariesResponseType + +type GetZoneApexRequest GetZoneApexRequestType + +type GetZoneApexResponse GetZoneApexResponseType + +type CreateARecordRequest CreateARecordRequestType + +type CreateARecordResponse CreateARecordResponseType + +type GetOneARecordRequest GetOneARecordRequestType + +type GetOneARecordResponse GetOneARecordResponseType + +type GetARecordsRequest GetARecordsRequestType + +type GetARecordsResponse GetARecordsResponseType + +type UpdateARecordRequest UpdateARecordRequestType + +type UpdateARecordResponse UpdateARecordResponseType + +type DeleteARecordsRequest DeleteARecordsRequestType + +type DeleteARecordsResponse DeleteARecordsResponseType + +type DeleteOneARecordRequest DeleteOneARecordRequestType + +type DeleteOneARecordResponse DeleteOneARecordResponseType + +type CreateAAAARecordRequest CreateAAAARecordRequestType + +type CreateAAAARecordResponse CreateAAAARecordResponseType + +type GetOneAAAARecordRequest GetOneAAAARecordRequestType + +type GetOneAAAARecordResponse GetOneAAAARecordResponseType + +type GetAAAARecordsRequest GetAAAARecordsRequestType + +type GetAAAARecordsResponse GetAAAARecordsResponseType + +type UpdateAAAARecordRequest UpdateAAAARecordRequestType + +type UpdateAAAARecordResponse UpdateAAAARecordResponseType + +type DeleteAAAARecordsRequest DeleteAAAARecordsRequestType + +type DeleteAAAARecordsResponse DeleteAAAARecordsResponseType + +type DeleteOneAAAARecordRequest DeleteOneAAAARecordRequestType + +type DeleteOneAAAARecordResponse DeleteOneAAAARecordResponseType + +type CreateALIASRecordRequest CreateALIASRecordRequestType + +type CreateALIASRecordResponse CreateALIASRecordResponseType + +type GetOneALIASRecordRequest GetOneALIASRecordRequestType + +type GetOneALIASRecordResponse GetOneALIASRecordResponseType + +type GetALIASRecordsRequest GetALIASRecordsRequestType + +type GetALIASRecordsResponse GetALIASRecordsResponseType + +type UpdateALIASRecordRequest UpdateALIASRecordRequestType + +type UpdateALIASRecordResponse UpdateALIASRecordResponseType + +type DeleteALIASRecordsRequest DeleteALIASRecordsRequestType + +type DeleteALIASRecordsResponse DeleteALIASRecordsResponseType + +type DeleteOneALIASRecordRequest DeleteOneALIASRecordRequestType + +type DeleteOneALIASRecordResponse DeleteOneALIASRecordResponseType + +type CreateCAARecordRequest CreateCAARecordRequestType + +type CreateCAARecordResponse CreateCAARecordResponseType + +type GetOneCAARecordRequest GetOneCAARecordRequestType + +type GetOneCAARecordResponse GetOneCAARecordResponseType + +type GetCAARecordsRequest GetCAARecordsRequestType + +type GetCAARecordsResponse GetCAARecordsResponseType + +type UpdateCAARecordRequest UpdateCAARecordRequestType + +type UpdateCAARecordResponse UpdateCAARecordResponseType + +type DeleteCAARecordsRequest DeleteCAARecordsRequestType + +type DeleteCAARecordsResponse DeleteCAARecordsResponseType + +type DeleteOneCAARecordRequest DeleteOneCAARecordRequestType + +type DeleteOneCAARecordResponse DeleteOneCAARecordResponseType + +type CreateCDNSKEYRecordRequest CreateCDNSKEYRecordRequestType + +type CreateCDNSKEYRecordResponse CreateCDNSKEYRecordResponseType + +type GetOneCDNSKEYRecordRequest GetOneCDNSKEYRecordRequestType + +type GetOneCDNSKEYRecordResponse GetOneCDNSKEYRecordResponseType + +type GetCDNSKEYRecordsRequest GetCDNSKEYRecordsRequestType + +type GetCDNSKEYRecordsResponse GetCDNSKEYRecordsResponseType + +type UpdateCDNSKEYRecordRequest UpdateCDNSKEYRecordRequestType + +type UpdateCDNSKEYRecordResponse UpdateCDNSKEYRecordResponseType + +type DeleteCDNSKEYRecordsRequest DeleteCDNSKEYRecordsRequestType + +type DeleteCDNSKEYRecordsResponse DeleteCDNSKEYRecordsResponseType + +type DeleteOneCDNSKEYRecordRequest DeleteOneCDNSKEYRecordRequestType + +type DeleteOneCDNSKEYRecordResponse DeleteOneCDNSKEYRecordResponseType + +type CreateCDSRecordRequest CreateCDSRecordRequestType + +type CreateCDSRecordResponse CreateCDSRecordResponseType + +type GetOneCDSRecordRequest GetOneCDSRecordRequestType + +type GetOneCDSRecordResponse GetOneCDSRecordResponseType + +type GetCDSRecordsRequest GetCDSRecordsRequestType + +type GetCDSRecordsResponse GetCDSRecordsResponseType + +type UpdateCDSRecordRequest UpdateCDSRecordRequestType + +type UpdateCDSRecordResponse UpdateCDSRecordResponseType + +type DeleteCDSRecordsRequest DeleteCDSRecordsRequestType + +type DeleteCDSRecordsResponse DeleteCDSRecordsResponseType + +type DeleteOneCDSRecordRequest DeleteOneCDSRecordRequestType + +type DeleteOneCDSRecordResponse DeleteOneCDSRecordResponseType + +type CreateCERTRecordRequest CreateCERTRecordRequestType + +type CreateCERTRecordResponse CreateCERTRecordResponseType + +type GetOneCERTRecordRequest GetOneCERTRecordRequestType + +type GetOneCERTRecordResponse GetOneCERTRecordResponseType + +type GetCERTRecordsRequest GetCERTRecordsRequestType + +type GetCERTRecordsResponse GetCERTRecordsResponseType + +type UpdateCERTRecordRequest UpdateCERTRecordRequestType + +type UpdateCERTRecordResponse UpdateCERTRecordResponseType + +type DeleteCERTRecordsRequest DeleteCERTRecordsRequestType + +type DeleteCERTRecordsResponse DeleteCERTRecordsResponseType + +type DeleteOneCERTRecordRequest DeleteOneCERTRecordRequestType + +type DeleteOneCERTRecordResponse DeleteOneCERTRecordResponseType + +type CreateCNAMERecordRequest CreateCNAMERecordRequestType + +type CreateCNAMERecordResponse CreateCNAMERecordResponseType + +type GetOneCNAMERecordRequest GetOneCNAMERecordRequestType + +type GetOneCNAMERecordResponse GetOneCNAMERecordResponseType + +type GetCNAMERecordsRequest GetCNAMERecordsRequestType + +type GetCNAMERecordsResponse GetCNAMERecordsResponseType + +type UpdateCNAMERecordRequest UpdateCNAMERecordRequestType + +type UpdateCNAMERecordResponse UpdateCNAMERecordResponseType + +type DeleteCNAMERecordsRequest DeleteCNAMERecordsRequestType + +type DeleteCNAMERecordsResponse DeleteCNAMERecordsResponseType + +type DeleteOneCNAMERecordRequest DeleteOneCNAMERecordRequestType + +type DeleteOneCNAMERecordResponse DeleteOneCNAMERecordResponseType + +type CreateCSYNCRecordRequest CreateCSYNCRecordRequestType + +type CreateCSYNCRecordResponse CreateCSYNCRecordResponseType + +type GetOneCSYNCRecordRequest GetOneCSYNCRecordRequestType + +type GetOneCSYNCRecordResponse GetOneCSYNCRecordResponseType + +type GetCSYNCRecordsRequest GetCSYNCRecordsRequestType + +type GetCSYNCRecordsResponse GetCSYNCRecordsResponseType + +type UpdateCSYNCRecordRequest UpdateCSYNCRecordRequestType + +type UpdateCSYNCRecordResponse UpdateCSYNCRecordResponseType + +type DeleteCSYNCRecordsRequest DeleteCSYNCRecordsRequestType + +type DeleteCSYNCRecordsResponse DeleteCSYNCRecordsResponseType + +type DeleteOneCSYNCRecordRequest DeleteOneCSYNCRecordRequestType + +type DeleteOneCSYNCRecordResponse DeleteOneCSYNCRecordResponseType + +type CreateDHCIDRecordRequest CreateDHCIDRecordRequestType + +type CreateDHCIDRecordResponse CreateDHCIDRecordResponseType + +type GetOneDHCIDRecordRequest GetOneDHCIDRecordRequestType + +type GetOneDHCIDRecordResponse GetOneDHCIDRecordResponseType + +type GetDHCIDRecordsRequest GetDHCIDRecordsRequestType + +type GetDHCIDRecordsResponse GetDHCIDRecordsResponseType + +type UpdateDHCIDRecordRequest UpdateDHCIDRecordRequestType + +type UpdateDHCIDRecordResponse UpdateDHCIDRecordResponseType + +type DeleteDHCIDRecordsRequest DeleteDHCIDRecordsRequestType + +type DeleteDHCIDRecordsResponse DeleteDHCIDRecordsResponseType + +type DeleteOneDHCIDRecordRequest DeleteOneDHCIDRecordRequestType + +type DeleteOneDHCIDRecordResponse DeleteOneDHCIDRecordResponseType + +type CreateDNAMERecordRequest CreateDNAMERecordRequestType + +type CreateDNAMERecordResponse CreateDNAMERecordResponseType + +type GetOneDNAMERecordRequest GetOneDNAMERecordRequestType + +type GetOneDNAMERecordResponse GetOneDNAMERecordResponseType + +type GetDNAMERecordsRequest GetDNAMERecordsRequestType + +type GetDNAMERecordsResponse GetDNAMERecordsResponseType + +type UpdateDNAMERecordRequest UpdateDNAMERecordRequestType + +type UpdateDNAMERecordResponse UpdateDNAMERecordResponseType + +type DeleteDNAMERecordsRequest DeleteDNAMERecordsRequestType + +type DeleteDNAMERecordsResponse DeleteDNAMERecordsResponseType + +type DeleteOneDNAMERecordRequest DeleteOneDNAMERecordRequestType + +type DeleteOneDNAMERecordResponse DeleteOneDNAMERecordResponseType + +type CreateDNSKEYRecordRequest CreateDNSKEYRecordRequestType + +type CreateDNSKEYRecordResponse CreateDNSKEYRecordResponseType + +type GetOneDNSKEYRecordRequest GetOneDNSKEYRecordRequestType + +type GetOneDNSKEYRecordResponse GetOneDNSKEYRecordResponseType + +type GetDNSKEYRecordsRequest GetDNSKEYRecordsRequestType + +type GetDNSKEYRecordsResponse GetDNSKEYRecordsResponseType + +type UpdateDNSKEYRecordRequest UpdateDNSKEYRecordRequestType + +type UpdateDNSKEYRecordResponse UpdateDNSKEYRecordResponseType + +type DeleteDNSKEYRecordsRequest DeleteDNSKEYRecordsRequestType + +type DeleteDNSKEYRecordsResponse DeleteDNSKEYRecordsResponseType + +type DeleteOneDNSKEYRecordRequest DeleteOneDNSKEYRecordRequestType + +type DeleteOneDNSKEYRecordResponse DeleteOneDNSKEYRecordResponseType + +type CreateDSRecordRequest CreateDSRecordRequestType + +type CreateDSRecordResponse CreateDSRecordResponseType + +type GetOneDSRecordRequest GetOneDSRecordRequestType + +type GetOneDSRecordResponse GetOneDSRecordResponseType + +type GetDSRecordsRequest GetDSRecordsRequestType + +type GetDSRecordsResponse GetDSRecordsResponseType + +type UpdateDSRecordRequest UpdateDSRecordRequestType + +type UpdateDSRecordResponse UpdateDSRecordResponseType + +type DeleteDSRecordsRequest DeleteDSRecordsRequestType + +type DeleteDSRecordsResponse DeleteDSRecordsResponseType + +type DeleteOneDSRecordRequest DeleteOneDSRecordRequestType + +type DeleteOneDSRecordResponse DeleteOneDSRecordResponseType + +type CreateIPSECKEYRecordRequest CreateIPSECKEYRecordRequestType + +type CreateIPSECKEYRecordResponse CreateIPSECKEYRecordResponseType + +type GetOneIPSECKEYRecordRequest GetOneIPSECKEYRecordRequestType + +type GetOneIPSECKEYRecordResponse GetOneIPSECKEYRecordResponseType + +type GetIPSECKEYRecordsRequest GetIPSECKEYRecordsRequestType + +type GetIPSECKEYRecordsResponse GetIPSECKEYRecordsResponseType + +type UpdateIPSECKEYRecordRequest UpdateIPSECKEYRecordRequestType + +type UpdateIPSECKEYRecordResponse UpdateIPSECKEYRecordResponseType + +type DeleteIPSECKEYRecordsRequest DeleteIPSECKEYRecordsRequestType + +type DeleteIPSECKEYRecordsResponse DeleteIPSECKEYRecordsResponseType + +type DeleteOneIPSECKEYRecordRequest DeleteOneIPSECKEYRecordRequestType + +type DeleteOneIPSECKEYRecordResponse DeleteOneIPSECKEYRecordResponseType + +type CreateKEYRecordRequest CreateKEYRecordRequestType + +type CreateKEYRecordResponse CreateKEYRecordResponseType + +type GetOneKEYRecordRequest GetOneKEYRecordRequestType + +type GetOneKEYRecordResponse GetOneKEYRecordResponseType + +type GetKEYRecordsRequest GetKEYRecordsRequestType + +type GetKEYRecordsResponse GetKEYRecordsResponseType + +type UpdateKEYRecordRequest UpdateKEYRecordRequestType + +type UpdateKEYRecordResponse UpdateKEYRecordResponseType + +type DeleteKEYRecordsRequest DeleteKEYRecordsRequestType + +type DeleteKEYRecordsResponse DeleteKEYRecordsResponseType + +type DeleteOneKEYRecordRequest DeleteOneKEYRecordRequestType + +type DeleteOneKEYRecordResponse DeleteOneKEYRecordResponseType + +type CreateKXRecordRequest CreateKXRecordRequestType + +type CreateKXRecordResponse CreateKXRecordResponseType + +type GetOneKXRecordRequest GetOneKXRecordRequestType + +type GetOneKXRecordResponse GetOneKXRecordResponseType + +type GetKXRecordsRequest GetKXRecordsRequestType + +type GetKXRecordsResponse GetKXRecordsResponseType + +type UpdateKXRecordRequest UpdateKXRecordRequestType + +type UpdateKXRecordResponse UpdateKXRecordResponseType + +type DeleteKXRecordsRequest DeleteKXRecordsRequestType + +type DeleteKXRecordsResponse DeleteKXRecordsResponseType + +type DeleteOneKXRecordRequest DeleteOneKXRecordRequestType + +type DeleteOneKXRecordResponse DeleteOneKXRecordResponseType + +type CreateLOCRecordRequest CreateLOCRecordRequestType + +type CreateLOCRecordResponse CreateLOCRecordResponseType + +type GetOneLOCRecordRequest GetOneLOCRecordRequestType + +type GetOneLOCRecordResponse GetOneLOCRecordResponseType + +type GetLOCRecordsRequest GetLOCRecordsRequestType + +type GetLOCRecordsResponse GetLOCRecordsResponseType + +type UpdateLOCRecordRequest UpdateLOCRecordRequestType + +type UpdateLOCRecordResponse UpdateLOCRecordResponseType + +type DeleteLOCRecordsRequest DeleteLOCRecordsRequestType + +type DeleteLOCRecordsResponse DeleteLOCRecordsResponseType + +type DeleteOneLOCRecordRequest DeleteOneLOCRecordRequestType + +type DeleteOneLOCRecordResponse DeleteOneLOCRecordResponseType + +type CreateMXRecordRequest CreateMXRecordRequestType + +type CreateMXRecordResponse CreateMXRecordResponseType + +type GetOneMXRecordRequest GetOneMXRecordRequestType + +type GetOneMXRecordResponse GetOneMXRecordResponseType + +type GetMXRecordsRequest GetMXRecordsRequestType + +type GetMXRecordsResponse GetMXRecordsResponseType + +type UpdateMXRecordRequest UpdateMXRecordRequestType + +type UpdateMXRecordResponse UpdateMXRecordResponseType + +type DeleteMXRecordsRequest DeleteMXRecordsRequestType + +type DeleteMXRecordsResponse DeleteMXRecordsResponseType + +type DeleteOneMXRecordRequest DeleteOneMXRecordRequestType + +type DeleteOneMXRecordResponse DeleteOneMXRecordResponseType + +type CreateNAPTRRecordRequest CreateNAPTRRecordRequestType + +type CreateNAPTRRecordResponse CreateNAPTRRecordResponseType + +type GetOneNAPTRRecordRequest GetOneNAPTRRecordRequestType + +type GetOneNAPTRRecordResponse GetOneNAPTRRecordResponseType + +type GetNAPTRRecordsRequest GetNAPTRRecordsRequestType + +type GetNAPTRRecordsResponse GetNAPTRRecordsResponseType + +type UpdateNAPTRRecordRequest UpdateNAPTRRecordRequestType + +type UpdateNAPTRRecordResponse UpdateNAPTRRecordResponseType + +type DeleteNAPTRRecordsRequest DeleteNAPTRRecordsRequestType + +type DeleteNAPTRRecordsResponse DeleteNAPTRRecordsResponseType + +type DeleteOneNAPTRRecordRequest DeleteOneNAPTRRecordRequestType + +type DeleteOneNAPTRRecordResponse DeleteOneNAPTRRecordResponseType + +type CreateNSAPRecordRequest CreateNSAPRecordRequestType + +type CreateNSAPRecordResponse CreateNSAPRecordResponseType + +type GetOneNSAPRecordRequest GetOneNSAPRecordRequestType + +type GetOneNSAPRecordResponse GetOneNSAPRecordResponseType + +type GetNSAPRecordsRequest GetNSAPRecordsRequestType + +type GetNSAPRecordsResponse GetNSAPRecordsResponseType + +type UpdateNSAPRecordRequest UpdateNSAPRecordRequestType + +type UpdateNSAPRecordResponse UpdateNSAPRecordResponseType + +type DeleteNSAPRecordsRequest DeleteNSAPRecordsRequestType + +type DeleteNSAPRecordsResponse DeleteNSAPRecordsResponseType + +type DeleteOneNSAPRecordRequest DeleteOneNSAPRecordRequestType + +type DeleteOneNSAPRecordResponse DeleteOneNSAPRecordResponseType + +type CreatePOLICYRecordRequest CreatePOLICYRecordRequestType + +type CreatePOLICYRecordResponse CreatePOLICYRecordResponseType + +type GetOnePOLICYRecordRequest GetOnePOLICYRecordRequestType + +type GetOnePOLICYRecordResponse GetOnePOLICYRecordResponseType + +type GetPOLICYRecordsRequest GetPOLICYRecordsRequestType + +type GetPOLICYRecordsResponse GetPOLICYRecordsResponseType + +type UpdatePOLICYRecordRequest UpdatePOLICYRecordRequestType + +type UpdatePOLICYRecordResponse UpdatePOLICYRecordResponseType + +type DeletePOLICYRecordsRequest DeletePOLICYRecordsRequestType + +type DeletePOLICYRecordsResponse DeletePOLICYRecordsResponseType + +type DeleteOnePOLICYRecordRequest DeleteOnePOLICYRecordRequestType + +type DeleteOnePOLICYRecordResponse DeleteOnePOLICYRecordResponseType + +type CreatePTRRecordRequest CreatePTRRecordRequestType + +type CreatePTRRecordResponse CreatePTRRecordResponseType + +type GetOnePTRRecordRequest GetOnePTRRecordRequestType + +type GetOnePTRRecordResponse GetOnePTRRecordResponseType + +type GetPTRRecordsRequest GetPTRRecordsRequestType + +type GetPTRRecordsResponse GetPTRRecordsResponseType + +type UpdatePTRRecordRequest UpdatePTRRecordRequestType + +type UpdatePTRRecordResponse UpdatePTRRecordResponseType + +type DeletePTRRecordsRequest DeletePTRRecordsRequestType + +type DeletePTRRecordsResponse DeletePTRRecordsResponseType + +type DeleteOnePTRRecordRequest DeleteOnePTRRecordRequestType + +type DeleteOnePTRRecordResponse DeleteOnePTRRecordResponseType + +type CreatePXRecordRequest CreatePXRecordRequestType + +type CreatePXRecordResponse CreatePXRecordResponseType + +type GetOnePXRecordRequest GetOnePXRecordRequestType + +type GetOnePXRecordResponse GetOnePXRecordResponseType + +type GetPXRecordsRequest GetPXRecordsRequestType + +type GetPXRecordsResponse GetPXRecordsResponseType + +type UpdatePXRecordRequest UpdatePXRecordRequestType + +type UpdatePXRecordResponse UpdatePXRecordResponseType + +type DeletePXRecordsRequest DeletePXRecordsRequestType + +type DeletePXRecordsResponse DeletePXRecordsResponseType + +type DeleteOnePXRecordRequest DeleteOnePXRecordRequestType + +type DeleteOnePXRecordResponse DeleteOnePXRecordResponseType + +type CreateRPRecordRequest CreateRPRecordRequestType + +type CreateRPRecordResponse CreateRPRecordResponseType + +type GetOneRPRecordRequest GetOneRPRecordRequestType + +type GetOneRPRecordResponse GetOneRPRecordResponseType + +type GetRPRecordsRequest GetRPRecordsRequestType + +type GetRPRecordsResponse GetRPRecordsResponseType + +type UpdateRPRecordRequest UpdateRPRecordRequestType + +type UpdateRPRecordResponse UpdateRPRecordResponseType + +type DeleteRPRecordsRequest DeleteRPRecordsRequestType + +type DeleteRPRecordsResponse DeleteRPRecordsResponseType + +type DeleteOneRPRecordRequest DeleteOneRPRecordRequestType + +type DeleteOneRPRecordResponse DeleteOneRPRecordResponseType + +type CreateSPFRecordRequest CreateSPFRecordRequestType + +type CreateSPFRecordResponse CreateSPFRecordResponseType + +type GetOneSPFRecordRequest GetOneSPFRecordRequestType + +type GetOneSPFRecordResponse GetOneSPFRecordResponseType + +type GetSPFRecordsRequest GetSPFRecordsRequestType + +type GetSPFRecordsResponse GetSPFRecordsResponseType + +type UpdateSPFRecordRequest UpdateSPFRecordRequestType + +type UpdateSPFRecordResponse UpdateSPFRecordResponseType + +type DeleteSPFRecordsRequest DeleteSPFRecordsRequestType + +type DeleteSPFRecordsResponse DeleteSPFRecordsResponseType + +type DeleteOneSPFRecordRequest DeleteOneSPFRecordRequestType + +type DeleteOneSPFRecordResponse DeleteOneSPFRecordResponseType + +type CreateSRVRecordRequest CreateSRVRecordRequestType + +type CreateSRVRecordResponse CreateSRVRecordResponseType + +type GetOneSRVRecordRequest GetOneSRVRecordRequestType + +type GetOneSRVRecordResponse GetOneSRVRecordResponseType + +type GetSRVRecordsRequest GetSRVRecordsRequestType + +type GetSRVRecordsResponse GetSRVRecordsResponseType + +type UpdateSRVRecordRequest UpdateSRVRecordRequestType + +type UpdateSRVRecordResponse UpdateSRVRecordResponseType + +type DeleteSRVRecordsRequest DeleteSRVRecordsRequestType + +type DeleteSRVRecordsResponse DeleteSRVRecordsResponseType + +type DeleteOneSRVRecordRequest DeleteOneSRVRecordRequestType + +type DeleteOneSRVRecordResponse DeleteOneSRVRecordResponseType + +type CreateSSHFPRecordRequest CreateSSHFPRecordRequestType + +type CreateSSHFPRecordResponse CreateSSHFPRecordResponseType + +type GetOneSSHFPRecordRequest GetOneSSHFPRecordRequestType + +type GetOneSSHFPRecordResponse GetOneSSHFPRecordResponseType + +type GetSSHFPRecordsRequest GetSSHFPRecordsRequestType + +type GetSSHFPRecordsResponse GetSSHFPRecordsResponseType + +type UpdateSSHFPRecordRequest UpdateSSHFPRecordRequestType + +type UpdateSSHFPRecordResponse UpdateSSHFPRecordResponseType + +type DeleteSSHFPRecordsRequest DeleteSSHFPRecordsRequestType + +type DeleteSSHFPRecordsResponse DeleteSSHFPRecordsResponseType + +type DeleteOneSSHFPRecordRequest DeleteOneSSHFPRecordRequestType + +type DeleteOneSSHFPRecordResponse DeleteOneSSHFPRecordResponseType + +type CreateTLSARecordRequest CreateTLSARecordRequestType + +type CreateTLSARecordResponse CreateTLSARecordResponseType + +type GetOneTLSARecordRequest GetOneTLSARecordRequestType + +type GetOneTLSARecordResponse GetOneTLSARecordResponseType + +type GetTLSARecordsRequest GetTLSARecordsRequestType + +type GetTLSARecordsResponse GetTLSARecordsResponseType + +type UpdateTLSARecordRequest UpdateTLSARecordRequestType + +type UpdateTLSARecordResponse UpdateTLSARecordResponseType + +type DeleteTLSARecordsRequest DeleteTLSARecordsRequestType + +type DeleteTLSARecordsResponse DeleteTLSARecordsResponseType + +type DeleteOneTLSARecordRequest DeleteOneTLSARecordRequestType + +type DeleteOneTLSARecordResponse DeleteOneTLSARecordResponseType + +type CreateTXTRecordRequest CreateTXTRecordRequestType + +type CreateTXTRecordResponse CreateTXTRecordResponseType + +type GetOneTXTRecordRequest GetOneTXTRecordRequestType + +type GetOneTXTRecordResponse GetOneTXTRecordResponseType + +type GetTXTRecordsRequest GetTXTRecordsRequestType + +type GetTXTRecordsResponse GetTXTRecordsResponseType + +type UpdateTXTRecordRequest UpdateTXTRecordRequestType + +type UpdateTXTRecordResponse UpdateTXTRecordResponseType + +type DeleteTXTRecordsRequest DeleteTXTRecordsRequestType + +type DeleteTXTRecordsResponse DeleteTXTRecordsResponseType + +type DeleteOneTXTRecordRequest DeleteOneTXTRecordRequestType + +type DeleteOneTXTRecordResponse DeleteOneTXTRecordResponseType + +type GetOneSOARecordRequest GetOneSOARecordRequestType + +type GetOneSOARecordResponse GetOneSOARecordResponseType + +type GetSOARecordsRequest GetSOARecordsRequestType + +type GetSOARecordsResponse GetSOARecordsResponseType + +type UpdateSOARecordRequest UpdateSOARecordRequestType + +type UpdateSOARecordResponse UpdateSOARecordResponseType + +type CreateNSRecordRequest CreateNSRecordRequestType + +type CreateNSRecordResponse CreateNSRecordResponseType + +type GetOneNSRecordRequest GetOneNSRecordRequestType + +type GetOneNSRecordResponse GetOneNSRecordResponseType + +type GetNSRecordsRequest GetNSRecordsRequestType + +type GetNSRecordsResponse GetNSRecordsResponseType + +type UpdateNSRecordRequest UpdateNSRecordRequestType + +type UpdateNSRecordResponse UpdateNSRecordResponseType + +type DeleteNSRecordsRequest DeleteNSRecordsRequestType + +type DeleteNSRecordsResponse DeleteNSRecordsResponseType + +type DeleteOneNSRecordRequest DeleteOneNSRecordRequestType + +type DeleteOneNSRecordResponse DeleteOneNSRecordResponseType + +type ReplaceARecordsRequest ReplaceARecordsRequestType + +type ReplaceARecordsResponse ReplaceARecordsResponseType + +type ReplaceAAAARecordsRequest ReplaceAAAARecordsRequestType + +type ReplaceAAAARecordsResponse ReplaceAAAARecordsResponseType + +type ReplaceALIASRecordsRequest ReplaceALIASRecordsRequestType + +type ReplaceALIASRecordsResponse ReplaceALIASRecordsResponseType + +type ReplaceCAARecordsRequest ReplaceCAARecordsRequestType + +type ReplaceCAARecordsResponse ReplaceCAARecordsResponseType + +type ReplaceCDNSKEYRecordsRequest ReplaceCDNSKEYRecordsRequestType + +type ReplaceCDNSKEYRecordsResponse ReplaceCDNSKEYRecordsResponseType + +type ReplaceCDSRecordsRequest ReplaceCDSRecordsRequestType + +type ReplaceCDSRecordsResponse ReplaceCDSRecordsResponseType + +type ReplaceCERTRecordsRequest ReplaceCERTRecordsRequestType + +type ReplaceCERTRecordsResponse ReplaceCERTRecordsResponseType + +type ReplaceCNAMERecordsRequest ReplaceCNAMERecordsRequestType + +type ReplaceCNAMERecordsResponse ReplaceCNAMERecordsResponseType + +type ReplaceCSYNCRecordsRequest ReplaceCSYNCRecordsRequestType + +type ReplaceCSYNCRecordsResponse ReplaceCSYNCRecordsResponseType + +type ReplaceDHCIDRecordsRequest ReplaceDHCIDRecordsRequestType + +type ReplaceDHCIDRecordsResponse ReplaceDHCIDRecordsResponseType + +type ReplaceDNAMERecordsRequest ReplaceDNAMERecordsRequestType + +type ReplaceDNAMERecordsResponse ReplaceDNAMERecordsResponseType + +type ReplaceDNSKEYRecordsRequest ReplaceDNSKEYRecordsRequestType + +type ReplaceDNSKEYRecordsResponse ReplaceDNSKEYRecordsResponseType + +type ReplaceDSRecordsRequest ReplaceDSRecordsRequestType + +type ReplaceDSRecordsResponse ReplaceDSRecordsResponseType + +type ReplaceIPSECKEYRecordsRequest ReplaceIPSECKEYRecordsRequestType + +type ReplaceIPSECKEYRecordsResponse ReplaceIPSECKEYRecordsResponseType + +type ReplaceKEYRecordsRequest ReplaceKEYRecordsRequestType + +type ReplaceKEYRecordsResponse ReplaceKEYRecordsResponseType + +type ReplaceKXRecordsRequest ReplaceKXRecordsRequestType + +type ReplaceKXRecordsResponse ReplaceKXRecordsResponseType + +type ReplaceLOCRecordsRequest ReplaceLOCRecordsRequestType + +type ReplaceLOCRecordsResponse ReplaceLOCRecordsResponseType + +type ReplaceMXRecordsRequest ReplaceMXRecordsRequestType + +type ReplaceMXRecordsResponse ReplaceMXRecordsResponseType + +type ReplaceNAPTRRecordsRequest ReplaceNAPTRRecordsRequestType + +type ReplaceNAPTRRecordsResponse ReplaceNAPTRRecordsResponseType + +type ReplaceNSAPRecordsRequest ReplaceNSAPRecordsRequestType + +type ReplaceNSAPRecordsResponse ReplaceNSAPRecordsResponseType + +type ReplacePOLICYRecordsRequest ReplacePOLICYRecordsRequestType + +type ReplacePOLICYRecordsResponse ReplacePOLICYRecordsResponseType + +type ReplacePTRRecordsRequest ReplacePTRRecordsRequestType + +type ReplacePTRRecordsResponse ReplacePTRRecordsResponseType + +type ReplacePXRecordsRequest ReplacePXRecordsRequestType + +type ReplacePXRecordsResponse ReplacePXRecordsResponseType + +type ReplaceRPRecordsRequest ReplaceRPRecordsRequestType + +type ReplaceRPRecordsResponse ReplaceRPRecordsResponseType + +type ReplaceSPFRecordsRequest ReplaceSPFRecordsRequestType + +type ReplaceSPFRecordsResponse ReplaceSPFRecordsResponseType + +type ReplaceSRVRecordsRequest ReplaceSRVRecordsRequestType + +type ReplaceSRVRecordsResponse ReplaceSRVRecordsResponseType + +type ReplaceSSHFPRecordsRequest ReplaceSSHFPRecordsRequestType + +type ReplaceSSHFPRecordsResponse ReplaceSSHFPRecordsResponseType + +type ReplaceTLSARecordsRequest ReplaceTLSARecordsRequestType + +type ReplaceTLSARecordsResponse ReplaceTLSARecordsResponseType + +type ReplaceTXTRecordsRequest ReplaceTXTRecordsRequestType + +type ReplaceTXTRecordsResponse ReplaceTXTRecordsResponseType + +type ReplaceNSRecordsRequest ReplaceNSRecordsRequestType + +type ReplaceNSRecordsResponse ReplaceNSRecordsResponseType + +type GetANYRecordsRequest GetANYRecordsRequestType + +type GetANYRecordsResponse GetANYRecordsResponseType + +type GetAllRecordsRequest GetAllRecordsRequestType + +type GetAllRecordsResponse GetAllRecordsResponseType + +type GetAllAliasQNamesRequest GetAllAliasQNamesRequestType + +type GetAllAliasQNamesResponse GetAllAliasQNamesResponseType + +type GetOneUserRequest GetOneUserRequestType + +type GetOneUserResponse GetOneUserResponseType + +type DeleteOneUserRequest DeleteOneUserRequestType + +type DeleteOneUserResponse DeleteOneUserResponseType + +type CreateUserRequest CreateUserRequestType + +type CreateUserResponse CreateUserResponseType + +type UpdateUserRequest UpdateUserRequestType + +type UpdateUserResponse UpdateUserResponseType + +type GetUsersRequest GetUsersRequestType + +type GetUsersResponse GetUsersResponseType + +type GetUpdateUsersRequest GetUpdateUsersRequestType + +type GetUpdateUsersResponse GetUpdateUsersResponseType + +type UpdateUpdateUserRequest UpdateUpdateUserRequestType + +type UpdateUpdateUserResponse UpdateUpdateUserResponseType + +type DeleteOneUpdateUserRequest DeleteOneUpdateUserRequestType + +type DeleteOneUpdateUserResponse DeleteOneUpdateUserResponseType + +type UpdateUserPasswordRequest UpdateUserPasswordRequestType + +type UpdateUserPasswordResponse UpdateUserPasswordResponseType + +type BlockUserRequest BlockUserRequestType + +type BlockUserResponse BlockUserResponseType + +type UnblockUserRequest UnblockUserRequestType + +type UnblockUserResponse UnblockUserResponseType + +type CreateContactRequest CreateContactRequestType + +type CreateContactResponse CreateContactResponseType + +type GetOneContactRequest GetOneContactRequestType + +type GetOneContactResponse GetOneContactResponseType + +type GetContactsRequest GetContactsRequestType + +type GetContactsResponse GetContactsResponseType + +type DeleteOneContactRequest DeleteOneContactRequestType + +type DeleteOneContactResponse DeleteOneContactResponseType + +type UpdateContactRequest UpdateContactRequestType + +type UpdateContactResponse UpdateContactResponseType + +type CreateCustomerRequest CreateCustomerRequestType + +type CreateCustomerResponse CreateCustomerResponseType + +type UpdateCustomerRequest UpdateCustomerRequestType + +type UpdateCustomerResponse UpdateCustomerResponseType + +type GetOneCustomerRequest GetOneCustomerRequestType + +type GetOneCustomerResponse GetOneCustomerResponseType + +type GetCustomersRequest GetCustomersRequestType + +type GetCustomersResponse GetCustomersResponseType + +type DeleteOneCustomerRequest DeleteOneCustomerRequestType + +type DeleteOneCustomerResponse DeleteOneCustomerResponseType + +type GetCustomerPrefsRequest GetCustomerPrefsRequestType + +type GetCustomerPrefsResponse GetCustomerPrefsResponseType + +type SetCustomerPrefsRequest SetCustomerPrefsRequestType + +type SetCustomerPrefsResponse SetCustomerPrefsResponseType + +type GetCustomerIPACLRequest GetCustomerIPACLRequestType + +type GetCustomerIPACLResponse GetCustomerIPACLResponseType + +type SetCustomerIPACLRequest SetCustomerIPACLRequestType + +type SetCustomerIPACLResponse SetCustomerIPACLResponseType + +type CreateCustomerOracleMetadataRequest CreateCustomerOracleMetadataRequestType + +type CreateCustomerOracleMetadataResponse CreateCustomerOracleMetadataResponseType + +type UpdateCustomerOracleMetadataRequest UpdateCustomerOracleMetadataRequestType + +type UpdateCustomerOracleMetadataResponse UpdateCustomerOracleMetadataResponseType + +type GetCustomerOracleMetadataRequest GetCustomerOracleMetadataRequestType + +type GetCustomerOracleMetadataResponse GetCustomerOracleMetadataResponseType + +type DeleteCustomerOracleMetadataRequest DeleteCustomerOracleMetadataRequestType + +type DeleteCustomerOracleMetadataResponse DeleteCustomerOracleMetadataResponseType + +type CreateZoneOracleMetadataRequest CreateZoneOracleMetadataRequestType + +type CreateZoneOracleMetadataResponse CreateZoneOracleMetadataResponseType + +type UpdateZoneOracleMetadataRequest UpdateZoneOracleMetadataRequestType + +type UpdateZoneOracleMetadataResponse UpdateZoneOracleMetadataResponseType + +type GetZoneOracleMetadataRequest GetZoneOracleMetadataRequestType + +type GetZoneOracleMetadataResponse GetZoneOracleMetadataResponseType + +type DeleteZoneOracleMetadataRequest DeleteZoneOracleMetadataRequestType + +type DeleteZoneOracleMetadataResponse DeleteZoneOracleMetadataResponseType + +type OCIMigrateRequest OCIMigrateRequestType + +type OCIMigrateResponse OCIMigrateResponseType + +type CreateDDNSRequest CreateDDNSRequestType + +type CreateDDNSResponse CreateDDNSResponseType + +type GetOneDDNSRequest GetOneDDNSRequestType + +type GetOneDDNSResponse GetOneDDNSResponseType + +type GetDDNSsRequest GetDDNSsRequestType + +type GetDDNSsResponse GetDDNSsResponseType + +type UpdateDDNSRequest UpdateDDNSRequestType + +type UpdateDDNSResponse UpdateDDNSResponseType + +type DeleteOneDDNSRequest DeleteOneDDNSRequestType + +type DeleteOneDDNSResponse DeleteOneDDNSResponseType + +type ActivateDDNSRequest ActivateDDNSRequestType + +type ActivateDDNSResponse ActivateDDNSResponseType + +type DeactivateDDNSRequest DeactivateDDNSRequestType + +type DeactivateDDNSResponse DeactivateDDNSResponseType + +type ResetDDNSRequest ResetDDNSRequestType + +type ResetDDNSResponse ResetDDNSResponseType + +type GetUpdateUserPasswordRequest GetUpdateUserPasswordRequestType + +type GetUpdateUserPasswordResponse GetUpdateUserPasswordResponseType + +type CreateDDNSHostRequest CreateDDNSHostRequestType + +type CreateDDNSHostResponse CreateDDNSHostResponseType + +type CreateUpdateUserRequest CreateUpdateUserRequestType + +type CreateUpdateUserResponse CreateUpdateUserResponseType + +type AddDDNSRequest AddDDNSRequestType + +type AddDDNSResponse AddDDNSResponseType + +type CreateFailoverRequest CreateFailoverRequestType + +type CreateFailoverResponse CreateFailoverResponseType + +type GetOneFailoverRequest GetOneFailoverRequestType + +type GetOneFailoverResponse GetOneFailoverResponseType + +type GetFailoversRequest GetFailoversRequestType + +type GetFailoversResponse GetFailoversResponseType + +type UpdateFailoverRequest UpdateFailoverRequestType + +type UpdateFailoverResponse UpdateFailoverResponseType + +type DeleteOneFailoverRequest DeleteOneFailoverRequestType + +type DeleteOneFailoverResponse DeleteOneFailoverResponseType + +type ActivateFailoverRequest ActivateFailoverRequestType + +type ActivateFailoverResponse ActivateFailoverResponseType + +type DeactivateFailoverRequest DeactivateFailoverRequestType + +type DeactivateFailoverResponse DeactivateFailoverResponseType + +type RecoverFailoverRequest RecoverFailoverRequestType + +type RecoverFailoverResponse RecoverFailoverResponseType + +type CreateLoadBalanceRequest CreateLoadBalanceRequestType + +type CreateLoadBalanceResponse CreateLoadBalanceResponseType + +type GetOneLoadBalanceRequest GetOneLoadBalanceRequestType + +type GetOneLoadBalanceResponse GetOneLoadBalanceResponseType + +type GetLoadBalancesRequest GetLoadBalancesRequestType + +type GetLoadBalancesResponse GetLoadBalancesResponseType + +type UpdateLoadBalanceRequest UpdateLoadBalanceRequestType + +type UpdateLoadBalanceResponse UpdateLoadBalanceResponseType + +type DeleteOneLoadBalanceRequest DeleteOneLoadBalanceRequestType + +type DeleteOneLoadBalanceResponse DeleteOneLoadBalanceResponseType + +type ActivateLoadBalanceRequest ActivateLoadBalanceRequestType + +type ActivateLoadBalanceResponse ActivateLoadBalanceResponseType + +type DeactivateLoadBalanceRequest DeactivateLoadBalanceRequestType + +type DeactivateLoadBalanceResponse DeactivateLoadBalanceResponseType + +type RecoverLoadBalanceRequest RecoverLoadBalanceRequestType + +type RecoverLoadBalanceResponse RecoverLoadBalanceResponseType + +type RecoverLoadBalanceIPRequest RecoverLoadBalanceIPRequestType + +type RecoverLoadBalanceIPResponse RecoverLoadBalanceIPResponseType + +type CreateLoadBalancePoolEntryRequest CreateLoadBalancePoolEntryRequestType + +type CreateLoadBalancePoolEntryResponse CreateLoadBalancePoolEntryResponseType + +type UpdateLoadBalancePoolEntryRequest UpdateLoadBalancePoolEntryRequestType + +type UpdateLoadBalancePoolEntryResponse UpdateLoadBalancePoolEntryResponseType + +type GetOneLoadBalancePoolEntryRequest GetOneLoadBalancePoolEntryRequestType + +type GetOneLoadBalancePoolEntryResponse GetOneLoadBalancePoolEntryResponseType + +type GetLoadBalancePoolEntriesRequest GetLoadBalancePoolEntriesRequestType + +type GetLoadBalancePoolEntriesResponse GetLoadBalancePoolEntriesResponseType + +type DeleteOneLoadBalancePoolEntryRequest DeleteOneLoadBalancePoolEntryRequestType + +type DeleteOneLoadBalancePoolEntryResponse DeleteOneLoadBalancePoolEntryResponseType + +type CreateGSLBRequest CreateGSLBRequestType + +type CreateGSLBResponse CreateGSLBResponseType + +type GetOneGSLBRequest GetOneGSLBRequestType + +type GetOneGSLBResponse GetOneGSLBResponseType + +type GetGSLBsRequest GetGSLBsRequestType + +type GetGSLBsResponse GetGSLBsResponseType + +type UpdateGSLBRequest UpdateGSLBRequestType + +type UpdateGSLBResponse UpdateGSLBResponseType + +type DeleteOneGSLBRequest DeleteOneGSLBRequestType + +type DeleteOneGSLBResponse DeleteOneGSLBResponseType + +type ActivateGSLBRequest ActivateGSLBRequestType + +type ActivateGSLBResponse ActivateGSLBResponseType + +type DeactivateGSLBRequest DeactivateGSLBRequestType + +type DeactivateGSLBResponse DeactivateGSLBResponseType + +type RecoverGSLBRequest RecoverGSLBRequestType + +type RecoverGSLBResponse RecoverGSLBResponseType + +type RecoverGSLBIPRequest RecoverGSLBIPRequestType + +type RecoverGSLBIPResponse RecoverGSLBIPResponseType + +type CreateGSLBRegionRequest CreateGSLBRegionRequestType + +type CreateGSLBRegionResponse CreateGSLBRegionResponseType + +type GetOneGSLBRegionRequest GetOneGSLBRegionRequestType + +type GetOneGSLBRegionResponse GetOneGSLBRegionResponseType + +type GetGSLBRegionsRequest GetGSLBRegionsRequestType + +type GetGSLBRegionsResponse GetGSLBRegionsResponseType + +type UpdateGSLBRegionRequest UpdateGSLBRegionRequestType + +type UpdateGSLBRegionResponse UpdateGSLBRegionResponseType + +type DeleteOneGSLBRegionRequest DeleteOneGSLBRegionRequestType + +type DeleteOneGSLBRegionResponse DeleteOneGSLBRegionResponseType + +type CreateGSLBRegionPoolEntryRequest CreateGSLBRegionPoolEntryRequestType + +type CreateGSLBRegionPoolEntryResponse CreateGSLBRegionPoolEntryResponseType + +type UpdateGSLBRegionPoolEntryRequest UpdateGSLBRegionPoolEntryRequestType + +type UpdateGSLBRegionPoolEntryResponse UpdateGSLBRegionPoolEntryResponseType + +type GetOneGSLBRegionPoolEntryRequest GetOneGSLBRegionPoolEntryRequestType + +type GetOneGSLBRegionPoolEntryResponse GetOneGSLBRegionPoolEntryResponseType + +type GetGSLBRegionPoolEntriesRequest GetGSLBRegionPoolEntriesRequestType + +type GetGSLBRegionPoolEntriesResponse GetGSLBRegionPoolEntriesResponseType + +type DeleteOneGSLBRegionPoolEntryRequest DeleteOneGSLBRegionPoolEntryRequestType + +type DeleteOneGSLBRegionPoolEntryResponse DeleteOneGSLBRegionPoolEntryResponseType + +type CreateRTTMRequest CreateRTTMRequestType + +type CreateRTTMResponse CreateRTTMResponseType + +type GetOneRTTMRequest GetOneRTTMRequestType + +type GetOneRTTMResponse GetOneRTTMResponseType + +type GetRTTMsRequest GetRTTMsRequestType + +type GetRTTMsResponse GetRTTMsResponseType + +type UpdateRTTMRequest UpdateRTTMRequestType + +type UpdateRTTMResponse UpdateRTTMResponseType + +type DeleteOneRTTMRequest DeleteOneRTTMRequestType + +type DeleteOneRTTMResponse DeleteOneRTTMResponseType + +type ActivateRTTMRequest ActivateRTTMRequestType + +type ActivateRTTMResponse ActivateRTTMResponseType + +type DeactivateRTTMRequest DeactivateRTTMRequestType + +type DeactivateRTTMResponse DeactivateRTTMResponseType + +type RecoverRTTMRequest RecoverRTTMRequestType + +type RecoverRTTMResponse RecoverRTTMResponseType + +type RecoverRTTMIPRequest RecoverRTTMIPRequestType + +type RecoverRTTMIPResponse RecoverRTTMIPResponseType + +type GetRTTMLogsRequest GetRTTMLogsRequestType + +type GetRTTMLogsResponse GetRTTMLogsResponseType + +type GetRTTMRRSetsRequest GetRTTMRRSetsRequestType + +type GetRTTMRRSetsResponse GetRTTMRRSetsResponseType + +type CreateRTTMRegionRequest CreateRTTMRegionRequestType + +type CreateRTTMRegionResponse CreateRTTMRegionResponseType + +type GetOneRTTMRegionRequest GetOneRTTMRegionRequestType + +type GetOneRTTMRegionResponse GetOneRTTMRegionResponseType + +type GetRTTMRegionsRequest GetRTTMRegionsRequestType + +type GetRTTMRegionsResponse GetRTTMRegionsResponseType + +type UpdateRTTMRegionRequest UpdateRTTMRegionRequestType + +type UpdateRTTMRegionResponse UpdateRTTMRegionResponseType + +type DeleteOneRTTMRegionRequest DeleteOneRTTMRegionRequestType + +type DeleteOneRTTMRegionResponse DeleteOneRTTMRegionResponseType + +type CreateRTTMRegionPoolEntryRequest CreateRTTMRegionPoolEntryRequestType + +type CreateRTTMRegionPoolEntryResponse CreateRTTMRegionPoolEntryResponseType + +type UpdateRTTMRegionPoolEntryRequest UpdateRTTMRegionPoolEntryRequestType + +type UpdateRTTMRegionPoolEntryResponse UpdateRTTMRegionPoolEntryResponseType + +type GetOneRTTMRegionPoolEntryRequest GetOneRTTMRegionPoolEntryRequestType + +type GetOneRTTMRegionPoolEntryResponse GetOneRTTMRegionPoolEntryResponseType + +type GetRTTMRegionPoolEntriesRequest GetRTTMRegionPoolEntriesRequestType + +type GetRTTMRegionPoolEntriesResponse GetRTTMRegionPoolEntriesResponseType + +type DeleteOneRTTMRegionPoolEntryRequest DeleteOneRTTMRegionPoolEntryRequestType + +type DeleteOneRTTMRegionPoolEntryResponse DeleteOneRTTMRegionPoolEntryResponseType + +type CreateHTTPRedirectRequest CreateHTTPRedirectRequestType + +type CreateHTTPRedirectResponse CreateHTTPRedirectResponseType + +type GetOneHTTPRedirectRequest GetOneHTTPRedirectRequestType + +type GetOneHTTPRedirectResponse GetOneHTTPRedirectResponseType + +type GetHTTPRedirectsRequest GetHTTPRedirectsRequestType + +type GetHTTPRedirectsResponse GetHTTPRedirectsResponseType + +type UpdateHTTPRedirectRequest UpdateHTTPRedirectRequestType + +type UpdateHTTPRedirectResponse UpdateHTTPRedirectResponseType + +type DeleteOneHTTPRedirectRequest DeleteOneHTTPRedirectRequestType + +type DeleteOneHTTPRedirectResponse DeleteOneHTTPRedirectResponseType + +type CreateAdvRedirectRuleRequest CreateAdvRedirectRuleRequestType + +type CreateAdvRedirectRuleResponse CreateAdvRedirectRuleResponseType + +type UpdateAdvRedirectRuleRequest UpdateAdvRedirectRuleRequestType + +type UpdateAdvRedirectRuleResponse UpdateAdvRedirectRuleResponseType + +type GetOneAdvRedirectRuleRequest GetOneAdvRedirectRuleRequestType + +type GetOneAdvRedirectRuleResponse GetOneAdvRedirectRuleResponseType + +type GetAdvRedirectRulesRequest GetAdvRedirectRulesRequestType + +type GetAdvRedirectRulesResponse GetAdvRedirectRulesResponseType + +type DeleteOneAdvRedirectRuleRequest DeleteOneAdvRedirectRuleRequestType + +type DeleteOneAdvRedirectRuleResponse DeleteOneAdvRedirectRuleResponseType + +type CreateAdvRedirectRequest CreateAdvRedirectRequestType + +type CreateAdvRedirectResponse CreateAdvRedirectResponseType + +type GetOneAdvRedirectRequest GetOneAdvRedirectRequestType + +type GetOneAdvRedirectResponse GetOneAdvRedirectResponseType + +type GetAdvRedirectsRequest GetAdvRedirectsRequestType + +type GetAdvRedirectsResponse GetAdvRedirectsResponseType + +type UpdateAdvRedirectRequest UpdateAdvRedirectRequestType + +type UpdateAdvRedirectResponse UpdateAdvRedirectResponseType + +type DeleteOneAdvRedirectRequest DeleteOneAdvRedirectRequestType + +type DeleteOneAdvRedirectResponse DeleteOneAdvRedirectResponseType + +type GetNodeListRequest GetNodeListRequestType + +type GetNodeListResponse GetNodeListResponseType + +type PublishZoneRequest PublishZoneRequestType + +type PublishZoneResponse PublishZoneResponseType + +type PruneZoneRequest PruneZoneRequestType + +type PruneZoneResponse PruneZoneResponseType + +type FreezeZoneRequest FreezeZoneRequestType + +type FreezeZoneResponse FreezeZoneResponseType + +type ThawZoneRequest ThawZoneRequestType + +type ThawZoneResponse ThawZoneResponseType + +type RestoreZoneRequest RestoreZoneRequestType + +type RestoreZoneResponse RestoreZoneResponseType + +type BlockZoneRequest BlockZoneRequestType + +type BlockZoneResponse BlockZoneResponseType + +type DeleteZoneChangesetRequest DeleteZoneChangesetRequestType + +type DeleteZoneChangesetResponse DeleteZoneChangesetResponseType + +type GetZoneChangesetRequest GetZoneChangesetRequestType + +type GetZoneChangesetResponse GetZoneChangesetResponseType + +type GetZoneNotesRequest GetZoneNotesRequestType + +type GetZoneNotesResponse GetZoneNotesResponseType + +type UploadZoneFileRequest UploadZoneFileRequestType + +type UploadZoneFileResponse UploadZoneFileResponseType + +type TransferZoneInRequest TransferZoneInRequestType + +type TransferZoneInResponse TransferZoneInResponseType + +type GetTransferStatusRequest GetTransferStatusRequestType + +type GetTransferStatusResponse GetTransferStatusResponseType + +type GetZoneConfigOptionsRequest GetZoneConfigOptionsRequestType + +type GetZoneConfigOptionsResponse GetZoneConfigOptionsResponseType + +type SetZoneConfigOptionsRequest SetZoneConfigOptionsRequestType + +type SetZoneConfigOptionsResponse SetZoneConfigOptionsResponseType + +type CreateIPTrackRequest CreateIPTrackRequestType + +type CreateIPTrackResponse CreateIPTrackResponseType + +type GetOneIPTrackRequest GetOneIPTrackRequestType + +type GetOneIPTrackResponse GetOneIPTrackResponseType + +type GetIPTracksRequest GetIPTracksRequestType + +type GetIPTracksResponse GetIPTracksResponseType + +type UpdateIPTrackRequest UpdateIPTrackRequestType + +type UpdateIPTrackResponse UpdateIPTrackResponseType + +type DeleteOneIPTrackRequest DeleteOneIPTrackRequestType + +type DeleteOneIPTrackResponse DeleteOneIPTrackResponseType + +type ActivateIPTrackRequest ActivateIPTrackRequestType + +type ActivateIPTrackResponse ActivateIPTrackResponseType + +type DeactivateIPTrackRequest DeactivateIPTrackRequestType + +type DeactivateIPTrackResponse DeactivateIPTrackResponseType + +type CreateDNSSECRequest CreateDNSSECRequestType + +type CreateDNSSECResponse CreateDNSSECResponseType + +type GetOneDNSSECRequest GetOneDNSSECRequestType + +type GetOneDNSSECResponse GetOneDNSSECResponseType + +type GetDNSSECsRequest GetDNSSECsRequestType + +type GetDNSSECsResponse GetDNSSECsResponseType + +type UpdateDNSSECRequest UpdateDNSSECRequestType + +type UpdateDNSSECResponse UpdateDNSSECResponseType + +type DeleteOneDNSSECRequest DeleteOneDNSSECRequestType + +type DeleteOneDNSSECResponse DeleteOneDNSSECResponseType + +type ActivateDNSSECRequest ActivateDNSSECRequestType + +type ActivateDNSSECResponse ActivateDNSSECResponseType + +type DeactivateDNSSECRequest DeactivateDNSSECRequestType + +type DeactivateDNSSECResponse DeactivateDNSSECResponseType + +type GetDNSSECTimelineRequest GetDNSSECTimelineRequestType + +type GetDNSSECTimelineResponse GetDNSSECTimelineResponseType + +type GetTasksRequest GetTasksRequestType + +type GetTasksResponse GetTasksResponseType + +type GetOneTaskRequest GetOneTaskRequestType + +type GetOneTaskResponse GetOneTaskResponseType + +type CancelTaskRequest CancelTaskRequestType + +type CancelTaskResponse CancelTaskResponseType + +type CreateExtNameserverRequest CreateExtNameserverRequestType + +type CreateExtNameserverResponse CreateExtNameserverResponseType + +type GetOneExtNameserverRequest GetOneExtNameserverRequestType + +type GetOneExtNameserverResponse GetOneExtNameserverResponseType + +type GetExtNameserversRequest GetExtNameserversRequestType + +type GetExtNameserversResponse GetExtNameserversResponseType + +type UpdateExtNameserverRequest UpdateExtNameserverRequestType + +type UpdateExtNameserverResponse UpdateExtNameserverResponseType + +type DeleteOneExtNameserverRequest DeleteOneExtNameserverRequestType + +type DeleteOneExtNameserverResponse DeleteOneExtNameserverResponseType + +type Messages struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ messages"` + + Source string `xml:"source,omitempty" json:"source,omitempty"` + + Lvl string `xml:"lvl,omitempty" json:"lvl,omitempty"` + + Err_cd string `xml:"err_cd,omitempty" json:"err_cd,omitempty"` + + Info string `xml:"info,omitempty" json:"info,omitempty"` +} + +type WeightData struct { + A_weight []string `xml:"a_weight,omitempty" json:"a_weight,omitempty"` + + Aaaa_weight []string `xml:"aaaa_weight,omitempty" json:"aaaa_weight,omitempty"` + + Cname_weight []string `xml:"cname_weight,omitempty" json:"cname_weight,omitempty"` +} + +type ServeCountData struct { + A_serve_count string `xml:"a_serve_count,omitempty" json:"a_serve_count,omitempty"` + + Aaaa_serve_count string `xml:"aaaa_serve_count,omitempty" json:"aaaa_serve_count,omitempty"` +} + +type TTLData struct { + A_ttl int32 `xml:"a_ttl,omitempty" json:"a_ttl,omitempty"` + + Aaaa_ttl int32 `xml:"aaaa_ttl,omitempty" json:"aaaa_ttl,omitempty"` + + Cert_ttl int32 `xml:"cert_ttl,omitempty" json:"cert_ttl,omitempty"` + + Cname_ttl int32 `xml:"cname_ttl,omitempty" json:"cname_ttl,omitempty"` + + Mx_ttl int32 `xml:"mx_ttl,omitempty" json:"mx_ttl,omitempty"` + + Txt_ttl int32 `xml:"txt_ttl,omitempty" json:"txt_ttl,omitempty"` + + Spf_ttl int32 `xml:"spf_ttl,omitempty" json:"spf_ttl,omitempty"` + + Ptr_ttl int32 `xml:"ptr_ttl,omitempty" json:"ptr_ttl,omitempty"` + + Loc_ttl int32 `xml:"loc_ttl,omitempty" json:"loc_ttl,omitempty"` + + Srv_ttl int32 `xml:"srv_ttl,omitempty" json:"srv_ttl,omitempty"` + + Rp_ttl int32 `xml:"rp_ttl,omitempty" json:"rp_ttl,omitempty"` + + Key_ttl int32 `xml:"key_ttl,omitempty" json:"key_ttl,omitempty"` + + Dnskey_ttl int32 `xml:"dnskey_ttl,omitempty" json:"dnskey_ttl,omitempty"` + + Sshfp_ttl int32 `xml:"sshfp_ttl,omitempty" json:"sshfp_ttl,omitempty"` + + Dhcid_ttl int32 `xml:"dhcid_ttl,omitempty" json:"dhcid_ttl,omitempty"` + + Nsap_ttl int32 `xml:"nsap_ttl,omitempty" json:"nsap_ttl,omitempty"` + + Px_ttl int32 `xml:"px_ttl,omitempty" json:"px_ttl,omitempty"` +} + +type LabelData struct { + A_label []string `xml:"a_label,omitempty" json:"a_label,omitempty"` + + Aaaa_label []string `xml:"aaaa_label,omitempty" json:"aaaa_label,omitempty"` + + Cert_label []string `xml:"cert_label,omitempty" json:"cert_label,omitempty"` + + Cname_label []string `xml:"cname_label,omitempty" json:"cname_label,omitempty"` + + Mx_label []string `xml:"mx_label,omitempty" json:"mx_label,omitempty"` + + Txt_label []string `xml:"txt_label,omitempty" json:"txt_label,omitempty"` + + Spf_label []string `xml:"spf_label,omitempty" json:"spf_label,omitempty"` + + Ptr_label []string `xml:"ptr_label,omitempty" json:"ptr_label,omitempty"` + + Loc_label []string `xml:"loc_label,omitempty" json:"loc_label,omitempty"` + + Srv_label []string `xml:"srv_label,omitempty" json:"srv_label,omitempty"` + + Rp_label []string `xml:"rp_label,omitempty" json:"rp_label,omitempty"` + + Key_label []string `xml:"key_label,omitempty" json:"key_label,omitempty"` + + Dnskey_label []string `xml:"dnskey_label,omitempty" json:"dnskey_label,omitempty"` + + Sshfp_label []string `xml:"sshfp_label,omitempty" json:"sshfp_label,omitempty"` + + Dhcid_label []string `xml:"dhcid_label,omitempty" json:"dhcid_label,omitempty"` + + Nsap_label []string `xml:"nsap_label,omitempty" json:"nsap_label,omitempty"` + + Px_label []string `xml:"px_label,omitempty" json:"px_label,omitempty"` +} + +type GeoRegionGroup struct { + Name string `xml:"name,omitempty" json:"name,omitempty"` + + Rdata *ANYRData `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Countries []string `xml:"countries,omitempty" json:"countries,omitempty"` + + Serve_count *ServeCountData `xml:"serve_count,omitempty" json:"serve_count,omitempty"` + + Weight *WeightData `xml:"weight,omitempty" json:"weight,omitempty"` + + Ttl *TTLData `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Label *LabelData `xml:"label,omitempty" json:"label,omitempty"` +} + +type GeoRegionGroupData struct { + Name string `xml:"name,omitempty" json:"name,omitempty"` + + Rdata *ANYRData `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Countries []string `xml:"countries,omitempty" json:"countries,omitempty"` + + Serve_count *ServeCountData `xml:"serve_count,omitempty" json:"serve_count,omitempty"` + + Weight *WeightData `xml:"weight,omitempty" json:"weight,omitempty"` + + Ttl *TTLData `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Label *LabelData `xml:"label,omitempty" json:"label,omitempty"` + + Service_name string `xml:"service_name,omitempty" json:"service_name,omitempty"` +} + +type GeoNode struct { + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type Geo struct { + Name string `xml:"name,omitempty" json:"name,omitempty"` + + Groups []*GeoRegionGroup `xml:"groups,omitempty" json:"groups,omitempty"` + + Nodes []*GeoNode `xml:"nodes,omitempty" json:"nodes,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Active string `xml:"active,omitempty" json:"active,omitempty"` +} + +type DSFRData struct { + Type_ string `xml:"type,omitempty" json:"type,omitempty"` + + Data *GenericRData `xml:"data,omitempty" json:"data,omitempty"` + + Ttl string `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type DSFRecord struct { + Master_line string `xml:"master_line,omitempty" json:"master_line,omitempty"` + + // Rdata to update the svc record with + Rdata *ANYOneRData `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Label string `xml:"label,omitempty" json:"label,omitempty"` + + Weight string `xml:"weight,omitempty" json:"weight,omitempty"` + + Automation string `xml:"automation,omitempty" json:"automation,omitempty"` + + Endpoints []string `xml:"endpoints,omitempty" json:"endpoints,omitempty"` + + Endpoint_up_count string `xml:"endpoint_up_count,omitempty" json:"endpoint_up_count,omitempty"` + + Eligible string `xml:"eligible,omitempty" json:"eligible,omitempty"` +} + +type DSFRecordData struct { + Dsf_record_id string `xml:"dsf_record_id,omitempty" json:"dsf_record_id,omitempty"` + + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + Dsf_record_set_id string `xml:"dsf_record_set_id,omitempty" json:"dsf_record_set_id,omitempty"` + + Label string `xml:"label,omitempty" json:"label,omitempty"` + + Master_line string `xml:"master_line,omitempty" json:"master_line,omitempty"` + + Weight int32 `xml:"weight,omitempty" json:"weight,omitempty"` + + Automation string `xml:"automation,omitempty" json:"automation,omitempty"` + + Endpoints []string `xml:"endpoints,omitempty" json:"endpoints,omitempty"` + + Endpoint_up_count int32 `xml:"endpoint_up_count,omitempty" json:"endpoint_up_count,omitempty"` + + Eligible string `xml:"eligible,omitempty" json:"eligible,omitempty"` + + Rdata_class string `xml:"rdata_class,omitempty" json:"rdata_class,omitempty"` + + Ttl string `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata []*DSFRData `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Response_time int32 `xml:"response_time,omitempty" json:"response_time,omitempty"` + + Torpidity int32 `xml:"torpidity,omitempty" json:"torpidity,omitempty"` + + Last_monitored int32 `xml:"last_monitored,omitempty" json:"last_monitored,omitempty"` + + Pending_change string `xml:"pending_change,omitempty" json:"pending_change,omitempty"` +} + +type DSFRecordSet struct { + Dsf_record_set_id string `xml:"dsf_record_set_id,omitempty" json:"dsf_record_set_id,omitempty"` + + Failover string `xml:"failover,omitempty" json:"failover,omitempty"` + + Rdata_class string `xml:"rdata_class,omitempty" json:"rdata_class,omitempty"` + + Label string `xml:"label,omitempty" json:"label,omitempty"` + + Dsf_monitor_id string `xml:"dsf_monitor_id,omitempty" json:"dsf_monitor_id,omitempty"` + + Ttl string `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Automation string `xml:"automation,omitempty" json:"automation,omitempty"` + + Eligible string `xml:"eligible,omitempty" json:"eligible,omitempty"` + + Serve_count string `xml:"serve_count,omitempty" json:"serve_count,omitempty"` + + Fail_count string `xml:"fail_count,omitempty" json:"fail_count,omitempty"` + + Trouble_count string `xml:"trouble_count,omitempty" json:"trouble_count,omitempty"` + + Torpidity_max string `xml:"torpidity_max,omitempty" json:"torpidity_max,omitempty"` + + Index string `xml:"index,omitempty" json:"index,omitempty"` + + Records []*DSFRecord `xml:"records,omitempty" json:"records,omitempty"` +} + +type DSFRecordSetData struct { + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + Dsf_record_set_id string `xml:"dsf_record_set_id,omitempty" json:"dsf_record_set_id,omitempty"` + + Label string `xml:"label,omitempty" json:"label,omitempty"` + + Rdata_class string `xml:"rdata_class,omitempty" json:"rdata_class,omitempty"` + + Ttl string `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Automation string `xml:"automation,omitempty" json:"automation,omitempty"` + + Serve_count string `xml:"serve_count,omitempty" json:"serve_count,omitempty"` + + Fail_count string `xml:"fail_count,omitempty" json:"fail_count,omitempty"` + + Trouble_count string `xml:"trouble_count,omitempty" json:"trouble_count,omitempty"` + + Torpidity_max string `xml:"torpidity_max,omitempty" json:"torpidity_max,omitempty"` + + Dsf_monitor_id string `xml:"dsf_monitor_id,omitempty" json:"dsf_monitor_id,omitempty"` + + Eligible string `xml:"eligible,omitempty" json:"eligible,omitempty"` + + Pending_change string `xml:"pending_change,omitempty" json:"pending_change,omitempty"` + + Ttl_derived string `xml:"ttl_derived,omitempty" json:"ttl_derived,omitempty"` + + Records []*DSFRecordData `xml:"records,omitempty" json:"records,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Last_monitored string `xml:"last_monitored,omitempty" json:"last_monitored,omitempty"` +} + +type DSFRecordSetFailoverChain struct { + Label string `xml:"label,omitempty" json:"label,omitempty"` + + Core string `xml:"core,omitempty" json:"core,omitempty"` + + Record_sets []*DSFRecordSet `xml:"record_sets,omitempty" json:"record_sets,omitempty"` +} + +type DSFRecordSetFailoverChainData struct { + Dsf_record_set_failover_chain_id string `xml:"dsf_record_set_failover_chain_id,omitempty" json:"dsf_record_set_failover_chain_id,omitempty"` + + Dsf_response_pool_id string `xml:"dsf_response_pool_id,omitempty" json:"dsf_response_pool_id,omitempty"` + + Label string `xml:"label,omitempty" json:"label,omitempty"` + + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + Core string `xml:"core,omitempty" json:"core,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Pending_change string `xml:"pending_change,omitempty" json:"pending_change,omitempty"` + + Record_sets []*DSFRecordSetData `xml:"record_sets,omitempty" json:"record_sets,omitempty"` +} + +type DSFCriteria struct { + Geoip *DSFGeoIPCriteria `xml:"geoip,omitempty" json:"geoip,omitempty"` +} + +type DSFGeoIPCriteria struct { + Country []string `xml:"country,omitempty" json:"country,omitempty"` + + Region []string `xml:"region,omitempty" json:"region,omitempty"` + + Province []string `xml:"province,omitempty" json:"province,omitempty"` +} + +type DSFRulesetData struct { + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + Dsf_ruleset_id string `xml:"dsf_ruleset_id,omitempty" json:"dsf_ruleset_id,omitempty"` + + Label string `xml:"label,omitempty" json:"label,omitempty"` + + Criteria_type string `xml:"criteria_type,omitempty" json:"criteria_type,omitempty"` + + Criteria *DSFCriteria `xml:"criteria,omitempty" json:"criteria,omitempty"` + + Ordering string `xml:"ordering,omitempty" json:"ordering,omitempty"` + + Eligible string `xml:"eligible,omitempty" json:"eligible,omitempty"` + + Response_pools []*DSFResponsePoolData `xml:"response_pools,omitempty" json:"response_pools,omitempty"` + + Pending_change string `xml:"pending_change,omitempty" json:"pending_change,omitempty"` +} + +type DSFRuleset struct { + Dsf_ruleset_id string `xml:"dsf_ruleset_id,omitempty" json:"dsf_ruleset_id,omitempty"` + + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // The type of criteria contained within this Pool + Criteria_type string `xml:"criteria_type,omitempty" json:"criteria_type,omitempty"` + + // Required based on criteria_type. Filtered in API/BLL + Criteria *DSFCriteria `xml:"criteria,omitempty" json:"criteria,omitempty"` + + // where in the list of rulesets this should be. Defaults to last. + Ordering string `xml:"ordering,omitempty" json:"ordering,omitempty"` + + Response_pools []*DSFResponsePool `xml:"response_pools,omitempty" json:"response_pools,omitempty"` +} + +type DSFResponsePoolData struct { + Dsf_response_pool_id string `xml:"dsf_response_pool_id,omitempty" json:"dsf_response_pool_id,omitempty"` + + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // Notify Object + Notifier string `xml:"notifier,omitempty" json:"notifier,omitempty"` + + Automation string `xml:"automation,omitempty" json:"automation,omitempty"` + + Eligible string `xml:"eligible,omitempty" json:"eligible,omitempty"` + + Core_set_count string `xml:"core_set_count,omitempty" json:"core_set_count,omitempty"` + + Pending_change string `xml:"pending_change,omitempty" json:"pending_change,omitempty"` + + Rs_chains []*DSFRecordSetFailoverChainData `xml:"rs_chains,omitempty" json:"rs_chains,omitempty"` + + Rulesets []*DSFRulesetData `xml:"rulesets,omitempty" json:"rulesets,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Last_monitored string `xml:"last_monitored,omitempty" json:"last_monitored,omitempty"` +} + +type DSFResponsePool struct { + Dsf_response_pool_id string `xml:"dsf_response_pool_id,omitempty" json:"dsf_response_pool_id,omitempty"` + + Failover string `xml:"failover,omitempty" json:"failover,omitempty"` + + Label string `xml:"label,omitempty" json:"label,omitempty"` + + Notifier string `xml:"notifier,omitempty" json:"notifier,omitempty"` + + Core_set_count string `xml:"core_set_count,omitempty" json:"core_set_count,omitempty"` + + Automation string `xml:"automation,omitempty" json:"automation,omitempty"` + + Eligible string `xml:"eligible,omitempty" json:"eligible,omitempty"` + + Rs_chains []*DSFRecordSetFailoverChain `xml:"rs_chains,omitempty" json:"rs_chains,omitempty"` + + Ruleset string `xml:"ruleset,omitempty" json:"ruleset,omitempty"` + + Index string `xml:"index,omitempty" json:"index,omitempty"` +} + +type DSFData struct { + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + Active string `xml:"active,omitempty" json:"active,omitempty"` + + Label string `xml:"label,omitempty" json:"label,omitempty"` + + Ttl string `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Nodes []*DSFNode `xml:"nodes,omitempty" json:"nodes,omitempty"` + + Notifiers []*NotifierLinkData `xml:"notifiers,omitempty" json:"notifiers,omitempty"` + + Rulesets []*DSFRulesetData `xml:"rulesets,omitempty" json:"rulesets,omitempty"` + + Pending_change string `xml:"pending_change,omitempty" json:"pending_change,omitempty"` +} + +type DSFNode struct { + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type DSFMonitorData struct { + + // ID + Dsf_monitor_id string `xml:"dsf_monitor_id,omitempty" json:"dsf_monitor_id,omitempty"` + + // Label for the DSF Monitor + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // Indicates whether or not the DSF Monitor is active + Active string `xml:"active,omitempty" json:"active,omitempty"` + + // Num of responses to determine status + Response_count string `xml:"response_count,omitempty" json:"response_count,omitempty"` + + // Interval, in seconds, between probes + Probe_interval string `xml:"probe_interval,omitempty" json:"probe_interval,omitempty"` + + // number of attempted retries on failure before giving up + Retries string `xml:"retries,omitempty" json:"retries,omitempty"` + + // name of the protocol to monitor + Protocol string `xml:"protocol,omitempty" json:"protocol,omitempty"` + + // options pertaining the monitor + Options *DSFMonitorOptions `xml:"options,omitempty" json:"options,omitempty"` + + // IDs of attached notifiers + Notifier []string `xml:"notifier,omitempty" json:"notifier,omitempty"` + + // Endpoints to monitor + Endpoints []*DSFMonitorEndpoint `xml:"endpoints,omitempty" json:"endpoints,omitempty"` + + // how are agents chosen? + Agent_scheme string `xml:"agent_scheme,omitempty" json:"agent_scheme,omitempty"` + + // IDs of attached services + Services []string `xml:"services,omitempty" json:"services,omitempty"` +} + +type DSFMonitorEndpoint struct { + + // Indicates whether or not the end point is active + Active string `xml:"active,omitempty" json:"active,omitempty"` + + // label of the endpoint + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // address for the endpoint + Address string `xml:"address,omitempty" json:"address,omitempty"` + + // ordered list of preferred sites for monitoring + Site_prefs []string `xml:"site_prefs,omitempty" json:"site_prefs,omitempty"` +} + +type DSFMonitorOptions struct { + + // time, in seconds, before the check timeout + Timeout string `xml:"timeout,omitempty" json:"timeout,omitempty"` + + // an alternate port to connect to + Port string `xml:"port,omitempty" json:"port,omitempty"` + + // a specific path to request + Path string `xml:"path,omitempty" json:"path,omitempty"` + + // a value to pass into the `HOST:` header + Host string `xml:"host,omitempty" json:"host,omitempty"` + + // additional header fields + Header string `xml:"header,omitempty" json:"header,omitempty"` + + // a string to search for in the response + Expected string `xml:"expected,omitempty" json:"expected,omitempty"` + + Host_override []*DSFMonitorHostOverride `xml:"host_override,omitempty" json:"host_override,omitempty"` +} + +type DSFMonitorHostOverride struct { + + // address of an endpoint + Address string `xml:"address,omitempty" json:"address,omitempty"` + + // host to use when checking that endpoint + Host string `xml:"host,omitempty" json:"host,omitempty"` +} + +type DSFMonitorSitesData struct { + + // information for a site performing DSF monitoring + DSFMonitorSites []*DSFMonitorSite `xml:"DSFMonitorSites,omitempty" json:"DSFMonitorSites,omitempty"` +} + +type DSFMonitorSite struct { + + // site code for the monitoring machine + Code string `xml:"code,omitempty" json:"code,omitempty"` + + // description of the machine's location + Description string `xml:"description,omitempty" json:"description,omitempty"` + + // CIDR of the monitoring machine(s) + Address string `xml:"address,omitempty" json:"address,omitempty"` +} + +type Notifier struct { + + // Label for the Notifier object + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // List of Recipients attached to the Notifier + Recipients []*Recipient `xml:"recipients,omitempty" json:"recipients,omitempty"` + + // List of services attached to the Notifier + Services []*Service `xml:"services,omitempty" json:"services,omitempty"` +} + +type NotifierLink struct { + + // Public_id of the Notifier to link to + Notifier_id string `xml:"notifier_id,omitempty" json:"notifier_id,omitempty"` + + // filters on when services should fire the notifier + Filters []string `xml:"filters,omitempty" json:"filters,omitempty"` +} + +type NotifierDataAlt struct { + + // Public ID of the Notifier object + Notifier_id string `xml:"notifier_id,omitempty" json:"notifier_id,omitempty"` + + // Label for the Notifier object + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // Indicates whether or not the Notifier is active + Active string `xml:"active,omitempty" json:"active,omitempty"` + + // List of Recepients attached to the Notifier + Recipients []string `xml:"recipients,omitempty" json:"recipients,omitempty"` + + // List of services attached to the Notifier + Services []*Service `xml:"services,omitempty" json:"services,omitempty"` +} + +type NotifierData struct { + + // Public ID of the Notifier object + Notifier_id string `xml:"notifier_id,omitempty" json:"notifier_id,omitempty"` + + // Label for the Notifier object + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // Indicates whether or not the Notifier is active + Active string `xml:"active,omitempty" json:"active,omitempty"` + + // List of Recepients attached to the Notifier + Recipients []*Recipient `xml:"recipients,omitempty" json:"recipients,omitempty"` + + // List of services attached to the Notifier + Services []*Service `xml:"services,omitempty" json:"services,omitempty"` +} + +type NotifierLinkData struct { + + // Public ID of the Notifier object + Link_id string `xml:"link_id,omitempty" json:"link_id,omitempty"` + + // Indicates whether or not the Notifier link is active + Active string `xml:"active,omitempty" json:"active,omitempty"` + + // filters on when services should fire the notifier + Filters []string `xml:"filters,omitempty" json:"filters,omitempty"` + + Notifier *NotifierSummaryData `xml:"notifier,omitempty" json:"notifier,omitempty"` +} + +type NotifierSummaryData struct { + + // Public ID of the Notifier object + Notifier_id string `xml:"notifier_id,omitempty" json:"notifier_id,omitempty"` + + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // List of Recepients attached to the Notifier + Recipients []string `xml:"recipients,omitempty" json:"recipients,omitempty"` + + // Indicates whether or not the Notifier is active + Active string `xml:"active,omitempty" json:"active,omitempty"` +} + +type Recipient struct { + + // email or syslog + Format string `xml:"format,omitempty" json:"format,omitempty"` + + // For email, valid address or contact name. Syslog - address or hostname + Recipient string `xml:"recipient,omitempty" json:"recipient,omitempty"` + + // hash of options + Details *RecipientDetail `xml:"details,omitempty" json:"details,omitempty"` + + // List of string. For email - detail and summary are valid + Features []string `xml:"features,omitempty" json:"features,omitempty"` +} + +type RecipientDetail struct { + + // syslog port + Port string `xml:"port,omitempty" json:"port,omitempty"` + + // syslog ident + Ident string `xml:"ident,omitempty" json:"ident,omitempty"` + + // syslog facility + Facility string `xml:"facility,omitempty" json:"facility,omitempty"` + + // syslog tls + Tls string `xml:"tls,omitempty" json:"tls,omitempty"` +} + +type Service struct { + + // Valid entries - DSF or Monitor + Service_class string `xml:"service_class,omitempty" json:"service_class,omitempty"` + + // public_id of the specified service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // filters on when services should fire the notifier + Filters []string `xml:"filters,omitempty" json:"filters,omitempty"` + + // Indicates whether or not the link to the service is active + Active string `xml:"active,omitempty" json:"active,omitempty"` +} + +type ConfigLimitData struct { + Name string `xml:"name,omitempty" json:"name,omitempty"` + + Value string `xml:"value,omitempty" json:"value,omitempty"` +} + +type PermissionZone struct { + Zone_name string `xml:"zone_name,omitempty" json:"zone_name,omitempty"` + + Recurse string `xml:"recurse,omitempty" json:"recurse,omitempty"` + + // This field is returned in responses from the API, it should not be included in requests. + Reason []string `xml:"reason,omitempty" json:"reason,omitempty"` +} + +type PermissionResponse struct { + Admin_override string `xml:"admin_override,omitempty" json:"admin_override,omitempty"` + + Allowed []*PermissionData `xml:"allowed,omitempty" json:"allowed,omitempty"` + + Forbidden []*PermissionData `xml:"forbidden,omitempty" json:"forbidden,omitempty"` +} + +type PermissionData struct { + Name string `xml:"name,omitempty" json:"name,omitempty"` + + Zone []*PermissionZone `xml:"zone,omitempty" json:"zone,omitempty"` + + Reason []string `xml:"reason,omitempty" json:"reason,omitempty"` +} + +type PermissionGroupData struct { + Group_name string `xml:"group_name,omitempty" json:"group_name,omitempty"` + + Type_ string `xml:"type,omitempty" json:"type,omitempty"` + + Description string `xml:"description,omitempty" json:"description,omitempty"` + + Permission []string `xml:"permission,omitempty" json:"permission,omitempty"` + + User_name []string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + Subgroup []string `xml:"subgroup,omitempty" json:"subgroup,omitempty"` + + Zone []*PermissionZone `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type TSIGKeyData struct { + Name string `xml:"name,omitempty" json:"name,omitempty"` + + Algorithm string `xml:"algorithm,omitempty" json:"algorithm,omitempty"` + + Secret string `xml:"secret,omitempty" json:"secret,omitempty"` +} + +type HostStatFlagsData struct { + + // empty for customer-wide default + Zone_name string `xml:"zone_name,omitempty" json:"zone_name,omitempty"` + + // Y or N + Active string `xml:"active,omitempty" json:"active,omitempty"` +} + +type ZoneData struct { + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // code indicating how serial numbers are constructed on publish + Serial_style string `xml:"serial_style,omitempty" json:"serial_style,omitempty"` + + // current serial number + Serial int32 `xml:"serial,omitempty" json:"serial,omitempty"` + + // Type of zone. Primary or Secondary + Zone_type string `xml:"zone_type,omitempty" json:"zone_type,omitempty"` +} + +type SecondaryData struct { + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Masters []string `xml:"masters,omitempty" json:"masters,omitempty"` + + Tsig_key_name string `xml:"tsig_key_name,omitempty" json:"tsig_key_name,omitempty"` + + Contact_nickname string `xml:"contact_nickname,omitempty" json:"contact_nickname,omitempty"` + + Active string `xml:"active,omitempty" json:"active,omitempty"` + + Task_id string `xml:"task_id,omitempty" json:"task_id,omitempty"` +} + +type SessionLoginData struct { + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Version string `xml:"version,omitempty" json:"version,omitempty"` +} + +type QueryStatsData struct { + Csv string `xml:"csv,omitempty" json:"csv,omitempty"` +} + +type ARecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataA `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type AAAARecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataAAAA `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type ALIASRecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataALIAS `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type CAARecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataCAA `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type CDNSKEYRecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataCDNSKEY `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type CDSRecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataCDS `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type CERTRecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataCERT `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type CNAMERecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataCNAME `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type CSYNCRecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataCSYNC `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DHCIDRecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataDHCID `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DNAMERecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataDNAME `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DNSKEYRecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataDNSKEY `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DSRecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataDS `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type IPSECKEYRecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataIPSECKEY `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type KEYRecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataKEY `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type KXRecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataKX `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type LOCRecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataLOC `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type MXRecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataMX `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type NAPTRRecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataNAPTR `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type NSAPRecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataNSAP `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type POLICYRecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataPOLICY `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type PTRRecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataPTR `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type PXRecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataPX `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type RPRecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataRP `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type SPFRecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataSPF `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type SRVRecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataSRV `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type SSHFPRecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataSSHFP `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type TLSARecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataTLSA `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type TXTRecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataTXT `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type SOARecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataSOA `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Serial_style string `xml:"serial_style,omitempty" json:"serial_style,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type RDataSOAUpdate struct { + Rname string `xml:"rname,omitempty" json:"rname,omitempty"` + + Refresh string `xml:"refresh,omitempty" json:"refresh,omitempty"` + + Retry string `xml:"retry,omitempty" json:"retry,omitempty"` + + Expire string `xml:"expire,omitempty" json:"expire,omitempty"` + + Minimum string `xml:"minimum,omitempty" json:"minimum,omitempty"` +} + +type NSRecordData struct { + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataNS `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Service_class string `xml:"service_class,omitempty" json:"service_class,omitempty"` + + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type UserData struct { + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + User_id string `xml:"user_id,omitempty" json:"user_id,omitempty"` + + Password string `xml:"password,omitempty" json:"password,omitempty"` + + Group_name []string `xml:"group_name,omitempty" json:"group_name,omitempty"` + + Nickname string `xml:"nickname,omitempty" json:"nickname,omitempty"` + + First_name string `xml:"first_name,omitempty" json:"first_name,omitempty"` + + Last_name string `xml:"last_name,omitempty" json:"last_name,omitempty"` + + Phone string `xml:"phone,omitempty" json:"phone,omitempty"` + + Fax string `xml:"fax,omitempty" json:"fax,omitempty"` + + Email string `xml:"email,omitempty" json:"email,omitempty"` + + Notify_email string `xml:"notify_email,omitempty" json:"notify_email,omitempty"` + + Pager_email string `xml:"pager_email,omitempty" json:"pager_email,omitempty"` + + Address string `xml:"address,omitempty" json:"address,omitempty"` + + Address_2 string `xml:"address_2,omitempty" json:"address_2,omitempty"` + + City string `xml:"city,omitempty" json:"city,omitempty"` + + State string `xml:"state,omitempty" json:"state,omitempty"` + + Post_code string `xml:"post_code,omitempty" json:"post_code,omitempty"` + + Country string `xml:"country,omitempty" json:"country,omitempty"` + + Website string `xml:"website,omitempty" json:"website,omitempty"` + + Organization string `xml:"organization,omitempty" json:"organization,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` +} + +type ContactData struct { + Nickname string `xml:"nickname,omitempty" json:"nickname,omitempty"` + + First_name string `xml:"first_name,omitempty" json:"first_name,omitempty"` + + Last_name string `xml:"last_name,omitempty" json:"last_name,omitempty"` + + Phone string `xml:"phone,omitempty" json:"phone,omitempty"` + + Fax string `xml:"fax,omitempty" json:"fax,omitempty"` + + Email string `xml:"email,omitempty" json:"email,omitempty"` + + Notify_email string `xml:"notify_email,omitempty" json:"notify_email,omitempty"` + + Pager_email string `xml:"pager_email,omitempty" json:"pager_email,omitempty"` + + Address string `xml:"address,omitempty" json:"address,omitempty"` + + Address_2 string `xml:"address_2,omitempty" json:"address_2,omitempty"` + + City string `xml:"city,omitempty" json:"city,omitempty"` + + State string `xml:"state,omitempty" json:"state,omitempty"` + + Post_code string `xml:"post_code,omitempty" json:"post_code,omitempty"` + + Country string `xml:"country,omitempty" json:"country,omitempty"` + + Website string `xml:"website,omitempty" json:"website,omitempty"` + + Organization string `xml:"organization,omitempty" json:"organization,omitempty"` +} + +type CustomerNSData struct { + Primary string `xml:"primary,omitempty" json:"primary,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type CustomerInterfaceData struct { + Name string `xml:"name,omitempty" json:"name,omitempty"` + + Address []string `xml:"address,omitempty" json:"address,omitempty"` +} + +type CustomerData struct { + Id string `xml:"id,omitempty" json:"id,omitempty"` + + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` + + Organization string `xml:"organization,omitempty" json:"organization,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Pool_id string `xml:"pool_id,omitempty" json:"pool_id,omitempty"` + + Activated string `xml:"activated,omitempty" json:"activated,omitempty"` + + Type_ string `xml:"type,omitempty" json:"type,omitempty"` + + Level string `xml:"level,omitempty" json:"level,omitempty"` + + Owner_contact string `xml:"owner_contact,omitempty" json:"owner_contact,omitempty"` + + Billing_contact string `xml:"billing_contact,omitempty" json:"billing_contact,omitempty"` + + Primary_sales_agent string `xml:"primary_sales_agent,omitempty" json:"primary_sales_agent,omitempty"` + + Salesforce_id string `xml:"salesforce_id,omitempty" json:"salesforce_id,omitempty"` + + Default_ns []*CustomerNSData `xml:"default_ns,omitempty" json:"default_ns,omitempty"` + + Interfaces []*CustomerInterfaceData `xml:"interfaces,omitempty" json:"interfaces,omitempty"` + + Admin_user_id string `xml:"admin_user_id,omitempty" json:"admin_user_id,omitempty"` + + Compartment_id string `xml:"compartment_id,omitempty" json:"compartment_id,omitempty"` + + Tenant string `xml:"tenant,omitempty" json:"tenant,omitempty"` +} + +type CustomerAdminData struct { + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + Password string `xml:"password,omitempty" json:"password,omitempty"` + + Email string `xml:"email,omitempty" json:"email,omitempty"` + + First_name string `xml:"first_name,omitempty" json:"first_name,omitempty"` + + Last_name string `xml:"last_name,omitempty" json:"last_name,omitempty"` + + Phone string `xml:"phone,omitempty" json:"phone,omitempty"` + + Fax string `xml:"fax,omitempty" json:"fax,omitempty"` + + Notify_email string `xml:"notify_email,omitempty" json:"notify_email,omitempty"` + + Pager_email string `xml:"pager_email,omitempty" json:"pager_email,omitempty"` + + Address string `xml:"address,omitempty" json:"address,omitempty"` + + Address_2 string `xml:"address_2,omitempty" json:"address_2,omitempty"` + + City string `xml:"city,omitempty" json:"city,omitempty"` + + State string `xml:"state,omitempty" json:"state,omitempty"` + + Post_code string `xml:"post_code,omitempty" json:"post_code,omitempty"` + + Country string `xml:"country,omitempty" json:"country,omitempty"` + + Website string `xml:"website,omitempty" json:"website,omitempty"` + + Organization string `xml:"organization,omitempty" json:"organization,omitempty"` +} + +type CustomerPrefData struct { + + // name of the pref setting + Name string `xml:"name,omitempty" json:"name,omitempty"` + + // value of the setting + Value string `xml:"value,omitempty" json:"value,omitempty"` + + // Y/N: pref is not explicitly set, this is the default value + Default_ string `xml:"default,omitempty" json:"default,omitempty"` +} + +type CustomerIPACL struct { + + // comma or space-delimited list of netmasks, in CIDR form; no '/' assumes exact address + Netmasks string `xml:"netmasks,omitempty" json:"netmasks,omitempty"` + + // 'Y'/'N', default 'Y' + Active string `xml:"active,omitempty" json:"active,omitempty"` + + // 'web'/'api', default 'web' + Scope string `xml:"scope,omitempty" json:"scope,omitempty"` +} + +type CustomerOracleMetadataData struct { + + // compartment id + Compartment_id string `xml:"compartment_id,omitempty" json:"compartment_id,omitempty"` + + // customer id + Cust_id string `xml:"cust_id,omitempty" json:"cust_id,omitempty"` + + // tenant id + Tenant string `xml:"tenant,omitempty" json:"tenant,omitempty"` +} + +type ZoneOracleMetadataData struct { + + // compartment id + Compartment_id string `xml:"compartment_id,omitempty" json:"compartment_id,omitempty"` + + // public id + Public_id string `xml:"public_id,omitempty" json:"public_id,omitempty"` + + // zone id + Zone_id string `xml:"zone_id,omitempty" json:"zone_id,omitempty"` +} + +type RedirectData struct { + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl string `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata string `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Rtype string `xml:"rtype,omitempty" json:"rtype,omitempty"` + + SubstituteRtype string `xml:"substituteRtype,omitempty" json:"substituteRtype,omitempty"` +} + +type Replacement struct { + Redirects []*RedirectData `xml:"redirects,omitempty" json:"redirects,omitempty"` +} + +type DDNSData struct { + + // an IP address, either v4 or v6 + Address string `xml:"address,omitempty" json:"address,omitempty"` + + // either A or AAAA + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // last time this service was update by a Dynamic DNS client + Last_updated string `xml:"last_updated,omitempty" json:"last_updated,omitempty"` + + // count of excessive updates + Abuse_count string `xml:"abuse_count,omitempty" json:"abuse_count,omitempty"` + + // 'Y', 'N' + Active string `xml:"active,omitempty" json:"active,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type UpdateUserPasswordData struct { + Password string `xml:"password,omitempty" json:"password,omitempty"` +} + +type UpdateUser struct { + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + Password string `xml:"password,omitempty" json:"password,omitempty"` + + Group_name []string `xml:"group_name,omitempty" json:"group_name,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` +} + +type DDNSHostData struct { + Ddns *DDNSData `xml:"ddns,omitempty" json:"ddns,omitempty"` + + New_user *UpdateUser `xml:"new_user,omitempty" json:"new_user,omitempty"` +} + +type FailoverData struct { + + // normally served address + Address string `xml:"address,omitempty" json:"address,omitempty"` + + // TTL (time-to-live) + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + // 'ip' or 'cname' + Failover_mode string `xml:"failover_mode,omitempty" json:"failover_mode,omitempty"` + + // address or CNAME to serve on failover + Failover_data string `xml:"failover_data,omitempty" json:"failover_data,omitempty"` + + // restore normal address automatically (Y) + Auto_recover string `xml:"auto_recover,omitempty" json:"auto_recover,omitempty"` + + // The number of consecutive monitoring intervals to delay before placing an IP address back in service + Recovery_delay int32 `xml:"recovery_delay,omitempty" json:"recovery_delay,omitempty"` + + // contact that gets status notification + Contact_nickname string `xml:"contact_nickname,omitempty" json:"contact_nickname,omitempty"` + + // when notifications are sent + Notify_events string `xml:"notify_events,omitempty" json:"notify_events,omitempty"` + + // The IP or hostname of a syslog server to send monitor events to + Syslog_server string `xml:"syslog_server,omitempty" json:"syslog_server,omitempty"` + + // The port of the syslog server. Defaults to 514 if not present + Syslog_port string `xml:"syslog_port,omitempty" json:"syslog_port,omitempty"` + + // The syslog ident to use. Defaults to 'dynect' + Syslog_ident string `xml:"syslog_ident,omitempty" json:"syslog_ident,omitempty"` + + // The syslog facility to use. Defaults to 'daemon' + Syslog_facility string `xml:"syslog_facility,omitempty" json:"syslog_facility,omitempty"` + + // When to deliver syslog message; 'change' or 'all' + Syslog_delivery string `xml:"syslog_delivery,omitempty" json:"syslog_delivery,omitempty"` + + // for custom syslog messages + Syslog_probe_fmt string `xml:"syslog_probe_fmt,omitempty" json:"syslog_probe_fmt,omitempty"` + + // for custom syslog messages + Syslog_status_fmt string `xml:"syslog_status_fmt,omitempty" json:"syslog_status_fmt,omitempty"` + + // details about monitoring + Monitor *MonitorData `xml:"monitor,omitempty" json:"monitor,omitempty"` + + // 'ok', 'trouble', 'failover' + Status string `xml:"status,omitempty" json:"status,omitempty"` + + // 'Y', 'N' + Active string `xml:"active,omitempty" json:"active,omitempty"` + + // monitoring changes task + Task_id string `xml:"task_id,omitempty" json:"task_id,omitempty"` + + // Recent monitoring results. This field is returned in responses from the API, it should not be included in requests. + Log []*MonitorLogData `xml:"log,omitempty" json:"log,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type MonitorData struct { + + // HTTP, HTTPS, PING, SMTP, TCP, NONE + Protocol string `xml:"protocol,omitempty" json:"protocol,omitempty"` + + // time between checks, in minutes + Interval int32 `xml:"interval,omitempty" json:"interval,omitempty"` + + // times to retest on failure + Retries int32 `xml:"retries,omitempty" json:"retries,omitempty"` + + // if different from service default + Port int32 `xml:"port,omitempty" json:"port,omitempty"` + + // e.g: http://host/path + Path string `xml:"path,omitempty" json:"path,omitempty"` + + // if different from fqdn + Host string `xml:"host,omitempty" json:"host,omitempty"` + + // check response for specific text + Expected string `xml:"expected,omitempty" json:"expected,omitempty"` + + // additional HTTP headers + Header string `xml:"header,omitempty" json:"header,omitempty"` + + // test timeout + Timeout int32 `xml:"timeout,omitempty" json:"timeout,omitempty"` +} + +type MonitorLogData struct { + + // 'up', 'down', 'unk' + Status string `xml:"status,omitempty" json:"status,omitempty"` + + // more details on error + Message string `xml:"message,omitempty" json:"message,omitempty"` + + // unix timestamp of monitor + Time int32 `xml:"time,omitempty" json:"time,omitempty"` + + // "airport" code + Site_code string `xml:"site_code,omitempty" json:"site_code,omitempty"` +} + +type LoadBalanceData struct { + + // pool of IP addresses to balance + Pool []*LoadBalanceAddress `xml:"pool,omitempty" json:"pool,omitempty"` + + // TTL (time-to-live) + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + // 'ip', 'global', or 'cname' + Failover_mode string `xml:"failover_mode,omitempty" json:"failover_mode,omitempty"` + + // for 'ip' or 'cname', what to serve on failover + Failover_data string `xml:"failover_data,omitempty" json:"failover_data,omitempty"` + + // restore normal address automatically (Y) + Auto_recover string `xml:"auto_recover,omitempty" json:"auto_recover,omitempty"` + + // The number of consecutive monitoring intervals to delay before placing an IP address back in service + Recovery_delay int32 `xml:"recovery_delay,omitempty" json:"recovery_delay,omitempty"` + + // contact that gets status notification + Contact_nickname string `xml:"contact_nickname,omitempty" json:"contact_nickname,omitempty"` + + // when notifications are sent + Notify_events string `xml:"notify_events,omitempty" json:"notify_events,omitempty"` + + // The IP or hostname of a syslog server to send monitor events to + Syslog_server string `xml:"syslog_server,omitempty" json:"syslog_server,omitempty"` + + // The port of the syslog server. Defaults to 514 if not present + Syslog_port string `xml:"syslog_port,omitempty" json:"syslog_port,omitempty"` + + // The syslog ident to use. Defaults to 'dynect' + Syslog_ident string `xml:"syslog_ident,omitempty" json:"syslog_ident,omitempty"` + + // The syslog facility to use. Defaults to 'daemon' + Syslog_facility string `xml:"syslog_facility,omitempty" json:"syslog_facility,omitempty"` + + // When to deliver syslog message; 'change' or 'all' + Syslog_delivery string `xml:"syslog_delivery,omitempty" json:"syslog_delivery,omitempty"` + + // for custom syslog messages + Syslog_probe_fmt string `xml:"syslog_probe_fmt,omitempty" json:"syslog_probe_fmt,omitempty"` + + // for custom syslog messages + Syslog_status_fmt string `xml:"syslog_status_fmt,omitempty" json:"syslog_status_fmt,omitempty"` + + // number of addresses in each DNS response + Serve_count int32 `xml:"serve_count,omitempty" json:"serve_count,omitempty"` + + // details about monitoring + Monitor *MonitorData `xml:"monitor,omitempty" json:"monitor,omitempty"` + + // 'ok', 'trouble', 'failover' + Status string `xml:"status,omitempty" json:"status,omitempty"` + + // 'Y', 'N' + Active string `xml:"active,omitempty" json:"active,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type LoadBalanceAddress struct { + + // an IP address to monitor and publish + Address string `xml:"address,omitempty" json:"address,omitempty"` + + // a human-readable label + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // how often this is served relative to others in pool + Weight int32 `xml:"weight,omitempty" json:"weight,omitempty"` + + // how this address reponds to monitoring: obey,remove,always,no + Serve_mode string `xml:"serve_mode,omitempty" json:"serve_mode,omitempty"` + + // current monitoring status This field is returned in responses from the API, it should not be included in requests. + Status string `xml:"status,omitempty" json:"status,omitempty"` + + // Recent monitoring results for this address. This field is returned in responses from the API, it should not be included in requests. + Log []*MonitorLogData `xml:"log,omitempty" json:"log,omitempty"` +} + +type LoadBalancePoolEntry struct { + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // an IP address to monitor and publish + Address string `xml:"address,omitempty" json:"address,omitempty"` + + // a human-readable label + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // how often this is served relative to others in pool + Weight int32 `xml:"weight,omitempty" json:"weight,omitempty"` + + // how this address reponds to monitoring: obey,remove,always,no + Serve_mode string `xml:"serve_mode,omitempty" json:"serve_mode,omitempty"` + + // current monitoring status This field is returned in responses from the API, it should not be included in requests. + Status string `xml:"status,omitempty" json:"status,omitempty"` + + // Recent monitoring results for this address. This field is returned in responses from the API, it should not be included in requests. + Log []*MonitorLogData `xml:"log,omitempty" json:"log,omitempty"` +} + +type GSLBData struct { + + // per-region addresses and configuration + Region []*GSLBRegion `xml:"region,omitempty" json:"region,omitempty"` + + // TTL (time-to-live) + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + // restore normal address automatically (Y) + Auto_recover string `xml:"auto_recover,omitempty" json:"auto_recover,omitempty"` + + // The number of consecutive monitoring intervals to delay before placing an IP address back in service + Recovery_delay int32 `xml:"recovery_delay,omitempty" json:"recovery_delay,omitempty"` + + // contact that gets status notification + Contact_nickname string `xml:"contact_nickname,omitempty" json:"contact_nickname,omitempty"` + + // when notifications are sent + Notify_events string `xml:"notify_events,omitempty" json:"notify_events,omitempty"` + + // The IP or hostname of a syslog server to send monitor events to + Syslog_server string `xml:"syslog_server,omitempty" json:"syslog_server,omitempty"` + + // The port of the syslog server. Defaults to 514 if not present + Syslog_port string `xml:"syslog_port,omitempty" json:"syslog_port,omitempty"` + + // The syslog ident to use. Defaults to 'dynect' + Syslog_ident string `xml:"syslog_ident,omitempty" json:"syslog_ident,omitempty"` + + // The syslog facility to use. Defaults to 'daemon' + Syslog_facility string `xml:"syslog_facility,omitempty" json:"syslog_facility,omitempty"` + + // When to deliver syslog message; 'change' or 'all' + Syslog_delivery string `xml:"syslog_delivery,omitempty" json:"syslog_delivery,omitempty"` + + // for custom syslog messages + Syslog_probe_fmt string `xml:"syslog_probe_fmt,omitempty" json:"syslog_probe_fmt,omitempty"` + + // for custom syslog messages + Syslog_status_fmt string `xml:"syslog_status_fmt,omitempty" json:"syslog_status_fmt,omitempty"` + + // details about monitoring + Monitor *MonitorData `xml:"monitor,omitempty" json:"monitor,omitempty"` + + // 'ok', 'trouble', 'failover' + Status string `xml:"status,omitempty" json:"status,omitempty"` + + // 'Y', 'N' + Active string `xml:"active,omitempty" json:"active,omitempty"` + + // monitoring changes task + Task_id string `xml:"task_id,omitempty" json:"task_id,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GSLBRegion struct { + + // 'global' or specific region code: 'US West', 'US Central', 'US East', 'EU West', 'EU Central', 'Asia', + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` + + // 'ip', 'global', or 'cname' + Failover_mode string `xml:"failover_mode,omitempty" json:"failover_mode,omitempty"` + + // for 'ip' or 'cname', what to serve on failover + Failover_data string `xml:"failover_data,omitempty" json:"failover_data,omitempty"` + + // number of addresses in each DNS response + Serve_count int32 `xml:"serve_count,omitempty" json:"serve_count,omitempty"` + + // number of 'ok' addresses before region fails over + Min_healthy int32 `xml:"min_healthy,omitempty" json:"min_healthy,omitempty"` + + // pool of IP addresses to balance + Pool []*GSLBAddress `xml:"pool,omitempty" json:"pool,omitempty"` +} + +type GSLBAddress struct { + + // an IP address or FQDN to monitor and publish + Address string `xml:"address,omitempty" json:"address,omitempty"` + + // a human-readable label + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // how often this is served relative to others in pool + Weight int32 `xml:"weight,omitempty" json:"weight,omitempty"` + + // how this address reponds to monitoring: obey,remove,always,no + Serve_mode string `xml:"serve_mode,omitempty" json:"serve_mode,omitempty"` + + // current monitoring status This field is returned in responses from the API, it should not be included in requests. + Status string `xml:"status,omitempty" json:"status,omitempty"` + + // Recent monitoring results for this address. This field is returned in responses from the API, it should not be included in requests. + Log []*MonitorLogData `xml:"log,omitempty" json:"log,omitempty"` +} + +type GSLBRegionData struct { + + // 'global' or specific region code: 'US West', 'US Central', 'US East', 'EU West', 'EU Central', 'Asia', + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` + + // 'ip', 'global', or 'cname' + Failover_mode string `xml:"failover_mode,omitempty" json:"failover_mode,omitempty"` + + // for 'ip' or 'cname', what to serve on failover + Failover_data string `xml:"failover_data,omitempty" json:"failover_data,omitempty"` + + // number of addresses in each DNS response + Serve_count int32 `xml:"serve_count,omitempty" json:"serve_count,omitempty"` + + // number of 'ok' addresses before region fails over + Min_healthy int32 `xml:"min_healthy,omitempty" json:"min_healthy,omitempty"` + + // pool of IP addresses to balance + Pool []*GSLBAddress `xml:"pool,omitempty" json:"pool,omitempty"` + + // 'ok', 'trouble', 'failover' + Status string `xml:"status,omitempty" json:"status,omitempty"` + + // monitoring changes task + Task_id string `xml:"task_id,omitempty" json:"task_id,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GSLBRegionPoolEntry struct { + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // 'global' or specific region code: 'US West', 'US Central', 'US East', 'EU West', 'EU Central', 'Asia', + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` + + // an IP address or FQDN to monitor and publish + Address string `xml:"address,omitempty" json:"address,omitempty"` + + // a human-readable label + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // how often this is served relative to others in pool + Weight int32 `xml:"weight,omitempty" json:"weight,omitempty"` + + // how this address reponds to monitoring: obey,remove,always,no + Serve_mode string `xml:"serve_mode,omitempty" json:"serve_mode,omitempty"` + + // current monitoring status This field is returned in responses from the API, it should not be included in requests. + Status string `xml:"status,omitempty" json:"status,omitempty"` + + // monitoring changes task This field is returned in responses from the API, it should not be included in requests. + Task_id string `xml:"task_id,omitempty" json:"task_id,omitempty"` + + // Recent monitoring results for this address. This field is returned in responses from the API, it should not be included in requests. + Log []*MonitorLogData `xml:"log,omitempty" json:"log,omitempty"` +} + +type RTTMData struct { + + // per-region addresses and configuration + Region []*RTTMRegion `xml:"region,omitempty" json:"region,omitempty"` + + // TTL (time-to-live) + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + // restore normal address automatically (Y) + Auto_recover string `xml:"auto_recover,omitempty" json:"auto_recover,omitempty"` + + // The number of consecutive monitoring intervals to delay before placing an IP address back in service + Recovery_delay int32 `xml:"recovery_delay,omitempty" json:"recovery_delay,omitempty"` + + // contact that gets status notification + Contact_nickname string `xml:"contact_nickname,omitempty" json:"contact_nickname,omitempty"` + + // when notifications are sent + Notify_events string `xml:"notify_events,omitempty" json:"notify_events,omitempty"` + + // The IP or hostname of a syslog server to send monitor events to + Syslog_server string `xml:"syslog_server,omitempty" json:"syslog_server,omitempty"` + + // The port of the syslog server. Defaults to 514 if not present + Syslog_port string `xml:"syslog_port,omitempty" json:"syslog_port,omitempty"` + + // The syslog ident to use. Defaults to 'dynect' + Syslog_ident string `xml:"syslog_ident,omitempty" json:"syslog_ident,omitempty"` + + // The syslog facility to use. Defaults to 'daemon' + Syslog_facility string `xml:"syslog_facility,omitempty" json:"syslog_facility,omitempty"` + + // When to deliver syslog message; 'change' or 'all' + Syslog_delivery string `xml:"syslog_delivery,omitempty" json:"syslog_delivery,omitempty"` + + // for custom syslog messages + Syslog_probe_fmt string `xml:"syslog_probe_fmt,omitempty" json:"syslog_probe_fmt,omitempty"` + + // for custom syslog messages + Syslog_status_fmt string `xml:"syslog_status_fmt,omitempty" json:"syslog_status_fmt,omitempty"` + + // for custom syslog messages + Syslog_rttm_fmt string `xml:"syslog_rttm_fmt,omitempty" json:"syslog_rttm_fmt,omitempty"` + + // details about monitoring + Monitor *MonitorData `xml:"monitor,omitempty" json:"monitor,omitempty"` + + // details about performance monitoring + Performance_monitor *MonitorData `xml:"performance_monitor,omitempty" json:"performance_monitor,omitempty"` + + // 'ok', 'unk', 'trouble', 'failover' + Status string `xml:"status,omitempty" json:"status,omitempty"` + + // 'Y', 'N' + Active string `xml:"active,omitempty" json:"active,omitempty"` + + // monitoring changes task + Task_id string `xml:"task_id,omitempty" json:"task_id,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type RTTMRegion struct { + + // 'global' or specific region code: 'US West', 'US Central', 'US East', 'EU West', 'EU Central', 'Asia', + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` + + // 'Y' or 'N', if 'Y', region will filled in with global settings + Autopopulate string `xml:"autopopulate,omitempty" json:"autopopulate,omitempty"` + + // number of addresses in each DNS response + Serve_count int32 `xml:"serve_count,omitempty" json:"serve_count,omitempty"` + + // pool_count, number of addresses to be included in the serve pool + Ep int32 `xml:"ep,omitempty" json:"ep,omitempty"` + + // 'ip', 'global', 'region', default 'global' + Failover_mode string `xml:"failover_mode,omitempty" json:"failover_mode,omitempty"` + + // for 'ip' mode, address to serve on failover. For 'region' mode, region_code of the region to failover to. + Failover_data string `xml:"failover_data,omitempty" json:"failover_data,omitempty"` + + // failover_count, number of addresses that must be 'ok', otherwise a region is considered 'failover' + Apmc int32 `xml:"apmc,omitempty" json:"apmc,omitempty"` + + // failover_count2, number of addresses that must be 'ok', otherwise a region is considered 'failover' + Epmc int32 `xml:"epmc,omitempty" json:"epmc,omitempty"` + + // pool of IP addresses to balance + Pool []*RTTMAddress `xml:"pool,omitempty" json:"pool,omitempty"` + + // 'ok, 'unk', 'trouble', 'failover', This field is returned in responses from the API, it should not be included in requests. + Status string `xml:"status,omitempty" json:"status,omitempty"` + + // monitoring changes task This field is returned in responses from the API, it should not be included in requests. + Task_id string `xml:"task_id,omitempty" json:"task_id,omitempty"` +} + +type RTTMAddress struct { + + // an IP address to monitor and publish + Address string `xml:"address,omitempty" json:"address,omitempty"` + + // a human-readable label + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // how often this is served relative to others in pool + Weight int32 `xml:"weight,omitempty" json:"weight,omitempty"` + + // how this address reponds to monitoring: obey,remove,always,no + Serve_mode string `xml:"serve_mode,omitempty" json:"serve_mode,omitempty"` + + // current monitoring status This field is returned in responses from the API, it should not be included in requests. + Status string `xml:"status,omitempty" json:"status,omitempty"` + + // Recent monitoring results for this address. This field is returned in responses from the API, it should not be included in requests. + Log []*MonitorLogData `xml:"log,omitempty" json:"log,omitempty"` +} + +type RTTMLogData struct { + + // zone serial at which this status was made + Serial string `xml:"serial,omitempty" json:"serial,omitempty"` + + // timestamp in UTC at which this status was made + Change_ts string `xml:"change_ts,omitempty" json:"change_ts,omitempty"` + + // type of status change. 'health', 'perf', or 'user' + Change_type string `xml:"change_type,omitempty" json:"change_type,omitempty"` + + // 'global' or specific region code: 'US West', 'US Central', 'US East', 'EU West', 'EU Central', 'Asia', + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` + + // 'up', 'trouble', 'failover', or 'reg_remove' + Region_status string `xml:"region_status,omitempty" json:"region_status,omitempty"` + + // If change_type is 'user', the user that made the change + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + // number of addresses in each DNS response + Serve_count string `xml:"serve_count,omitempty" json:"serve_count,omitempty"` + + // 'A', 'AAAA', or 'CNAME' + Rdata_type string `xml:"rdata_type,omitempty" json:"rdata_type,omitempty"` + + // List of rdata being served for this region + Region_rdata []*RTTMLogRData `xml:"region_rdata,omitempty" json:"region_rdata,omitempty"` +} + +type RTTMLogRData struct { + + // how often this is served relative to others in pool + Weight string `xml:"weight,omitempty" json:"weight,omitempty"` + + Rdata_a *RDataA `xml:"rdata_a,omitempty" json:"rdata_a,omitempty"` + + Rdata_aaaa *RDataAAAA `xml:"rdata_aaaa,omitempty" json:"rdata_aaaa,omitempty"` + + Rdata_cname *RDataCNAME `xml:"rdata_cname,omitempty" json:"rdata_cname,omitempty"` +} + +type RTTMRegionData struct { + + // 'global' or specific region code: 'US West', 'US Central', 'US East', 'EU West', 'EU Central', 'Asia', + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` + + // 'Y' or 'N', if 'Y', region will filled in with global settings + Autopopulate string `xml:"autopopulate,omitempty" json:"autopopulate,omitempty"` + + // number of addresses in each DNS response + Serve_count int32 `xml:"serve_count,omitempty" json:"serve_count,omitempty"` + + // pool_count, number of addresses to be included in the serve pool + Ep int32 `xml:"ep,omitempty" json:"ep,omitempty"` + + // 'ip', 'global', 'region', default 'global' + Failover_mode string `xml:"failover_mode,omitempty" json:"failover_mode,omitempty"` + + // for 'ip' mode, address to serve on failover. For 'region' mode, region_code of the region to failover to. + Failover_data string `xml:"failover_data,omitempty" json:"failover_data,omitempty"` + + // failover_count, number of addresses that must be 'ok', otherwise a region is considered 'failover' + Apmc int32 `xml:"apmc,omitempty" json:"apmc,omitempty"` + + // failover_count2, number of addresses that must be 'ok', otherwise a region is considered 'failover' + Epmc int32 `xml:"epmc,omitempty" json:"epmc,omitempty"` + + // pool of IP addresses to balance + Pool []*RTTMAddress `xml:"pool,omitempty" json:"pool,omitempty"` + + // monitoring changes task This field is returned in responses from the API, it should not be included in requests. + Task_id string `xml:"task_id,omitempty" json:"task_id,omitempty"` + + // 'ok, 'unk', 'trouble', 'failover', + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type RTTMRegionPoolEntry struct { + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // 'global' or specific region code: 'US West', 'US Central', 'US East', 'EU West', 'EU Central', 'Asia', + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` + + // an IP address to monitor and publish + Address string `xml:"address,omitempty" json:"address,omitempty"` + + // a human-readable label + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // how often this is served relative to others in pool + Weight int32 `xml:"weight,omitempty" json:"weight,omitempty"` + + // how this address reponds to monitoring: obey,remove,always,no + Serve_mode string `xml:"serve_mode,omitempty" json:"serve_mode,omitempty"` + + // current monitoring status This field is returned in responses from the API, it should not be included in requests. + Status string `xml:"status,omitempty" json:"status,omitempty"` + + // Recent monitoring results for this address. This field is returned in responses from the API, it should not be included in requests. + Log []*MonitorLogData `xml:"log,omitempty" json:"log,omitempty"` + + // monitoring changes task This field is returned in responses from the API, it should not be included in requests. + Task_id string `xml:"task_id,omitempty" json:"task_id,omitempty"` +} + +type HTTPRedirectData struct { + + // URL requests are redirecto to + Url string `xml:"url,omitempty" json:"url,omitempty"` + + // either '301' (temporary) or '302' (permanent) + Code string `xml:"code,omitempty" json:"code,omitempty"` + + // should redirected URL include requested URL + Keep_uri string `xml:"keep_uri,omitempty" json:"keep_uri,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type AdvRedirectRuleData struct { + + // Public ID of rule. + Public_id string `xml:"public_id,omitempty" json:"public_id,omitempty"` + + // either '301' (temporary) or '302' (permanent) + Code string `xml:"code,omitempty" json:"code,omitempty"` + + // host portion of URL to match + Host_prefix string `xml:"host_prefix,omitempty" json:"host_prefix,omitempty"` + + // path portion of URL to match + Path string `xml:"path,omitempty" json:"path,omitempty"` + + // replacement pattern + Url_pattern string `xml:"url_pattern,omitempty" json:"url_pattern,omitempty"` + + // 'Y'/'N', default 'Y' + Active string `xml:"active,omitempty" json:"active,omitempty"` + + // Public ID of next AdvRedirect rule to be processed. (default to end of list) + Next_public_id string `xml:"next_public_id,omitempty" json:"next_public_id,omitempty"` +} + +type AdvRedirectData struct { + + // 'Y'/'N', default 'Y' + Active string `xml:"active,omitempty" json:"active,omitempty"` + + // List of AdvRedirectRules + Rules []*AdvRedirectRuleData `xml:"rules,omitempty" json:"rules,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type RDataA struct { + Address string `xml:"address,omitempty" json:"address,omitempty"` +} + +type RDataAAAA struct { + Address string `xml:"address,omitempty" json:"address,omitempty"` +} + +type RDataALIAS struct { + Alias string `xml:"alias,omitempty" json:"alias,omitempty"` +} + +type RDataCAA struct { + Flags int32 `xml:"flags,omitempty" json:"flags,omitempty"` + + Tag string `xml:"tag,omitempty" json:"tag,omitempty"` + + Value string `xml:"value,omitempty" json:"value,omitempty"` +} + +type RDataCDNSKEY struct { + Flags int32 `xml:"flags,omitempty" json:"flags,omitempty"` + + Algorithm int32 `xml:"algorithm,omitempty" json:"algorithm,omitempty"` + + Protocol int32 `xml:"protocol,omitempty" json:"protocol,omitempty"` + + Public_key string `xml:"public_key,omitempty" json:"public_key,omitempty"` +} + +type RDataCDS struct { + Keytag int32 `xml:"keytag,omitempty" json:"keytag,omitempty"` + + Algorithm int32 `xml:"algorithm,omitempty" json:"algorithm,omitempty"` + + Digtype int32 `xml:"digtype,omitempty" json:"digtype,omitempty"` + + Digest string `xml:"digest,omitempty" json:"digest,omitempty"` +} + +type RDataCERT struct { + Format int32 `xml:"format,omitempty" json:"format,omitempty"` + + Tag int32 `xml:"tag,omitempty" json:"tag,omitempty"` + + Algorithm int32 `xml:"algorithm,omitempty" json:"algorithm,omitempty"` + + Certificate string `xml:"certificate,omitempty" json:"certificate,omitempty"` +} + +type RDataCNAME struct { + Cname string `xml:"cname,omitempty" json:"cname,omitempty"` +} + +type RDataCSYNC struct { + Soa_serial int32 `xml:"soa_serial,omitempty" json:"soa_serial,omitempty"` + + Flags string `xml:"flags,omitempty" json:"flags,omitempty"` + + Types string `xml:"types,omitempty" json:"types,omitempty"` +} + +type RDataDNSKEY struct { + Flags int32 `xml:"flags,omitempty" json:"flags,omitempty"` + + Algorithm int32 `xml:"algorithm,omitempty" json:"algorithm,omitempty"` + + Protocol int32 `xml:"protocol,omitempty" json:"protocol,omitempty"` + + Public_key string `xml:"public_key,omitempty" json:"public_key,omitempty"` +} + +type RDataDHCID struct { + Digest string `xml:"digest,omitempty" json:"digest,omitempty"` +} + +type RDataDNAME struct { + Dname string `xml:"dname,omitempty" json:"dname,omitempty"` +} + +type RDataDS struct { + Keytag int32 `xml:"keytag,omitempty" json:"keytag,omitempty"` + + Algorithm int32 `xml:"algorithm,omitempty" json:"algorithm,omitempty"` + + Digtype int32 `xml:"digtype,omitempty" json:"digtype,omitempty"` + + Digest string `xml:"digest,omitempty" json:"digest,omitempty"` +} + +type RDataIPSECKEY struct { + Precedence int32 `xml:"precedence,omitempty" json:"precedence,omitempty"` + + Gatetype int32 `xml:"gatetype,omitempty" json:"gatetype,omitempty"` + + Algorithm int32 `xml:"algorithm,omitempty" json:"algorithm,omitempty"` + + Gateway string `xml:"gateway,omitempty" json:"gateway,omitempty"` + + Public_key string `xml:"public_key,omitempty" json:"public_key,omitempty"` +} + +type RDataKEY struct { + Flags int32 `xml:"flags,omitempty" json:"flags,omitempty"` + + Algorithm int32 `xml:"algorithm,omitempty" json:"algorithm,omitempty"` + + Protocol int32 `xml:"protocol,omitempty" json:"protocol,omitempty"` + + Public_key string `xml:"public_key,omitempty" json:"public_key,omitempty"` +} + +type RDataKX struct { + Preference int32 `xml:"preference,omitempty" json:"preference,omitempty"` + + Exchange string `xml:"exchange,omitempty" json:"exchange,omitempty"` +} + +type RDataLOC struct { + Latitude string `xml:"latitude,omitempty" json:"latitude,omitempty"` + + Longitude string `xml:"longitude,omitempty" json:"longitude,omitempty"` + + Altitude int32 `xml:"altitude,omitempty" json:"altitude,omitempty"` + + Horiz_pre int32 `xml:"horiz_pre,omitempty" json:"horiz_pre,omitempty"` + + Vert_pre int32 `xml:"vert_pre,omitempty" json:"vert_pre,omitempty"` + + Size int32 `xml:"size,omitempty" json:"size,omitempty"` + + Version int32 `xml:"version,omitempty" json:"version,omitempty"` +} + +type RDataMX struct { + Preference int32 `xml:"preference,omitempty" json:"preference,omitempty"` + + Exchange string `xml:"exchange,omitempty" json:"exchange,omitempty"` +} + +type RDataNAPTR struct { + Order int32 `xml:"order,omitempty" json:"order,omitempty"` + + Preference int32 `xml:"preference,omitempty" json:"preference,omitempty"` + + Flags string `xml:"flags,omitempty" json:"flags,omitempty"` + + Services string `xml:"services,omitempty" json:"services,omitempty"` + + Regexp string `xml:"regexp,omitempty" json:"regexp,omitempty"` + + Replacement string `xml:"replacement,omitempty" json:"replacement,omitempty"` +} + +type RDataNS struct { + Nsdname string `xml:"nsdname,omitempty" json:"nsdname,omitempty"` +} + +type RDataNSAP struct { + Nsap string `xml:"nsap,omitempty" json:"nsap,omitempty"` +} + +type RDataPOLICY struct { + Name string `xml:"name,omitempty" json:"name,omitempty"` + + Rtype string `xml:"rtype,omitempty" json:"rtype,omitempty"` + + Api_url string `xml:"api_url,omitempty" json:"api_url,omitempty"` + + Gui_url string `xml:"gui_url,omitempty" json:"gui_url,omitempty"` + + Policy string `xml:"policy,omitempty" json:"policy,omitempty"` +} + +type RDataPTR struct { + Ptrdname string `xml:"ptrdname,omitempty" json:"ptrdname,omitempty"` +} + +type RDataPX struct { + Preference int32 `xml:"preference,omitempty" json:"preference,omitempty"` + + Map822 string `xml:"map822,omitempty" json:"map822,omitempty"` + + Mapx400 string `xml:"mapx400,omitempty" json:"mapx400,omitempty"` +} + +type RDataRP struct { + Mbox string `xml:"mbox,omitempty" json:"mbox,omitempty"` + + Txtdname string `xml:"txtdname,omitempty" json:"txtdname,omitempty"` +} + +type RDataSPF struct { + Txtdata string `xml:"txtdata,omitempty" json:"txtdata,omitempty"` +} + +type RDataSSHFP struct { + Algorithm int32 `xml:"algorithm,omitempty" json:"algorithm,omitempty"` + + Fptype int32 `xml:"fptype,omitempty" json:"fptype,omitempty"` + + Fingerprint string `xml:"fingerprint,omitempty" json:"fingerprint,omitempty"` +} + +type RDataSRV struct { + Priority int32 `xml:"priority,omitempty" json:"priority,omitempty"` + + Weight int32 `xml:"weight,omitempty" json:"weight,omitempty"` + + Port int32 `xml:"port,omitempty" json:"port,omitempty"` + + Target string `xml:"target,omitempty" json:"target,omitempty"` +} + +type RDataTLSA struct { + Cert_usage int32 `xml:"cert_usage,omitempty" json:"cert_usage,omitempty"` + + Selector int32 `xml:"selector,omitempty" json:"selector,omitempty"` + + Match_type int32 `xml:"match_type,omitempty" json:"match_type,omitempty"` + + Certificate string `xml:"certificate,omitempty" json:"certificate,omitempty"` +} + +type RDataTXT struct { + Txtdata string `xml:"txtdata,omitempty" json:"txtdata,omitempty"` +} + +type RDataSOA struct { + Mname string `xml:"mname,omitempty" json:"mname,omitempty"` + + Rname string `xml:"rname,omitempty" json:"rname,omitempty"` + + Serial int32 `xml:"serial,omitempty" json:"serial,omitempty"` + + Refresh int32 `xml:"refresh,omitempty" json:"refresh,omitempty"` + + Retry int32 `xml:"retry,omitempty" json:"retry,omitempty"` + + Expire int32 `xml:"expire,omitempty" json:"expire,omitempty"` + + Minimum int32 `xml:"minimum,omitempty" json:"minimum,omitempty"` +} + +type GenericRData struct { + Rdata_a *RDataA `xml:"rdata_a,omitempty" json:"rdata_a,omitempty"` + + Rdata_aaaa *RDataAAAA `xml:"rdata_aaaa,omitempty" json:"rdata_aaaa,omitempty"` + + Rdata_alias *RDataALIAS `xml:"rdata_alias,omitempty" json:"rdata_alias,omitempty"` + + Rdata_caa *RDataCAA `xml:"rdata_caa,omitempty" json:"rdata_caa,omitempty"` + + Rdata_cdnskey *RDataCDNSKEY `xml:"rdata_cdnskey,omitempty" json:"rdata_cdnskey,omitempty"` + + Rdata_cds *RDataCDS `xml:"rdata_cds,omitempty" json:"rdata_cds,omitempty"` + + Rdata_cert *RDataCERT `xml:"rdata_cert,omitempty" json:"rdata_cert,omitempty"` + + Rdata_cname *RDataCNAME `xml:"rdata_cname,omitempty" json:"rdata_cname,omitempty"` + + Rdata_csync *RDataCSYNC `xml:"rdata_csync,omitempty" json:"rdata_csync,omitempty"` + + Rdata_dhcid *RDataDHCID `xml:"rdata_dhcid,omitempty" json:"rdata_dhcid,omitempty"` + + Rdata_dname *RDataDNAME `xml:"rdata_dname,omitempty" json:"rdata_dname,omitempty"` + + Rdata_dnskey *RDataDNSKEY `xml:"rdata_dnskey,omitempty" json:"rdata_dnskey,omitempty"` + + Rdata_ds *RDataDS `xml:"rdata_ds,omitempty" json:"rdata_ds,omitempty"` + + Rdata_ipseckey *RDataIPSECKEY `xml:"rdata_ipseckey,omitempty" json:"rdata_ipseckey,omitempty"` + + Rdata_key *RDataKEY `xml:"rdata_key,omitempty" json:"rdata_key,omitempty"` + + Rdata_kx *RDataKX `xml:"rdata_kx,omitempty" json:"rdata_kx,omitempty"` + + Rdata_loc *RDataLOC `xml:"rdata_loc,omitempty" json:"rdata_loc,omitempty"` + + Rdata_mx *RDataMX `xml:"rdata_mx,omitempty" json:"rdata_mx,omitempty"` + + Rdata_naptr *RDataNAPTR `xml:"rdata_naptr,omitempty" json:"rdata_naptr,omitempty"` + + Rdata_ns *RDataNS `xml:"rdata_ns,omitempty" json:"rdata_ns,omitempty"` + + Rdata_nsap *RDataNSAP `xml:"rdata_nsap,omitempty" json:"rdata_nsap,omitempty"` + + Rdata_policy *RDataPOLICY `xml:"rdata_policy,omitempty" json:"rdata_policy,omitempty"` + + Rdata_ptr *RDataPTR `xml:"rdata_ptr,omitempty" json:"rdata_ptr,omitempty"` + + Rdata_px *RDataPX `xml:"rdata_px,omitempty" json:"rdata_px,omitempty"` + + Rdata_rp *RDataRP `xml:"rdata_rp,omitempty" json:"rdata_rp,omitempty"` + + Rdata_spf *RDataSPF `xml:"rdata_spf,omitempty" json:"rdata_spf,omitempty"` + + Rdata_sshfp *RDataSSHFP `xml:"rdata_sshfp,omitempty" json:"rdata_sshfp,omitempty"` + + Rdata_srv *RDataSRV `xml:"rdata_srv,omitempty" json:"rdata_srv,omitempty"` + + Rdata_tlsa *RDataTLSA `xml:"rdata_tlsa,omitempty" json:"rdata_tlsa,omitempty"` + + Rdata_txt *RDataTXT `xml:"rdata_txt,omitempty" json:"rdata_txt,omitempty"` + + Rdata_soa *RDataSOA `xml:"rdata_soa,omitempty" json:"rdata_soa,omitempty"` +} + +type QNames struct { + Names []string `xml:"names,omitempty" json:"names,omitempty"` +} + +type ANYRecordData struct { + A_records []*ARecordData `xml:"a_records,omitempty" json:"a_records,omitempty"` + + Aaaa_records []*AAAARecordData `xml:"aaaa_records,omitempty" json:"aaaa_records,omitempty"` + + Alias_records []*ALIASRecordData `xml:"alias_records,omitempty" json:"alias_records,omitempty"` + + Caa_records []*CAARecordData `xml:"caa_records,omitempty" json:"caa_records,omitempty"` + + Cdnskey_records []*CDNSKEYRecordData `xml:"cdnskey_records,omitempty" json:"cdnskey_records,omitempty"` + + Cds_records []*CDSRecordData `xml:"cds_records,omitempty" json:"cds_records,omitempty"` + + Cert_records []*CERTRecordData `xml:"cert_records,omitempty" json:"cert_records,omitempty"` + + Cname_records []*CNAMERecordData `xml:"cname_records,omitempty" json:"cname_records,omitempty"` + + Csync_records []*CSYNCRecordData `xml:"csync_records,omitempty" json:"csync_records,omitempty"` + + Dhcid_records []*DHCIDRecordData `xml:"dhcid_records,omitempty" json:"dhcid_records,omitempty"` + + Dname_records []*DNAMERecordData `xml:"dname_records,omitempty" json:"dname_records,omitempty"` + + Dnskey_records []*DNSKEYRecordData `xml:"dnskey_records,omitempty" json:"dnskey_records,omitempty"` + + Ds_records []*DSRecordData `xml:"ds_records,omitempty" json:"ds_records,omitempty"` + + Ipseckey_records []*IPSECKEYRecordData `xml:"ipseckey_records,omitempty" json:"ipseckey_records,omitempty"` + + Key_records []*KEYRecordData `xml:"key_records,omitempty" json:"key_records,omitempty"` + + Kx_records []*KXRecordData `xml:"kx_records,omitempty" json:"kx_records,omitempty"` + + Loc_records []*LOCRecordData `xml:"loc_records,omitempty" json:"loc_records,omitempty"` + + Mx_records []*MXRecordData `xml:"mx_records,omitempty" json:"mx_records,omitempty"` + + Naptr_records []*NAPTRRecordData `xml:"naptr_records,omitempty" json:"naptr_records,omitempty"` + + Nsap_records []*NSAPRecordData `xml:"nsap_records,omitempty" json:"nsap_records,omitempty"` + + Policy_records []*POLICYRecordData `xml:"policy_records,omitempty" json:"policy_records,omitempty"` + + Ptr_records []*PTRRecordData `xml:"ptr_records,omitempty" json:"ptr_records,omitempty"` + + Px_records []*PXRecordData `xml:"px_records,omitempty" json:"px_records,omitempty"` + + Rp_records []*RPRecordData `xml:"rp_records,omitempty" json:"rp_records,omitempty"` + + Spf_records []*SPFRecordData `xml:"spf_records,omitempty" json:"spf_records,omitempty"` + + Srv_records []*SRVRecordData `xml:"srv_records,omitempty" json:"srv_records,omitempty"` + + Sshfp_records []*SSHFPRecordData `xml:"sshfp_records,omitempty" json:"sshfp_records,omitempty"` + + Tlsa_records []*TLSARecordData `xml:"tlsa_records,omitempty" json:"tlsa_records,omitempty"` + + Txt_records []*TXTRecordData `xml:"txt_records,omitempty" json:"txt_records,omitempty"` + + Soa_records []*SOARecordData `xml:"soa_records,omitempty" json:"soa_records,omitempty"` + + Ns_records []*NSRecordData `xml:"ns_records,omitempty" json:"ns_records,omitempty"` +} + +type ANYRData struct { + A_rdata []*RDataA `xml:"a_rdata,omitempty" json:"a_rdata,omitempty"` + + Aaaa_rdata []*RDataAAAA `xml:"aaaa_rdata,omitempty" json:"aaaa_rdata,omitempty"` + + Alias_rdata []*RDataALIAS `xml:"alias_rdata,omitempty" json:"alias_rdata,omitempty"` + + Caa_rdata []*RDataCAA `xml:"caa_rdata,omitempty" json:"caa_rdata,omitempty"` + + Cdnskey_rdata []*RDataCDNSKEY `xml:"cdnskey_rdata,omitempty" json:"cdnskey_rdata,omitempty"` + + Cds_rdata []*RDataCDS `xml:"cds_rdata,omitempty" json:"cds_rdata,omitempty"` + + Cert_rdata []*RDataCERT `xml:"cert_rdata,omitempty" json:"cert_rdata,omitempty"` + + Cname_rdata []*RDataCNAME `xml:"cname_rdata,omitempty" json:"cname_rdata,omitempty"` + + Csync_rdata []*RDataCSYNC `xml:"csync_rdata,omitempty" json:"csync_rdata,omitempty"` + + Dhcid_rdata []*RDataDHCID `xml:"dhcid_rdata,omitempty" json:"dhcid_rdata,omitempty"` + + Dname_rdata []*RDataDNAME `xml:"dname_rdata,omitempty" json:"dname_rdata,omitempty"` + + Dnskey_rdata []*RDataDNSKEY `xml:"dnskey_rdata,omitempty" json:"dnskey_rdata,omitempty"` + + Ds_rdata []*RDataDS `xml:"ds_rdata,omitempty" json:"ds_rdata,omitempty"` + + Ipseckey_rdata []*RDataIPSECKEY `xml:"ipseckey_rdata,omitempty" json:"ipseckey_rdata,omitempty"` + + Key_rdata []*RDataKEY `xml:"key_rdata,omitempty" json:"key_rdata,omitempty"` + + Kx_rdata []*RDataKX `xml:"kx_rdata,omitempty" json:"kx_rdata,omitempty"` + + Loc_rdata []*RDataLOC `xml:"loc_rdata,omitempty" json:"loc_rdata,omitempty"` + + Mx_rdata []*RDataMX `xml:"mx_rdata,omitempty" json:"mx_rdata,omitempty"` + + Naptr_rdata []*RDataNAPTR `xml:"naptr_rdata,omitempty" json:"naptr_rdata,omitempty"` + + Nsap_rdata []*RDataNSAP `xml:"nsap_rdata,omitempty" json:"nsap_rdata,omitempty"` + + Policy_rdata []*RDataPOLICY `xml:"policy_rdata,omitempty" json:"policy_rdata,omitempty"` + + Ptr_rdata []*RDataPTR `xml:"ptr_rdata,omitempty" json:"ptr_rdata,omitempty"` + + Px_rdata []*RDataPX `xml:"px_rdata,omitempty" json:"px_rdata,omitempty"` + + Rp_rdata []*RDataRP `xml:"rp_rdata,omitempty" json:"rp_rdata,omitempty"` + + Spf_rdata []*RDataSPF `xml:"spf_rdata,omitempty" json:"spf_rdata,omitempty"` + + Srv_rdata []*RDataSRV `xml:"srv_rdata,omitempty" json:"srv_rdata,omitempty"` + + Sshfp_rdata []*RDataSSHFP `xml:"sshfp_rdata,omitempty" json:"sshfp_rdata,omitempty"` + + Tlsa_rdata []*RDataTLSA `xml:"tlsa_rdata,omitempty" json:"tlsa_rdata,omitempty"` + + Txt_rdata []*RDataTXT `xml:"txt_rdata,omitempty" json:"txt_rdata,omitempty"` + + Soa_rdata []*RDataSOA `xml:"soa_rdata,omitempty" json:"soa_rdata,omitempty"` + + Ns_rdata []*RDataNS `xml:"ns_rdata,omitempty" json:"ns_rdata,omitempty"` +} + +type ANYOneRData struct { + A_rdata *RDataA `xml:"a_rdata,omitempty" json:"a_rdata,omitempty"` + + Aaaa_rdata *RDataAAAA `xml:"aaaa_rdata,omitempty" json:"aaaa_rdata,omitempty"` + + Alias_rdata *RDataALIAS `xml:"alias_rdata,omitempty" json:"alias_rdata,omitempty"` + + Caa_rdata *RDataCAA `xml:"caa_rdata,omitempty" json:"caa_rdata,omitempty"` + + Cdnskey_rdata *RDataCDNSKEY `xml:"cdnskey_rdata,omitempty" json:"cdnskey_rdata,omitempty"` + + Cds_rdata *RDataCDS `xml:"cds_rdata,omitempty" json:"cds_rdata,omitempty"` + + Cert_rdata *RDataCERT `xml:"cert_rdata,omitempty" json:"cert_rdata,omitempty"` + + Cname_rdata *RDataCNAME `xml:"cname_rdata,omitempty" json:"cname_rdata,omitempty"` + + Csync_rdata *RDataCSYNC `xml:"csync_rdata,omitempty" json:"csync_rdata,omitempty"` + + Dhcid_rdata *RDataDHCID `xml:"dhcid_rdata,omitempty" json:"dhcid_rdata,omitempty"` + + Dname_rdata *RDataDNAME `xml:"dname_rdata,omitempty" json:"dname_rdata,omitempty"` + + Dnskey_rdata *RDataDNSKEY `xml:"dnskey_rdata,omitempty" json:"dnskey_rdata,omitempty"` + + Ds_rdata *RDataDS `xml:"ds_rdata,omitempty" json:"ds_rdata,omitempty"` + + Ipseckey_rdata *RDataIPSECKEY `xml:"ipseckey_rdata,omitempty" json:"ipseckey_rdata,omitempty"` + + Key_rdata *RDataKEY `xml:"key_rdata,omitempty" json:"key_rdata,omitempty"` + + Kx_rdata *RDataKX `xml:"kx_rdata,omitempty" json:"kx_rdata,omitempty"` + + Loc_rdata *RDataLOC `xml:"loc_rdata,omitempty" json:"loc_rdata,omitempty"` + + Mx_rdata *RDataMX `xml:"mx_rdata,omitempty" json:"mx_rdata,omitempty"` + + Naptr_rdata *RDataNAPTR `xml:"naptr_rdata,omitempty" json:"naptr_rdata,omitempty"` + + Nsap_rdata *RDataNSAP `xml:"nsap_rdata,omitempty" json:"nsap_rdata,omitempty"` + + Policy_rdata *RDataPOLICY `xml:"policy_rdata,omitempty" json:"policy_rdata,omitempty"` + + Ptr_rdata *RDataPTR `xml:"ptr_rdata,omitempty" json:"ptr_rdata,omitempty"` + + Px_rdata *RDataPX `xml:"px_rdata,omitempty" json:"px_rdata,omitempty"` + + Rp_rdata *RDataRP `xml:"rp_rdata,omitempty" json:"rp_rdata,omitempty"` + + Spf_rdata *RDataSPF `xml:"spf_rdata,omitempty" json:"spf_rdata,omitempty"` + + Srv_rdata *RDataSRV `xml:"srv_rdata,omitempty" json:"srv_rdata,omitempty"` + + Sshfp_rdata *RDataSSHFP `xml:"sshfp_rdata,omitempty" json:"sshfp_rdata,omitempty"` + + Tlsa_rdata *RDataTLSA `xml:"tlsa_rdata,omitempty" json:"tlsa_rdata,omitempty"` + + Txt_rdata *RDataTXT `xml:"txt_rdata,omitempty" json:"txt_rdata,omitempty"` + + Soa_rdata *RDataSOA `xml:"soa_rdata,omitempty" json:"soa_rdata,omitempty"` + + Ns_rdata *RDataNS `xml:"ns_rdata,omitempty" json:"ns_rdata,omitempty"` +} + +type ZoneChangeData struct { + Id int64 `xml:"id,omitempty" json:"id,omitempty"` + + User_id int64 `xml:"user_id,omitempty" json:"user_id,omitempty"` + + Rdata_type string `xml:"rdata_type,omitempty" json:"rdata_type,omitempty"` + + Rdata *GenericRData `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Serial int32 `xml:"serial,omitempty" json:"serial,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type ZoneNoteData struct { + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + Serial int32 `xml:"serial,omitempty" json:"serial,omitempty"` + + Type_ string `xml:"type,omitempty" json:"type,omitempty"` + + Note string `xml:"note,omitempty" json:"note,omitempty"` + + Timestamp string `xml:"timestamp,omitempty" json:"timestamp,omitempty"` +} + +type ZoneTransferStatus struct { + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Master_ip string `xml:"master_ip,omitempty" json:"master_ip,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Message string `xml:"message,omitempty" json:"message,omitempty"` +} + +type ZoneConfigOptionData struct { + Name string `xml:"name,omitempty" json:"name,omitempty"` + + Value string `xml:"value,omitempty" json:"value,omitempty"` + + Target string `xml:"target,omitempty" json:"target,omitempty"` +} + +type PublishZoneData struct { + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Serial int32 `xml:"serial,omitempty" json:"serial,omitempty"` + + Serial_style string `xml:"serial_style,omitempty" json:"serial_style,omitempty"` + + Zone_type string `xml:"zone_type,omitempty" json:"zone_type,omitempty"` + + Task_id string `xml:"task_id,omitempty" json:"task_id,omitempty"` +} + +type IPTrackData struct { + + // A, Dynamic_A, AAAA, Dynamic_AAAA + Record_types []string `xml:"record_types,omitempty" json:"record_types,omitempty"` + + // List of hostnames to watch for records + Hosts []string `xml:"hosts,omitempty" json:"hosts,omitempty"` + + // 'match', 'default', or a valid ttl + Ttl string `xml:"ttl,omitempty" json:"ttl,omitempty"` + + // Mask that records should match + Netmask string `xml:"netmask,omitempty" json:"netmask,omitempty"` + + Iptrack_id int64 `xml:"iptrack_id,omitempty" json:"iptrack_id,omitempty"` + + Active string `xml:"active,omitempty" json:"active,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DNSSECData struct { + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // , contact that gets key notifications + Contact_nickname string `xml:"contact_nickname,omitempty" json:"contact_nickname,omitempty"` + + // when notifications are sent + Notify_events string `xml:"notify_events,omitempty" json:"notify_events,omitempty"` + + Keys []*DNSSECKey `xml:"keys,omitempty" json:"keys,omitempty"` + + Active string `xml:"active,omitempty" json:"active,omitempty"` +} + +type DNSSECKey struct { + + // 'KSK' or 'ZSK' + Type_ string `xml:"type,omitempty" json:"type,omitempty"` + + // 'RSA/SHA-1', 'RSA/SHA-256', 'RSA/SHA-512', 'DSA' + Algorithm string `xml:"algorithm,omitempty" json:"algorithm,omitempty"` + + Bits string `xml:"bits,omitempty" json:"bits,omitempty"` + + Start_ts int32 `xml:"start_ts,omitempty" json:"start_ts,omitempty"` + + Lifetime int32 `xml:"lifetime,omitempty" json:"lifetime,omitempty"` + + Overlap int32 `xml:"overlap,omitempty" json:"overlap,omitempty"` + + Expire_ts int32 `xml:"expire_ts,omitempty" json:"expire_ts,omitempty"` + + // Only for updates: 'rollover', 'rollover_now', 'remove' + Action string `xml:"action,omitempty" json:"action,omitempty"` + + Dnssec_key_id int64 `xml:"dnssec_key_id,omitempty" json:"dnssec_key_id,omitempty"` + + // This field is returned in responses from the API, it should not be included in requests. + Dnskey *RDataDNSKEY `xml:"dnskey,omitempty" json:"dnskey,omitempty"` + + // preserved for compatibility This field is returned in responses from the API, it should not be included in requests. + Ds *RDataDS `xml:"ds,omitempty" json:"ds,omitempty"` + + All_ds []*RDataDS `xml:"all_ds,omitempty" json:"all_ds,omitempty"` +} + +type DNSSECTimelineEvent struct { + Scheduled_ts int32 `xml:"scheduled_ts,omitempty" json:"scheduled_ts,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Event string `xml:"event,omitempty" json:"event,omitempty"` + + Message string `xml:"message,omitempty" json:"message,omitempty"` + + Send_notify string `xml:"send_notify,omitempty" json:"send_notify,omitempty"` + + User string `xml:"user,omitempty" json:"user,omitempty"` + + Dnssec_key_id int64 `xml:"dnssec_key_id,omitempty" json:"dnssec_key_id,omitempty"` +} + +type TaskArgData struct { + Name string `xml:"name,omitempty" json:"name,omitempty"` + + Value string `xml:"value,omitempty" json:"value,omitempty"` +} + +type TaskIDData struct { + Task_id string `xml:"task_id,omitempty" json:"task_id,omitempty"` +} + +type TaskData struct { + Task_id string `xml:"task_id,omitempty" json:"task_id,omitempty"` + + // identifies the task operation + Name string `xml:"name,omitempty" json:"name,omitempty"` + + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` + + Zone_name string `xml:"zone_name,omitempty" json:"zone_name,omitempty"` + + // ready running waiting complete failed canceled stalled + Status string `xml:"status,omitempty" json:"status,omitempty"` + + // in a multi-step process, how far along + Step_count int32 `xml:"step_count,omitempty" json:"step_count,omitempty"` + + // total number of steps in multi-step process + Total_steps int32 `xml:"total_steps,omitempty" json:"total_steps,omitempty"` + + // Y/N - does this task block further zone operations? + Blocking string `xml:"blocking,omitempty" json:"blocking,omitempty"` + + Message string `xml:"message,omitempty" json:"message,omitempty"` + + Debug string `xml:"debug,omitempty" json:"debug,omitempty"` + + Created_ts int64 `xml:"created_ts,omitempty" json:"created_ts,omitempty"` + + Modified_ts int64 `xml:"modified_ts,omitempty" json:"modified_ts,omitempty"` + + // other arguments passed to the task + Args []*TaskArgData `xml:"args,omitempty" json:"args,omitempty"` +} + +type ExtNameserverData struct { + + // can be empty or 'default' + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // Y/N - does this block requests or add them + Deny string `xml:"deny,omitempty" json:"deny,omitempty"` + + Hosts []*ExtNSEntry `xml:"hosts,omitempty" json:"hosts,omitempty"` + + Tsig_key_name string `xml:"tsig_key_name,omitempty" json:"tsig_key_name,omitempty"` + + Active string `xml:"active,omitempty" json:"active,omitempty"` +} + +type ExtNSEntry struct { + + // address or CIDR + Address string `xml:"address,omitempty" json:"address,omitempty"` + + // Y/N - do we send NOTIFYs to this host? + Notifies string `xml:"notifies,omitempty" json:"notifies,omitempty"` + + // Y/N - do we accept [AI]XFRs from this host? + Transfers string `xml:"transfers,omitempty" json:"transfers,omitempty"` +} + +type ErrorResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ErrorResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + // should be empty and can be ignored + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetJobRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetJobRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` +} + +type GetJobResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetJobResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + // Contains the response data. Can be any type as GetJob is request-agnostic. + Data interface{} `xml:"data,omitempty" json:"data,omitempty"` +} + +type SessionLoginRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SessionLoginRequest"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` + + Password string `xml:"password,omitempty" json:"password,omitempty"` +} + +type SessionLoginResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SessionLoginResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + // identifies your session token (needed for all other Dynect API calls) and the API protocol version + Data *SessionLoginData `xml:"data,omitempty" json:"data,omitempty"` +} + +type SessionLogoutRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SessionLogoutRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` +} + +type SessionLogoutResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SessionLogoutResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type SessionIsAliveRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SessionIsAliveRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` +} + +type SessionIsAliveResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SessionIsAliveResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type SessionKeepAliveRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SessionKeepAliveRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` +} + +type SessionKeepAliveResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SessionKeepAliveResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type ScopeInRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ScopeInRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` + + // defaults to admin user + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` +} + +type ScopeInResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ScopeInResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type ScopeAsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ScopeAsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` + + // defaults to admin user + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` +} + +type ScopeAsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ScopeAsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type UnscopeRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UnscopeRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` +} + +type UnscopeResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UnscopeResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetQueryStatsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetQueryStatsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // The timestamp indicating the beginning of the period to report on + Start_ts int32 `xml:"start_ts,omitempty" json:"start_ts,omitempty"` + + // The timestamp indicating the end of the period to report on + End_ts int32 `xml:"end_ts,omitempty" json:"end_ts,omitempty"` + + // The fields to break down the data with + Breakdown []string `xml:"breakdown,omitempty" json:"breakdown,omitempty"` + + // A list of specific hostnames to report on. A hostname beginning with '!' will cause that hostname to be excluded + Hosts []string `xml:"hosts,omitempty" json:"hosts,omitempty"` + + // A list of specific nameservers to report on. A nameserver beginning with '!' will cause that nameserver to be excluded + Nameservers []string `xml:"nameservers,omitempty" json:"nameservers,omitempty"` + + // A list of record types to report on. A record type beginning with '!' will cause that record type to be excluded + Rrecs []string `xml:"rrecs,omitempty" json:"rrecs,omitempty"` + + // A list of zone names to report on. A zone name beginning with '!' will cause that zone to be excluded. + Zones []string `xml:"zones,omitempty" json:"zones,omitempty"` +} + +type GetQueryStatsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetQueryStatsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + // The CSV data containing the requested statistics + Data *QueryStatsData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateGeoRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateGeoRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Name of the service we want to create + Name string `xml:"name,omitempty" json:"name,omitempty"` + + // List of region groups that contain a list of countries and records to be served + Groups []*GeoRegionGroup `xml:"groups,omitempty" json:"groups,omitempty"` + + // List of zone name, node name pairs to link a node to the Geo Service + Nodes []*GeoNode `xml:"nodes,omitempty" json:"nodes,omitempty"` + + // Default TTL for records + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type CreateGeoResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateGeoResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *Geo `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateGeoRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateGeoRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Name of the Geo Service to update + Name string `xml:"name,omitempty" json:"name,omitempty"` + + // The new name to assign to the Geo Service + New_name string `xml:"new_name,omitempty" json:"new_name,omitempty"` + + // List of region groups that contain a list of countries and records to be served + Groups []*GeoRegionGroup `xml:"groups,omitempty" json:"groups,omitempty"` + + // List of zone name, node name pairs to link a node to the Geo Service + Nodes []*GeoNode `xml:"nodes,omitempty" json:"nodes,omitempty"` + + // Default TTL for records + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateGeoResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateGeoResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *Geo `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetGeosRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetGeosRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Name (partial) of the Geo Service to find + Name string `xml:"name,omitempty" json:"name,omitempty"` + + // Name (partial) of the Geo Region Group to find + Group_name string `xml:"group_name,omitempty" json:"group_name,omitempty"` +} + +type GetGeosResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetGeosResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*Geo `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneGeoRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneGeoRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Name (partial) of the Geo Service to find + Name string `xml:"name,omitempty" json:"name,omitempty"` +} + +type GetOneGeoResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneGeoResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *Geo `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneGeoRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneGeoRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Name of the Geo Service to delete + Name string `xml:"name,omitempty" json:"name,omitempty"` +} + +type DeleteOneGeoResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneGeoResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type ActivateGeoRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ActivateGeoRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Name of the Geo Service to activate + Name string `xml:"name,omitempty" json:"name,omitempty"` +} + +type ActivateGeoResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ActivateGeoResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *Geo `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeactivateGeoRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeactivateGeoRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Name of the Geo Service to deactivate + Name string `xml:"name,omitempty" json:"name,omitempty"` +} + +type DeactivateGeoResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeactivateGeoResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *Geo `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateGeoRegionGroupRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateGeoRegionGroupRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Name of the Geo Service to update + Service_name string `xml:"service_name,omitempty" json:"service_name,omitempty"` + + // , Name of the Region Group + Name string `xml:"name,omitempty" json:"name,omitempty"` + + // Rdata to update the Region Group with + Rdata *ANYRData `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // List of countries to update the Region Group with + Countries []string `xml:"countries,omitempty" json:"countries,omitempty"` + + // Optional weights to accompany the rdata + Weight *WeightData `xml:"weight,omitempty" json:"weight,omitempty"` + + // Optional serve counts to accompany the rdata + Serve_count *ServeCountData `xml:"serve_count,omitempty" json:"serve_count,omitempty"` + + // Optional Default TTL values for each record + Ttl *TTLData `xml:"ttl,omitempty" json:"ttl,omitempty"` + + // Optional labels for the rdata + Label *LabelData `xml:"label,omitempty" json:"label,omitempty"` +} + +type CreateGeoRegionGroupResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateGeoRegionGroupResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *Geo `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateGeoRegionGroupRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateGeoRegionGroupRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Name of the Geo Service to update + Service_name string `xml:"service_name,omitempty" json:"service_name,omitempty"` + + // , Name of the Region Group + Name string `xml:"name,omitempty" json:"name,omitempty"` + + // Rdata to update the Region Group with + Rdata *ANYRData `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // List of countries to update the Region Group with + Countries []string `xml:"countries,omitempty" json:"countries,omitempty"` + + // Optional weights to accompany the rdata + Weight *WeightData `xml:"weight,omitempty" json:"weight,omitempty"` + + // Optional serve counts to accompany the rdata + Serve_count *ServeCountData `xml:"serve_count,omitempty" json:"serve_count,omitempty"` + + // Optional Default TTL values for each record + Ttl *TTLData `xml:"ttl,omitempty" json:"ttl,omitempty"` + + // Optional labels for the rdata + Label *LabelData `xml:"label,omitempty" json:"label,omitempty"` +} + +type UpdateGeoRegionGroupResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateGeoRegionGroupResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *Geo `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneGeoRegionGroupRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneGeoRegionGroupRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Name of the Geo Service to update + Service_name string `xml:"service_name,omitempty" json:"service_name,omitempty"` + + // , Name of the Region Group + Name string `xml:"name,omitempty" json:"name,omitempty"` +} + +type DeleteOneGeoRegionGroupResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneGeoRegionGroupResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetGeoRegionGroupsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetGeoRegionGroupsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Name of the Geo Service to update + Service_name string `xml:"service_name,omitempty" json:"service_name,omitempty"` +} + +type GetGeoRegionGroupsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetGeoRegionGroupsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*GeoRegionGroupData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneGeoRegionGroupRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneGeoRegionGroupRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Name of the Geo Service to update + Service_name string `xml:"service_name,omitempty" json:"service_name,omitempty"` + + // , Name of the Region Group + Name string `xml:"name,omitempty" json:"name,omitempty"` +} + +type GetOneGeoRegionGroupResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneGeoRegionGroupResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *GeoRegionGroupData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateGeoNodeRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateGeoNodeRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Name of the Geo Service to add the nodes to + Service_name string `xml:"service_name,omitempty" json:"service_name,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type CreateGeoNodeResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateGeoNodeResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *Geo `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneGeoNodeRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneGeoNodeRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Name of the Geo Service to delete the nodes from + Service_name string `xml:"service_name,omitempty" json:"service_name,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteOneGeoNodeResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneGeoNodeResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetGeoNodesRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetGeoNodesRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Name of the Geo Service + Service_name string `xml:"service_name,omitempty" json:"service_name,omitempty"` +} + +type GetGeoNodesResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetGeoNodesResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateDSFRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDSFRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // DSF Label + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // Default TTL to be used in this service + Ttl string `xml:"ttl,omitempty" json:"ttl,omitempty"` + + // A list of fqdn,zone pairs to identify nodes to attach + Nodes []*DSFNode `xml:"nodes,omitempty" json:"nodes,omitempty"` + + // A list of DSF Rulesets defined for the service + Rulesets []*DSFRuleset `xml:"rulesets,omitempty" json:"rulesets,omitempty"` + + // A list of notifier links + Notifiers []*NotifierLink `xml:"notifiers,omitempty" json:"notifiers,omitempty"` + + // If 'Y', service will be published on creation + Publish string `xml:"publish,omitempty" json:"publish,omitempty"` + + // Optional Publish Notes. + Notes string `xml:"notes,omitempty" json:"notes,omitempty"` +} + +type CreateDSFResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDSFResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateDSFRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDSFRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID or label of the DSF service to update + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // A new label for the service + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // Default TTL to be used + Ttl string `xml:"ttl,omitempty" json:"ttl,omitempty"` + + // A list of fqdn,zone pairs to identify nodes to attach + Nodes []*DSFNode `xml:"nodes,omitempty" json:"nodes,omitempty"` + + Rulesets []*DSFRuleset `xml:"rulesets,omitempty" json:"rulesets,omitempty"` + + // A list of notifier links + Notifiers []*NotifierLink `xml:"notifiers,omitempty" json:"notifiers,omitempty"` + + // If true, the service is immediately published + Publish string `xml:"publish,omitempty" json:"publish,omitempty"` + + // Optional Publish Notes. + Notes string `xml:"notes,omitempty" json:"notes,omitempty"` +} + +type UpdateDSFResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDSFResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetDSFsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDSFsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // label, ID, or wildcard + Cust string `xml:"cust,omitempty" json:"cust,omitempty"` + + // label or ID + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // wildcard + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // linker + Linker string `xml:"linker,omitempty" json:"linker,omitempty"` + + // response will include pending changes + Pending_changes string `xml:"pending_changes,omitempty" json:"pending_changes,omitempty"` +} + +type GetDSFsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDSFsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*DSFData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetDSFNotifiersRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDSFNotifiersRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Identifier for DSF service to search on + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` +} + +type GetDSFNotifiersResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDSFNotifiersResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*NotifierDataAlt `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneDSFRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDSFRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID or label of the DSF service to delete + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` +} + +type DeleteOneDSFResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDSFResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneDSFRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDSFRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // label or ID + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // response will include pending changes + Pending_changes string `xml:"pending_changes,omitempty" json:"pending_changes,omitempty"` +} + +type GetOneDSFResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDSFResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFData `xml:"data,omitempty" json:"data,omitempty"` +} + +type RevertDSFRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RevertDSFRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // label or ID + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` +} + +type RevertDSFResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RevertDSFResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFData `xml:"data,omitempty" json:"data,omitempty"` +} + +type PublishDSFRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ PublishDSFRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // label or ID + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // Optional notes + Notes string `xml:"notes,omitempty" json:"notes,omitempty"` +} + +type PublishDSFResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ PublishDSFResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFData `xml:"data,omitempty" json:"data,omitempty"` +} + +type AddDSFNotifierRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddDSFNotifierRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Identifier for DSF service to search on + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // Public_id of the Notifier to link to + Notifier_id string `xml:"notifier_id,omitempty" json:"notifier_id,omitempty"` + + // filters on when services should fire the notifier + Filters []string `xml:"filters,omitempty" json:"filters,omitempty"` + + Publish string `xml:"publish,omitempty" json:"publish,omitempty"` + + // Optional notes + Notes string `xml:"notes,omitempty" json:"notes,omitempty"` +} + +type AddDSFNotifierResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddDSFNotifierResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *NotifierLinkData `xml:"data,omitempty" json:"data,omitempty"` +} + +type RemoveDSFNotifierRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RemoveDSFNotifierRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Identifier for DSF service to search on + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // Public_id of the Notifier to link to + Link_id string `xml:"link_id,omitempty" json:"link_id,omitempty"` + + Publish string `xml:"publish,omitempty" json:"publish,omitempty"` + + // Optional notes + Notes string `xml:"notes,omitempty" json:"notes,omitempty"` +} + +type RemoveDSFNotifierResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RemoveDSFNotifierResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *NotifierLinkData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateDSFRulesetRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDSFRulesetRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID or label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // Ruleset label + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // The type of criteria contained within this Pool + Criteria_type string `xml:"criteria_type,omitempty" json:"criteria_type,omitempty"` + + // Required based on criteria_type. Filtered in API/BLL + Criteria *DSFCriteria `xml:"criteria,omitempty" json:"criteria,omitempty"` + + // Where in the chain does the ruleset land. Defautls to the last. + Ordering string `xml:"ordering,omitempty" json:"ordering,omitempty"` + + // A list of DSF Reponse Pools that comprise the Ruleset + Response_pools []*DSFResponsePool `xml:"response_pools,omitempty" json:"response_pools,omitempty"` + + // boolean - immediately save change and publish + Publish string `xml:"publish,omitempty" json:"publish,omitempty"` + + // Optional notes + Notes string `xml:"notes,omitempty" json:"notes,omitempty"` +} + +type CreateDSFRulesetResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDSFRulesetResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFRulesetData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateDSFRulesetRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDSFRulesetRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID or label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // ID of the ruleset to update + Dsf_ruleset_id string `xml:"dsf_ruleset_id,omitempty" json:"dsf_ruleset_id,omitempty"` + + // Ruleset label + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // The type of criteria contained within this Pool + Criteria_type string `xml:"criteria_type,omitempty" json:"criteria_type,omitempty"` + + // Required based on criteria_type. Filtered in API/BLL + Criteria *DSFCriteria `xml:"criteria,omitempty" json:"criteria,omitempty"` + + // Where in the chain does the ruleset land. Defautls to the last. + Ordering string `xml:"ordering,omitempty" json:"ordering,omitempty"` + + // A list of DSF Reponse Pools that comprise the Ruleset + Response_pools []*DSFResponsePool `xml:"response_pools,omitempty" json:"response_pools,omitempty"` + + // boolean - immediately save change and publish + Publish string `xml:"publish,omitempty" json:"publish,omitempty"` + + // Optional Publish Notes. + Notes string `xml:"notes,omitempty" json:"notes,omitempty"` +} + +type UpdateDSFRulesetResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDSFRulesetResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFRulesetData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetDSFRulesetsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDSFRulesetsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID or label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // Ruleset label to search on. Can be wildcarded + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // Can be wildcarded...must be string representation + Criteria string `xml:"criteria,omitempty" json:"criteria,omitempty"` + + // The type of criteria contained within this Pool + Criteria_type string `xml:"criteria_type,omitempty" json:"criteria_type,omitempty"` + + // Where in the chain does the ruleset land. Defautls to the last. + Ordering string `xml:"ordering,omitempty" json:"ordering,omitempty"` + + // response will include pending changes + Pending_changes string `xml:"pending_changes,omitempty" json:"pending_changes,omitempty"` +} + +type GetDSFRulesetsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDSFRulesetsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*DSFRulesetData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneDSFRulesetRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDSFRulesetRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID or label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // ID of the ruleset to update + Dsf_ruleset_id string `xml:"dsf_ruleset_id,omitempty" json:"dsf_ruleset_id,omitempty"` + + // response will include pending changes + Pending_changes string `xml:"pending_changes,omitempty" json:"pending_changes,omitempty"` +} + +type GetOneDSFRulesetResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDSFRulesetResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFRulesetData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneDSFRulesetRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDSFRulesetRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID or label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // ID of the ruleset to update + Dsf_ruleset_id string `xml:"dsf_ruleset_id,omitempty" json:"dsf_ruleset_id,omitempty"` + + // boolean - immediately save change and publish + Publish string `xml:"publish,omitempty" json:"publish,omitempty"` + + // Optional notes + Notes string `xml:"notes,omitempty" json:"notes,omitempty"` +} + +type DeleteOneDSFRulesetResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDSFRulesetResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFRulesetData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateDSFResponsePoolRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDSFResponsePoolRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID or label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // Response Pool label + Label string `xml:"label,omitempty" json:"label,omitempty"` + + Core_set_count string `xml:"core_set_count,omitempty" json:"core_set_count,omitempty"` + + Automation string `xml:"automation,omitempty" json:"automation,omitempty"` + + // Defaults to true + Eligible string `xml:"eligible,omitempty" json:"eligible,omitempty"` + + // ID or label of the DSF Ruleset to join + Dsf_ruleset_id string `xml:"dsf_ruleset_id,omitempty" json:"dsf_ruleset_id,omitempty"` + + // Index within the specified DSF Ruleset + Index string `xml:"index,omitempty" json:"index,omitempty"` + + Rs_chains []*DSFRecordSetFailoverChain `xml:"rs_chains,omitempty" json:"rs_chains,omitempty"` + + // boolean - immediately save change and publish + Publish string `xml:"publish,omitempty" json:"publish,omitempty"` + + // Optional notes + Notes string `xml:"notes,omitempty" json:"notes,omitempty"` +} + +type CreateDSFResponsePoolResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDSFResponsePoolResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFResponsePoolData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateDSFResponsePoolRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDSFResponsePoolRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID or label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // ID or label of the Response Pool to update + Dsf_response_pool_id string `xml:"dsf_response_pool_id,omitempty" json:"dsf_response_pool_id,omitempty"` + + // Response Pool label + Label string `xml:"label,omitempty" json:"label,omitempty"` + + Core_set_count string `xml:"core_set_count,omitempty" json:"core_set_count,omitempty"` + + Automation string `xml:"automation,omitempty" json:"automation,omitempty"` + + // Defaults to true + Eligible string `xml:"eligible,omitempty" json:"eligible,omitempty"` + + // Entire chain must be specified + Rs_chains []*DSFRecordSetFailoverChain `xml:"rs_chains,omitempty" json:"rs_chains,omitempty"` + + // ID or label of the DSF Ruleset to join + Dsf_ruleset_id string `xml:"dsf_ruleset_id,omitempty" json:"dsf_ruleset_id,omitempty"` + + // If true, removes record-sets that are no longer referenced by anyone + Remove_orphans string `xml:"remove_orphans,omitempty" json:"remove_orphans,omitempty"` + + // boolean - immediately save change and publish + Publish string `xml:"publish,omitempty" json:"publish,omitempty"` + + // Optional Publish Notes. + Notes string `xml:"notes,omitempty" json:"notes,omitempty"` +} + +type UpdateDSFResponsePoolResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDSFResponsePoolResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFResponsePoolData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetDSFResponsePoolsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDSFResponsePoolsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID or label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // ID or label of a DSF Ruleset that could contain + Dsf_ruleset_id string `xml:"dsf_ruleset_id,omitempty" json:"dsf_ruleset_id,omitempty"` + + Core_set_count string `xml:"core_set_count,omitempty" json:"core_set_count,omitempty"` + + Automation string `xml:"automation,omitempty" json:"automation,omitempty"` + + Eligible string `xml:"eligible,omitempty" json:"eligible,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + // bool, if true, finds pools that do not exist in any Rulesets + No_ruleset string `xml:"no_ruleset,omitempty" json:"no_ruleset,omitempty"` + + // response will include pending changes + Pending_changes string `xml:"pending_changes,omitempty" json:"pending_changes,omitempty"` +} + +type GetDSFResponsePoolsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDSFResponsePoolsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*DSFResponsePoolData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneDSFResponsePoolRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDSFResponsePoolRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID or the label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // ID or label of the desired response pool + Dsf_response_pool_id string `xml:"dsf_response_pool_id,omitempty" json:"dsf_response_pool_id,omitempty"` + + // response will include pending changes + Pending_changes string `xml:"pending_changes,omitempty" json:"pending_changes,omitempty"` +} + +type GetOneDSFResponsePoolResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDSFResponsePoolResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFResponsePoolData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneDSFResponsePoolRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDSFResponsePoolRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID or the label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // ID or label of the desired response pool + Dsf_response_pool_id string `xml:"dsf_response_pool_id,omitempty" json:"dsf_response_pool_id,omitempty"` + + // If 'Y', Pool will be deleted on execution + Publish string `xml:"publish,omitempty" json:"publish,omitempty"` + + // Optional notes + Notes string `xml:"notes,omitempty" json:"notes,omitempty"` +} + +type DeleteOneDSFResponsePoolResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDSFResponsePoolResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFResponsePoolData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateDSFRecordSetFailoverChainRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDSFRecordSetFailoverChainRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // ID of the DSF Response Pool that the Rec Set Fail chain belongs to + Dsf_response_pool_id string `xml:"dsf_response_pool_id,omitempty" json:"dsf_response_pool_id,omitempty"` + + // Label of the DSF Record Set Failover Chain + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // Optional, defaults to false, indicates whether enclosed Record Sets are Core + Core string `xml:"core,omitempty" json:"core,omitempty"` + + // A list of record sets to be included in this chain + Record_sets []*DSFRecordSet `xml:"record_sets,omitempty" json:"record_sets,omitempty"` + + // If 'Y', RS Chain will be deleted on execution + Publish string `xml:"publish,omitempty" json:"publish,omitempty"` + + // Optional notes + Notes string `xml:"notes,omitempty" json:"notes,omitempty"` +} + +type CreateDSFRecordSetFailoverChainResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDSFRecordSetFailoverChainResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFRecordSetFailoverChainData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateDSFRecordSetFailoverChainRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDSFRecordSetFailoverChainRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // ID or label of the DSF Rec Set Failover Chain + Dsf_record_set_failover_chain_id string `xml:"dsf_record_set_failover_chain_id,omitempty" json:"dsf_record_set_failover_chain_id,omitempty"` + + // Label of the DSF Record Set Failover Chain + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // Optional, defaults to false, indicates whether enclosed Record Sets are Core + Core string `xml:"core,omitempty" json:"core,omitempty"` + + // A list of record sets to be included in this chain + Record_sets []*DSFRecordSet `xml:"record_sets,omitempty" json:"record_sets,omitempty"` + + // If 'Y', RS Chain will be deleted on execution + Publish string `xml:"publish,omitempty" json:"publish,omitempty"` + + // Optional Publish Notes. + Notes string `xml:"notes,omitempty" json:"notes,omitempty"` +} + +type UpdateDSFRecordSetFailoverChainResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDSFRecordSetFailoverChainResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFRecordSetFailoverChainData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetDSFRecordSetFailoverChainsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDSFRecordSetFailoverChainsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID or label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // ID or label of the DSF Response Pool that the Rec Set Fail chain belongs to + Dsf_response_pool_id string `xml:"dsf_response_pool_id,omitempty" json:"dsf_response_pool_id,omitempty"` + + // Label of the DSF Record Set Failover Chain + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // Search for core DSF Record Set Failover Chains that are core + Core string `xml:"core,omitempty" json:"core,omitempty"` + + // response will include pending changes + Pending_changes string `xml:"pending_changes,omitempty" json:"pending_changes,omitempty"` +} + +type GetDSFRecordSetFailoverChainsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDSFRecordSetFailoverChainsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*DSFRecordSetFailoverChainData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneDSFRecordSetFailoverChainRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDSFRecordSetFailoverChainRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID or label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // ID or label of the DSF Rec Set Failover Chain + Dsf_record_set_failover_chain_id string `xml:"dsf_record_set_failover_chain_id,omitempty" json:"dsf_record_set_failover_chain_id,omitempty"` + + // response will include pending changes + Pending_changes string `xml:"pending_changes,omitempty" json:"pending_changes,omitempty"` +} + +type GetOneDSFRecordSetFailoverChainResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDSFRecordSetFailoverChainResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFRecordSetFailoverChainData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneDSFRecordSetFailoverChainRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDSFRecordSetFailoverChainRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID or label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // ID or label of the DSF Rec Set Failover Chain + Dsf_record_set_failover_chain_id string `xml:"dsf_record_set_failover_chain_id,omitempty" json:"dsf_record_set_failover_chain_id,omitempty"` + + // If 'Y', Pool will be deleted on execution + Publish string `xml:"publish,omitempty" json:"publish,omitempty"` + + // Optional notes + Notes string `xml:"notes,omitempty" json:"notes,omitempty"` +} + +type DeleteOneDSFRecordSetFailoverChainResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDSFRecordSetFailoverChainResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFRecordSetFailoverChainData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateDSFRecordSetRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDSFRecordSetRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID or label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // class of rdata that the set will contain + Rdata_class string `xml:"rdata_class,omitempty" json:"rdata_class,omitempty"` + + // Record Set label + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // ID or label of the associated monitor + Dsf_monitor_id string `xml:"dsf_monitor_id,omitempty" json:"dsf_monitor_id,omitempty"` + + Ttl string `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Automation string `xml:"automation,omitempty" json:"automation,omitempty"` + + Serve_count string `xml:"serve_count,omitempty" json:"serve_count,omitempty"` + + Fail_count string `xml:"fail_count,omitempty" json:"fail_count,omitempty"` + + Trouble_count string `xml:"trouble_count,omitempty" json:"trouble_count,omitempty"` + + Torpidity_max string `xml:"torpidity_max,omitempty" json:"torpidity_max,omitempty"` + + // list of hashes that contain information to create DSF Records + Records []*DSFRecord `xml:"records,omitempty" json:"records,omitempty"` + + // ID or label to associate the new RS with an existing RP + Dsf_record_set_failover_chain_id string `xml:"dsf_record_set_failover_chain_id,omitempty" json:"dsf_record_set_failover_chain_id,omitempty"` + + // Index of the RS in the specified chain + Index string `xml:"index,omitempty" json:"index,omitempty"` + + // ID or label to associate the new RS with an existing RP + Dsf_response_pool_id string `xml:"dsf_response_pool_id,omitempty" json:"dsf_response_pool_id,omitempty"` + + // Defaults to true + Eligible string `xml:"eligible,omitempty" json:"eligible,omitempty"` + + // boolean - immediately save change and publish + Publish string `xml:"publish,omitempty" json:"publish,omitempty"` + + // Optional notes + Notes string `xml:"notes,omitempty" json:"notes,omitempty"` +} + +type CreateDSFRecordSetResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDSFRecordSetResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFRecordSetData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateDSFRecordSetRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDSFRecordSetRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID or label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // ID or label of the DSF Record Set + Dsf_record_set_id string `xml:"dsf_record_set_id,omitempty" json:"dsf_record_set_id,omitempty"` + + // new label for the DSF Record Set + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // ID or label of the associated monitor + Dsf_monitor_id string `xml:"dsf_monitor_id,omitempty" json:"dsf_monitor_id,omitempty"` + + Ttl string `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Automation string `xml:"automation,omitempty" json:"automation,omitempty"` + + Serve_count string `xml:"serve_count,omitempty" json:"serve_count,omitempty"` + + Fail_count string `xml:"fail_count,omitempty" json:"fail_count,omitempty"` + + Trouble_count string `xml:"trouble_count,omitempty" json:"trouble_count,omitempty"` + + Torpidity_max string `xml:"torpidity_max,omitempty" json:"torpidity_max,omitempty"` + + // Defaults to true + Eligible string `xml:"eligible,omitempty" json:"eligible,omitempty"` + + // hash of information to create DSF Records + Records []*DSFRecord `xml:"records,omitempty" json:"records,omitempty"` + + // boolean - immediately save change and publish + Publish string `xml:"publish,omitempty" json:"publish,omitempty"` + + // Optional Publish Notes. + Notes string `xml:"notes,omitempty" json:"notes,omitempty"` +} + +type UpdateDSFRecordSetResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDSFRecordSetResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFRecordSetData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneDSFRecordSetRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDSFRecordSetRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID or label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // ID or label of the DSF Record Set + Dsf_record_set_id string `xml:"dsf_record_set_id,omitempty" json:"dsf_record_set_id,omitempty"` + + // response will include pending changes + Pending_changes string `xml:"pending_changes,omitempty" json:"pending_changes,omitempty"` +} + +type GetOneDSFRecordSetResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDSFRecordSetResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFRecordSetData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetDSFRecordSetsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDSFRecordSetsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID or label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // Record Set label - can be wildcarded + Label string `xml:"label,omitempty" json:"label,omitempty"` + + Ttl string `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Automation string `xml:"automation,omitempty" json:"automation,omitempty"` + + Serve_count string `xml:"serve_count,omitempty" json:"serve_count,omitempty"` + + Fail_count string `xml:"fail_count,omitempty" json:"fail_count,omitempty"` + + Trouble_count string `xml:"trouble_count,omitempty" json:"trouble_count,omitempty"` + + Torpidity_max string `xml:"torpidity_max,omitempty" json:"torpidity_max,omitempty"` + + Eligible string `xml:"eligible,omitempty" json:"eligible,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + // class of rdata that the set will contain + Rdata_class string `xml:"rdata_class,omitempty" json:"rdata_class,omitempty"` + + // ID or label to associate the RS with an existing DSF Record Set Failover Chain + Dsf_record_set_failover_chain_id string `xml:"dsf_record_set_failover_chain_id,omitempty" json:"dsf_record_set_failover_chain_id,omitempty"` + + // ID or label of the associated monitor + Dsf_monitor_id string `xml:"dsf_monitor_id,omitempty" json:"dsf_monitor_id,omitempty"` + + // response will include pending changes + Pending_changes string `xml:"pending_changes,omitempty" json:"pending_changes,omitempty"` +} + +type GetDSFRecordSetsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDSFRecordSetsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*DSFRecordSetData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneDSFRecordSetRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDSFRecordSetRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID or label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // ID or label of the DSF Record Set + Dsf_record_set_id string `xml:"dsf_record_set_id,omitempty" json:"dsf_record_set_id,omitempty"` + + // If 'Y', Record Set will be deleted on execution + Publish string `xml:"publish,omitempty" json:"publish,omitempty"` + + // Optional notes + Notes string `xml:"notes,omitempty" json:"notes,omitempty"` +} + +type DeleteOneDSFRecordSetResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDSFRecordSetResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFRecordSetData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateDSFRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDSFRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // label of the DSF Record Set + Dsf_record_set_id string `xml:"dsf_record_set_id,omitempty" json:"dsf_record_set_id,omitempty"` + + Master_line string `xml:"master_line,omitempty" json:"master_line,omitempty"` + + // Rdata to create the svc record with + Rdata *ANYOneRData `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of the DSF record + Label string `xml:"label,omitempty" json:"label,omitempty"` + + Weight string `xml:"weight,omitempty" json:"weight,omitempty"` + + Automation string `xml:"automation,omitempty" json:"automation,omitempty"` + + Endpoints []string `xml:"endpoints,omitempty" json:"endpoints,omitempty"` + + // number of endpoints that need to be up + Endpoint_up_count string `xml:"endpoint_up_count,omitempty" json:"endpoint_up_count,omitempty"` + + Eligible string `xml:"eligible,omitempty" json:"eligible,omitempty"` + + // boolean, if true add and immediately publish + Publish string `xml:"publish,omitempty" json:"publish,omitempty"` + + // Optional notes + Notes string `xml:"notes,omitempty" json:"notes,omitempty"` +} + +type CreateDSFRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDSFRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateDSFRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDSFRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // label of the DSF Record + Dsf_record_id string `xml:"dsf_record_id,omitempty" json:"dsf_record_id,omitempty"` + + Master_line string `xml:"master_line,omitempty" json:"master_line,omitempty"` + + // Rdata to update the svc record with + Rdata *ANYOneRData `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of the DSF record + Label string `xml:"label,omitempty" json:"label,omitempty"` + + Weight string `xml:"weight,omitempty" json:"weight,omitempty"` + + Automation string `xml:"automation,omitempty" json:"automation,omitempty"` + + Endpoints []string `xml:"endpoints,omitempty" json:"endpoints,omitempty"` + + // number of endpoints that need to be up + Endpoint_up_count string `xml:"endpoint_up_count,omitempty" json:"endpoint_up_count,omitempty"` + + Eligible string `xml:"eligible,omitempty" json:"eligible,omitempty"` + + // boolean, if true add and immediately publish + Publish string `xml:"publish,omitempty" json:"publish,omitempty"` + + // Optional Publish Notes. + Notes string `xml:"notes,omitempty" json:"notes,omitempty"` +} + +type UpdateDSFRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDSFRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneDSFRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDSFRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // label of the DSF Record + Dsf_record_id string `xml:"dsf_record_id,omitempty" json:"dsf_record_id,omitempty"` + + // response will include pending changes + Pending_changes string `xml:"pending_changes,omitempty" json:"pending_changes,omitempty"` +} + +type GetOneDSFRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDSFRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetDSFRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDSFRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // DSF Record Set Failover Chain ID to search on + Dsf_record_set_failover_chain_id string `xml:"dsf_record_set_failover_chain_id,omitempty" json:"dsf_record_set_failover_chain_id,omitempty"` + + // Record set id to search on + Dsf_record_set_id string `xml:"dsf_record_set_id,omitempty" json:"dsf_record_set_id,omitempty"` + + // Wildcard allowed + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // Wildcard allowed + Master_line string `xml:"master_line,omitempty" json:"master_line,omitempty"` + + // Wildcard allowed + Endpoints string `xml:"endpoints,omitempty" json:"endpoints,omitempty"` + + Endpoint_up_count string `xml:"endpoint_up_count,omitempty" json:"endpoint_up_count,omitempty"` + + Weight string `xml:"weight,omitempty" json:"weight,omitempty"` + + Automation string `xml:"automation,omitempty" json:"automation,omitempty"` + + Eligible string `xml:"eligible,omitempty" json:"eligible,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + // response will include pending changes + Pending_changes string `xml:"pending_changes,omitempty" json:"pending_changes,omitempty"` +} + +type GetDSFRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDSFRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*DSFRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneDSFRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDSFRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // label of the DSF Record + Dsf_record_id string `xml:"dsf_record_id,omitempty" json:"dsf_record_id,omitempty"` + + // If 'Y', Record will be deleted on execution + Publish string `xml:"publish,omitempty" json:"publish,omitempty"` + + // Optional notes + Notes string `xml:"notes,omitempty" json:"notes,omitempty"` +} + +type DeleteOneDSFRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDSFRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type AddDSFNodeRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddDSFNodeRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // an fqdn, zone pair + Node *DSFNode `xml:"node,omitempty" json:"node,omitempty"` + + // If 'Y', change is published immediately + Publish string `xml:"publish,omitempty" json:"publish,omitempty"` + + // Optional notes + Notes string `xml:"notes,omitempty" json:"notes,omitempty"` +} + +type AddDSFNodeResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddDSFNodeResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*DSFNode `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateDSFNodesRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDSFNodesRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // A list of fqdn, zone pairs + Nodes []*DSFNode `xml:"nodes,omitempty" json:"nodes,omitempty"` + + // If 'Y', change is published immediately + Publish string `xml:"publish,omitempty" json:"publish,omitempty"` + + // Optional Publish Notes. + Notes string `xml:"notes,omitempty" json:"notes,omitempty"` +} + +type UpdateDSFNodesResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDSFNodesResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*DSFNode `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetDSFNodesRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDSFNodesRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // response will include pending changes + Pending_changes string `xml:"pending_changes,omitempty" json:"pending_changes,omitempty"` +} + +type GetDSFNodesResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDSFNodesResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*DSFNode `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneDSFNodeRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDSFNodeRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // label of the DSF Service + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // an fqdn, zone pair + Node *DSFNode `xml:"node,omitempty" json:"node,omitempty"` + + // If 'Y', change is published immediately + Publish string `xml:"publish,omitempty" json:"publish,omitempty"` + + // Optional notes + Notes string `xml:"notes,omitempty" json:"notes,omitempty"` +} + +type DeleteOneDSFNodeResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDSFNodeResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*DSFNode `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateDSFMonitorRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDSFMonitorRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Label for the DSF Monitor + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // Num of responses to determine status + Response_count string `xml:"response_count,omitempty" json:"response_count,omitempty"` + + // Interval, in seconds, between probes + Probe_interval string `xml:"probe_interval,omitempty" json:"probe_interval,omitempty"` + + // number of attempted retries on failure before giving up + Retries string `xml:"retries,omitempty" json:"retries,omitempty"` + + // name of the protocol to monitor + Protocol string `xml:"protocol,omitempty" json:"protocol,omitempty"` + + // indicates if the monitor is active, default is N + Active string `xml:"active,omitempty" json:"active,omitempty"` + + // options pertaining the monitor + Options *DSFMonitorOptions `xml:"options,omitempty" json:"options,omitempty"` + + // Endpoints to monitor + Endpoints []*DSFMonitorEndpoint `xml:"endpoints,omitempty" json:"endpoints,omitempty"` +} + +type CreateDSFMonitorResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDSFMonitorResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFMonitorData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateDSFMonitorRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDSFMonitorRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID + Dsf_monitor_id string `xml:"dsf_monitor_id,omitempty" json:"dsf_monitor_id,omitempty"` + + // New label for the DSF Monitor + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // Num of responses to determine status + Response_count string `xml:"response_count,omitempty" json:"response_count,omitempty"` + + // Interval, in seconds, between probes + Probe_interval string `xml:"probe_interval,omitempty" json:"probe_interval,omitempty"` + + // number of attempted retries on failure before giving up + Retries string `xml:"retries,omitempty" json:"retries,omitempty"` + + // name of the protocol to monitor + Protocol string `xml:"protocol,omitempty" json:"protocol,omitempty"` + + // indicates if the monitor is active + Active string `xml:"active,omitempty" json:"active,omitempty"` + + // options pertaining the monitor + Options *DSFMonitorOptions `xml:"options,omitempty" json:"options,omitempty"` + + // Endpoints to monitor + Endpoints []*DSFMonitorEndpoint `xml:"endpoints,omitempty" json:"endpoints,omitempty"` +} + +type UpdateDSFMonitorResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDSFMonitorResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFMonitorData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneDSFMonitorRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDSFMonitorRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID + Dsf_monitor_id string `xml:"dsf_monitor_id,omitempty" json:"dsf_monitor_id,omitempty"` +} + +type GetOneDSFMonitorResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDSFMonitorResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFMonitorData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetDSFMonitorsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDSFMonitorsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Label for the DSF Monitor + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // Interval, in seconds, between probes + Probe_interval string `xml:"probe_interval,omitempty" json:"probe_interval,omitempty"` + + // number of attempted retries on failure before giving up + Retries string `xml:"retries,omitempty" json:"retries,omitempty"` + + // name of the protocol to monitor + Protocol string `xml:"protocol,omitempty" json:"protocol,omitempty"` +} + +type GetDSFMonitorsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDSFMonitorsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*DSFMonitorData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneDSFMonitorRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDSFMonitorRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // ID + Dsf_monitor_id string `xml:"dsf_monitor_id,omitempty" json:"dsf_monitor_id,omitempty"` +} + +type DeleteOneDSFMonitorResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDSFMonitorResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type AddDSFMonitorNotifierRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddDSFMonitorNotifierRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Monitor ID + Dsf_monitor_id string `xml:"dsf_monitor_id,omitempty" json:"dsf_monitor_id,omitempty"` + + // Notifier ID passed in for existing Notifier, or the follow params used to create + Dsf_notify_id string `xml:"dsf_notify_id,omitempty" json:"dsf_notify_id,omitempty"` + + // filters on when services should fire the notifier + Filters []string `xml:"filters,omitempty" json:"filters,omitempty"` +} + +type AddDSFMonitorNotifierResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddDSFMonitorNotifierResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *NotifierData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetDSFMonitorSitesRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDSFMonitorSitesRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` +} + +type GetDSFMonitorSitesResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDSFMonitorSitesResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSFMonitorSitesData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateNotifierRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateNotifierRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Label for the Notifier + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // List of Recipients attached to the Notifier + Recipients []*Recipient `xml:"recipients,omitempty" json:"recipients,omitempty"` + + // List of Services attached to the Notifier + Services []*Service `xml:"services,omitempty" json:"services,omitempty"` +} + +type CreateNotifierResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateNotifierResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *NotifierData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateNotifierRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateNotifierRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Public_id of the Notifier to update + Notifier_id string `xml:"notifier_id,omitempty" json:"notifier_id,omitempty"` + + // Label for the DSF Notify + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // List of Recipients attached to the Notifier + Recipients []*Recipient `xml:"recipients,omitempty" json:"recipients,omitempty"` + + // List of Services attached to the Notifier + Services []*Service `xml:"services,omitempty" json:"services,omitempty"` +} + +type UpdateNotifierResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateNotifierResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *NotifierData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneNotifierRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneNotifierRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Public_id of the Notifier to retrieve + Notifier_id string `xml:"notifier_id,omitempty" json:"notifier_id,omitempty"` +} + +type GetOneNotifierResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneNotifierResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *NotifierData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetNotifiersRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetNotifiersRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Label for the DSF Notify + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // Search for active or inactive notifiers + Active string `xml:"active,omitempty" json:"active,omitempty"` + + // Search for email or syslog recipients + Format string `xml:"format,omitempty" json:"format,omitempty"` + + // Search on the recipient email, hostname, or contact + Recipient string `xml:"recipient,omitempty" json:"recipient,omitempty"` + + // Search for active or inactive recipients + Recipient_active string `xml:"recipient_active,omitempty" json:"recipient_active,omitempty"` + + // Must be specified with service public id + Service_class string `xml:"service_class,omitempty" json:"service_class,omitempty"` + + // Public_id of the service_class item to search for + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + // Search for active or inactive services + Service_active string `xml:"service_active,omitempty" json:"service_active,omitempty"` +} + +type GetNotifiersResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetNotifiersResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*NotifierDataAlt `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneNotifierRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneNotifierRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // Public_id of the Notifier to delete + Notifier_id string `xml:"notifier_id,omitempty" json:"notifier_id,omitempty"` +} + +type DeleteOneNotifierResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneNotifierResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateConfigLimitRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateConfigLimitRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + Name string `xml:"name,omitempty" json:"name,omitempty"` + + Value string `xml:"value,omitempty" json:"value,omitempty"` +} + +type CreateConfigLimitResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateConfigLimitResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ConfigLimitData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneConfigLimitRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneConfigLimitRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + Name string `xml:"name,omitempty" json:"name,omitempty"` +} + +type GetOneConfigLimitResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneConfigLimitResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ConfigLimitData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetConfigLimitsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetConfigLimitsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` +} + +type GetConfigLimitsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetConfigLimitsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*ConfigLimitData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateConfigLimitRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateConfigLimitRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + Name string `xml:"name,omitempty" json:"name,omitempty"` + + Value string `xml:"value,omitempty" json:"value,omitempty"` +} + +type UpdateConfigLimitResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateConfigLimitResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ConfigLimitData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneConfigLimitRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneConfigLimitRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Service_id string `xml:"service_id,omitempty" json:"service_id,omitempty"` + + Name string `xml:"name,omitempty" json:"name,omitempty"` +} + +type DeleteOneConfigLimitResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneConfigLimitResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreatePermissionGroupRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreatePermissionGroupRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Group_name string `xml:"group_name,omitempty" json:"group_name,omitempty"` + + Type_ string `xml:"type,omitempty" json:"type,omitempty"` + + All_users string `xml:"all_users,omitempty" json:"all_users,omitempty"` + + Description string `xml:"description,omitempty" json:"description,omitempty"` + + Permission []string `xml:"permission,omitempty" json:"permission,omitempty"` + + User_name []string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + Subgroup []string `xml:"subgroup,omitempty" json:"subgroup,omitempty"` + + Zone []*PermissionZone `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type CreatePermissionGroupResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreatePermissionGroupResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *PermissionGroupData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOnePermissionGroupRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOnePermissionGroupRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Group_name string `xml:"group_name,omitempty" json:"group_name,omitempty"` +} + +type GetOnePermissionGroupResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOnePermissionGroupResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *PermissionGroupData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetPermissionGroupsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetPermissionGroupsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` +} + +type GetPermissionGroupsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetPermissionGroupsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*PermissionGroupData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOnePermissionGroupRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOnePermissionGroupRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Group_name string `xml:"group_name,omitempty" json:"group_name,omitempty"` +} + +type DeleteOnePermissionGroupResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOnePermissionGroupResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdatePermissionGroupRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdatePermissionGroupRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Group_name string `xml:"group_name,omitempty" json:"group_name,omitempty"` + + New_group_name string `xml:"new_group_name,omitempty" json:"new_group_name,omitempty"` + + Type_ string `xml:"type,omitempty" json:"type,omitempty"` + + All_users string `xml:"all_users,omitempty" json:"all_users,omitempty"` + + Description string `xml:"description,omitempty" json:"description,omitempty"` + + Permission []string `xml:"permission,omitempty" json:"permission,omitempty"` + + User_name []string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + Subgroup []string `xml:"subgroup,omitempty" json:"subgroup,omitempty"` + + Zone []*PermissionZone `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type UpdatePermissionGroupResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdatePermissionGroupResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *PermissionGroupData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetCustomerPermissionsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetCustomerPermissionsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` +} + +type GetCustomerPermissionsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetCustomerPermissionsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *PermissionResponse `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetUserPermissionsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetUserPermissionsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` +} + +type GetUserPermissionsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetUserPermissionsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *PermissionResponse `xml:"data,omitempty" json:"data,omitempty"` +} + +type CheckPermissionsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CheckPermissionsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Permission []string `xml:"permission,omitempty" json:"permission,omitempty"` + + Zone_name string `xml:"zone_name,omitempty" json:"zone_name,omitempty"` +} + +type CheckPermissionsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CheckPermissionsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *PermissionResponse `xml:"data,omitempty" json:"data,omitempty"` +} + +type AddPermissionGroupUsersRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddPermissionGroupUsersRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Group_name string `xml:"group_name,omitempty" json:"group_name,omitempty"` + + User_name []string `xml:"user_name,omitempty" json:"user_name,omitempty"` +} + +type AddPermissionGroupUsersResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddPermissionGroupUsersResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type SetPermissionGroupUsersRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetPermissionGroupUsersRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Group_name string `xml:"group_name,omitempty" json:"group_name,omitempty"` + + User_name []string `xml:"user_name,omitempty" json:"user_name,omitempty"` +} + +type SetPermissionGroupUsersResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetPermissionGroupUsersResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type RemovePermissionGroupUsersRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RemovePermissionGroupUsersRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Group_name string `xml:"group_name,omitempty" json:"group_name,omitempty"` + + User_name []string `xml:"user_name,omitempty" json:"user_name,omitempty"` +} + +type RemovePermissionGroupUsersResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RemovePermissionGroupUsersResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type AddPermissionGroupSubgroupsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddPermissionGroupSubgroupsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Group_name string `xml:"group_name,omitempty" json:"group_name,omitempty"` + + Subgroup []string `xml:"subgroup,omitempty" json:"subgroup,omitempty"` +} + +type AddPermissionGroupSubgroupsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddPermissionGroupSubgroupsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type SetPermissionGroupSubgroupsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetPermissionGroupSubgroupsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Group_name string `xml:"group_name,omitempty" json:"group_name,omitempty"` + + Subgroup []string `xml:"subgroup,omitempty" json:"subgroup,omitempty"` +} + +type SetPermissionGroupSubgroupsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetPermissionGroupSubgroupsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type RemovePermissionGroupSubgroupsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RemovePermissionGroupSubgroupsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Group_name string `xml:"group_name,omitempty" json:"group_name,omitempty"` + + Subgroup []string `xml:"subgroup,omitempty" json:"subgroup,omitempty"` +} + +type RemovePermissionGroupSubgroupsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RemovePermissionGroupSubgroupsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type AddPermissionGroupPermissionsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddPermissionGroupPermissionsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Group_name string `xml:"group_name,omitempty" json:"group_name,omitempty"` + + Permission []string `xml:"permission,omitempty" json:"permission,omitempty"` +} + +type AddPermissionGroupPermissionsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddPermissionGroupPermissionsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type SetPermissionGroupPermissionsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetPermissionGroupPermissionsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Group_name string `xml:"group_name,omitempty" json:"group_name,omitempty"` + + Permission []string `xml:"permission,omitempty" json:"permission,omitempty"` +} + +type SetPermissionGroupPermissionsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetPermissionGroupPermissionsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type RemovePermissionGroupPermissionsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RemovePermissionGroupPermissionsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Group_name string `xml:"group_name,omitempty" json:"group_name,omitempty"` + + Permission []string `xml:"permission,omitempty" json:"permission,omitempty"` +} + +type RemovePermissionGroupPermissionsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RemovePermissionGroupPermissionsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type AddPermissionGroupZonesRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddPermissionGroupZonesRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Group_name string `xml:"group_name,omitempty" json:"group_name,omitempty"` + + Zone []*PermissionZone `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type AddPermissionGroupZonesResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddPermissionGroupZonesResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type SetPermissionGroupZonesRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetPermissionGroupZonesRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Group_name string `xml:"group_name,omitempty" json:"group_name,omitempty"` + + Zone []*PermissionZone `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type SetPermissionGroupZonesResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetPermissionGroupZonesResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type RemovePermissionGroupZonesRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RemovePermissionGroupZonesRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Group_name string `xml:"group_name,omitempty" json:"group_name,omitempty"` + + Zone []*PermissionZone `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type RemovePermissionGroupZonesResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RemovePermissionGroupZonesResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type AddUserGroupsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddUserGroupsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + Group []string `xml:"group,omitempty" json:"group,omitempty"` +} + +type AddUserGroupsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddUserGroupsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type SetUserGroupsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetUserGroupsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + Group []string `xml:"group,omitempty" json:"group,omitempty"` +} + +type SetUserGroupsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetUserGroupsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type RemoveUserGroupsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RemoveUserGroupsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + Group []string `xml:"group,omitempty" json:"group,omitempty"` +} + +type RemoveUserGroupsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RemoveUserGroupsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type AddUserZonesRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddUserZonesRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + Zone []*PermissionZone `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type AddUserZonesResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddUserZonesResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type SetUserZonesRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetUserZonesRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + Zone []*PermissionZone `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type SetUserZonesResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetUserZonesResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type RemoveUserZonesRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RemoveUserZonesRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + Zone []*PermissionZone `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type RemoveUserZonesResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RemoveUserZonesResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type AddUserPermissionsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddUserPermissionsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + Permission []string `xml:"permission,omitempty" json:"permission,omitempty"` +} + +type AddUserPermissionsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddUserPermissionsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type SetUserPermissionsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetUserPermissionsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + Permission []string `xml:"permission,omitempty" json:"permission,omitempty"` +} + +type SetUserPermissionsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetUserPermissionsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type RemoveUserPermissionsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RemoveUserPermissionsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + Permission []string `xml:"permission,omitempty" json:"permission,omitempty"` +} + +type RemoveUserPermissionsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RemoveUserPermissionsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type AddUserForbidsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddUserForbidsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + Forbid []*PermissionData `xml:"forbid,omitempty" json:"forbid,omitempty"` +} + +type AddUserForbidsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddUserForbidsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type SetUserForbidsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetUserForbidsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + Forbid []*PermissionData `xml:"forbid,omitempty" json:"forbid,omitempty"` +} + +type SetUserForbidsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetUserForbidsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type RemoveUserForbidsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RemoveUserForbidsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + Forbid []*PermissionData `xml:"forbid,omitempty" json:"forbid,omitempty"` +} + +type RemoveUserForbidsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RemoveUserForbidsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type AddCustomerPermissionsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddCustomerPermissionsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` + + Permission []string `xml:"permission,omitempty" json:"permission,omitempty"` +} + +type AddCustomerPermissionsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddCustomerPermissionsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type SetCustomerPermissionsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetCustomerPermissionsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` + + Permission []string `xml:"permission,omitempty" json:"permission,omitempty"` +} + +type SetCustomerPermissionsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetCustomerPermissionsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type RemoveCustomerPermissionsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RemoveCustomerPermissionsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` + + Permission []string `xml:"permission,omitempty" json:"permission,omitempty"` +} + +type RemoveCustomerPermissionsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RemoveCustomerPermissionsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type AddCustomerForbidsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddCustomerForbidsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` + + Forbid []string `xml:"forbid,omitempty" json:"forbid,omitempty"` +} + +type AddCustomerForbidsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddCustomerForbidsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type SetCustomerForbidsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetCustomerForbidsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` + + Forbid []string `xml:"forbid,omitempty" json:"forbid,omitempty"` +} + +type SetCustomerForbidsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetCustomerForbidsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type RemoveCustomerForbidsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RemoveCustomerForbidsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` + + Forbid []string `xml:"forbid,omitempty" json:"forbid,omitempty"` +} + +type RemoveCustomerForbidsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RemoveCustomerForbidsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetHostStatsFlagsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetHostStatsFlagsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` +} + +type GetHostStatsFlagsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetHostStatsFlagsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*HostStatFlagsData `xml:"data,omitempty" json:"data,omitempty"` +} + +type SetHostStatsFlagsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetHostStatsFlagsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` + + Host_stats []*HostStatFlagsData `xml:"host_stats,omitempty" json:"host_stats,omitempty"` +} + +type SetHostStatsFlagsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetHostStatsFlagsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*HostStatFlagsData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateTSIGKeyRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateTSIGKeyRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Name string `xml:"name,omitempty" json:"name,omitempty"` + + Algorithm string `xml:"algorithm,omitempty" json:"algorithm,omitempty"` + + Secret string `xml:"secret,omitempty" json:"secret,omitempty"` + + Tsig_ocid string `xml:"tsig_ocid,omitempty" json:"tsig_ocid,omitempty"` + + Compartment string `xml:"compartment,omitempty" json:"compartment,omitempty"` +} + +type CreateTSIGKeyResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateTSIGKeyResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *TSIGKeyData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneTSIGKeyRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneTSIGKeyRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Name string `xml:"name,omitempty" json:"name,omitempty"` +} + +type GetOneTSIGKeyResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneTSIGKeyResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *TSIGKeyData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetTSIGKeysRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetTSIGKeysRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` +} + +type GetTSIGKeysResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetTSIGKeysResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*TSIGKeyData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateTSIGKeyRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateTSIGKeyRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Name string `xml:"name,omitempty" json:"name,omitempty"` + + New_name string `xml:"new_name,omitempty" json:"new_name,omitempty"` + + Secret string `xml:"secret,omitempty" json:"secret,omitempty"` + + Algorithm string `xml:"algorithm,omitempty" json:"algorithm,omitempty"` + + Tsig_ocid string `xml:"tsig_ocid,omitempty" json:"tsig_ocid,omitempty"` + + Compartment string `xml:"compartment,omitempty" json:"compartment,omitempty"` +} + +type UpdateTSIGKeyResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateTSIGKeyResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *TSIGKeyData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneTSIGKeyRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneTSIGKeyRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Name string `xml:"name,omitempty" json:"name,omitempty"` +} + +type DeleteOneTSIGKeyResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneTSIGKeyResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateZoneRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateZoneRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // address of responsible party, per SOA + Rname string `xml:"rname,omitempty" json:"rname,omitempty"` + + // default TTL (Time-to-Live) for records + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + // code indicating how serial numbers are constructed on publish + Serial_style string `xml:"serial_style,omitempty" json:"serial_style,omitempty"` +} + +type CreateZoneResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateZoneResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ZoneData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneZoneRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneZoneRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetOneZoneResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneZoneResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ZoneData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetZonesRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetZonesRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` +} + +type GetZonesResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetZonesResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*ZoneData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneZoneRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneZoneRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteOneZoneResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneZoneResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateSecondaryZoneRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateSecondaryZoneRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Masters []string `xml:"masters,omitempty" json:"masters,omitempty"` + + Tsig_key_name string `xml:"tsig_key_name,omitempty" json:"tsig_key_name,omitempty"` + + Contact_nickname string `xml:"contact_nickname,omitempty" json:"contact_nickname,omitempty"` +} + +type CreateSecondaryZoneResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateSecondaryZoneResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *SecondaryData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateSecondaryRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateSecondaryRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Masters []string `xml:"masters,omitempty" json:"masters,omitempty"` + + Tsig_key_name string `xml:"tsig_key_name,omitempty" json:"tsig_key_name,omitempty"` + + Contact_nickname string `xml:"contact_nickname,omitempty" json:"contact_nickname,omitempty"` +} + +type UpdateSecondaryResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateSecondaryResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *SecondaryData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ActivateSecondaryRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ActivateSecondaryRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type ActivateSecondaryResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ActivateSecondaryResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *SecondaryData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeactivateSecondaryRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeactivateSecondaryRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeactivateSecondaryResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeactivateSecondaryResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *SecondaryData `xml:"data,omitempty" json:"data,omitempty"` +} + +type RetransferSecondaryRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RetransferSecondaryRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type RetransferSecondaryResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RetransferSecondaryResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *SecondaryData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneSecondaryRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneSecondaryRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetOneSecondaryResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneSecondaryResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *SecondaryData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetSecondariesRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetSecondariesRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` +} + +type GetSecondariesResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetSecondariesResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*SecondaryData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetZoneApexRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetZoneApexRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // FQDN of a node + Node string `xml:"node,omitempty" json:"node,omitempty"` +} + +type GetZoneApexResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetZoneApexResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ZoneData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateARecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateARecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataA `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateARecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateARecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ARecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneARecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneARecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataA `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneARecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneARecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ARecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetARecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetARecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetARecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetARecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*ARecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateARecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateARecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataA `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateARecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateARecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ARecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteARecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteARecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteARecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteARecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneARecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneARecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataA `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneARecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneARecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateAAAARecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateAAAARecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataAAAA `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateAAAARecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateAAAARecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *AAAARecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneAAAARecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneAAAARecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataAAAA `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneAAAARecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneAAAARecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *AAAARecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetAAAARecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetAAAARecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetAAAARecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetAAAARecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*AAAARecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateAAAARecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateAAAARecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataAAAA `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateAAAARecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateAAAARecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *AAAARecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteAAAARecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteAAAARecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteAAAARecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteAAAARecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneAAAARecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneAAAARecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataAAAA `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneAAAARecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneAAAARecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateALIASRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateALIASRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataALIAS `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateALIASRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateALIASRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ALIASRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneALIASRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneALIASRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataALIAS `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneALIASRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneALIASRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ALIASRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetALIASRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetALIASRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetALIASRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetALIASRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*ALIASRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateALIASRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateALIASRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataALIAS `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateALIASRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateALIASRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ALIASRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteALIASRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteALIASRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteALIASRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteALIASRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneALIASRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneALIASRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataALIAS `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneALIASRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneALIASRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateCAARecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateCAARecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataCAA `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateCAARecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateCAARecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *CAARecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneCAARecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneCAARecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataCAA `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneCAARecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneCAARecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *CAARecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetCAARecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetCAARecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetCAARecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetCAARecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*CAARecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateCAARecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateCAARecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataCAA `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateCAARecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateCAARecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *CAARecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteCAARecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteCAARecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteCAARecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteCAARecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneCAARecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneCAARecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataCAA `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneCAARecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneCAARecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateCDNSKEYRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateCDNSKEYRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataCDNSKEY `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateCDNSKEYRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateCDNSKEYRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *CDNSKEYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneCDNSKEYRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneCDNSKEYRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataCDNSKEY `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneCDNSKEYRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneCDNSKEYRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *CDNSKEYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetCDNSKEYRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetCDNSKEYRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetCDNSKEYRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetCDNSKEYRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*CDNSKEYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateCDNSKEYRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateCDNSKEYRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataCDNSKEY `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateCDNSKEYRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateCDNSKEYRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *CDNSKEYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteCDNSKEYRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteCDNSKEYRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteCDNSKEYRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteCDNSKEYRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneCDNSKEYRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneCDNSKEYRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataCDNSKEY `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneCDNSKEYRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneCDNSKEYRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateCDSRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateCDSRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataCDS `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateCDSRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateCDSRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *CDSRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneCDSRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneCDSRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataCDS `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneCDSRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneCDSRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *CDSRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetCDSRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetCDSRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetCDSRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetCDSRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*CDSRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateCDSRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateCDSRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataCDS `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateCDSRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateCDSRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *CDSRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteCDSRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteCDSRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteCDSRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteCDSRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneCDSRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneCDSRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataCDS `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneCDSRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneCDSRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateCERTRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateCERTRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataCERT `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateCERTRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateCERTRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *CERTRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneCERTRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneCERTRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataCERT `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneCERTRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneCERTRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *CERTRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetCERTRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetCERTRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetCERTRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetCERTRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*CERTRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateCERTRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateCERTRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataCERT `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateCERTRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateCERTRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *CERTRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteCERTRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteCERTRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteCERTRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteCERTRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneCERTRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneCERTRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataCERT `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneCERTRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneCERTRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateCNAMERecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateCNAMERecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataCNAME `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateCNAMERecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateCNAMERecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *CNAMERecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneCNAMERecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneCNAMERecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataCNAME `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneCNAMERecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneCNAMERecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *CNAMERecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetCNAMERecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetCNAMERecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetCNAMERecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetCNAMERecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*CNAMERecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateCNAMERecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateCNAMERecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataCNAME `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateCNAMERecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateCNAMERecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *CNAMERecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteCNAMERecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteCNAMERecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteCNAMERecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteCNAMERecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneCNAMERecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneCNAMERecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataCNAME `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneCNAMERecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneCNAMERecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateCSYNCRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateCSYNCRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataCSYNC `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateCSYNCRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateCSYNCRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *CSYNCRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneCSYNCRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneCSYNCRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataCSYNC `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneCSYNCRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneCSYNCRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *CSYNCRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetCSYNCRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetCSYNCRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetCSYNCRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetCSYNCRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*CSYNCRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateCSYNCRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateCSYNCRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataCSYNC `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateCSYNCRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateCSYNCRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *CSYNCRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteCSYNCRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteCSYNCRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteCSYNCRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteCSYNCRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneCSYNCRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneCSYNCRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataCSYNC `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneCSYNCRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneCSYNCRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateDHCIDRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDHCIDRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataDHCID `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateDHCIDRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDHCIDRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DHCIDRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneDHCIDRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDHCIDRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataDHCID `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneDHCIDRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDHCIDRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DHCIDRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetDHCIDRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDHCIDRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetDHCIDRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDHCIDRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*DHCIDRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateDHCIDRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDHCIDRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataDHCID `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateDHCIDRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDHCIDRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DHCIDRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteDHCIDRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteDHCIDRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteDHCIDRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteDHCIDRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneDHCIDRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDHCIDRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataDHCID `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneDHCIDRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDHCIDRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateDNAMERecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDNAMERecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataDNAME `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateDNAMERecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDNAMERecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DNAMERecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneDNAMERecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDNAMERecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataDNAME `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneDNAMERecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDNAMERecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DNAMERecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetDNAMERecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDNAMERecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetDNAMERecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDNAMERecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*DNAMERecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateDNAMERecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDNAMERecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataDNAME `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateDNAMERecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDNAMERecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DNAMERecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteDNAMERecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteDNAMERecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteDNAMERecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteDNAMERecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneDNAMERecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDNAMERecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataDNAME `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneDNAMERecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDNAMERecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateDNSKEYRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDNSKEYRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataDNSKEY `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateDNSKEYRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDNSKEYRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DNSKEYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneDNSKEYRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDNSKEYRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataDNSKEY `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneDNSKEYRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDNSKEYRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DNSKEYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetDNSKEYRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDNSKEYRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetDNSKEYRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDNSKEYRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*DNSKEYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateDNSKEYRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDNSKEYRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataDNSKEY `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateDNSKEYRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDNSKEYRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DNSKEYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteDNSKEYRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteDNSKEYRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteDNSKEYRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteDNSKEYRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneDNSKEYRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDNSKEYRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataDNSKEY `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneDNSKEYRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDNSKEYRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateDSRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDSRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataDS `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateDSRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDSRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneDSRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDSRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataDS `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneDSRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDSRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetDSRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDSRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetDSRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDSRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*DSRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateDSRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDSRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataDS `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateDSRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDSRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DSRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteDSRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteDSRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteDSRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteDSRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneDSRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDSRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataDS `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneDSRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDSRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateIPSECKEYRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateIPSECKEYRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataIPSECKEY `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateIPSECKEYRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateIPSECKEYRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *IPSECKEYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneIPSECKEYRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneIPSECKEYRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataIPSECKEY `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneIPSECKEYRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneIPSECKEYRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *IPSECKEYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetIPSECKEYRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetIPSECKEYRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetIPSECKEYRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetIPSECKEYRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*IPSECKEYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateIPSECKEYRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateIPSECKEYRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataIPSECKEY `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateIPSECKEYRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateIPSECKEYRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *IPSECKEYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteIPSECKEYRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteIPSECKEYRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteIPSECKEYRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteIPSECKEYRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneIPSECKEYRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneIPSECKEYRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataIPSECKEY `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneIPSECKEYRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneIPSECKEYRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateKEYRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateKEYRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataKEY `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateKEYRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateKEYRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *KEYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneKEYRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneKEYRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataKEY `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneKEYRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneKEYRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *KEYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetKEYRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetKEYRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetKEYRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetKEYRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*KEYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateKEYRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateKEYRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataKEY `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateKEYRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateKEYRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *KEYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteKEYRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteKEYRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteKEYRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteKEYRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneKEYRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneKEYRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataKEY `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneKEYRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneKEYRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateKXRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateKXRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataKX `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateKXRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateKXRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *KXRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneKXRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneKXRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataKX `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneKXRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneKXRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *KXRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetKXRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetKXRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetKXRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetKXRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*KXRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateKXRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateKXRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataKX `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateKXRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateKXRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *KXRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteKXRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteKXRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteKXRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteKXRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneKXRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneKXRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataKX `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneKXRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneKXRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateLOCRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateLOCRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataLOC `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateLOCRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateLOCRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *LOCRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneLOCRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneLOCRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataLOC `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneLOCRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneLOCRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *LOCRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetLOCRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetLOCRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetLOCRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetLOCRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*LOCRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateLOCRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateLOCRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataLOC `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateLOCRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateLOCRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *LOCRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteLOCRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteLOCRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteLOCRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteLOCRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneLOCRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneLOCRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataLOC `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneLOCRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneLOCRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateMXRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateMXRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataMX `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateMXRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateMXRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *MXRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneMXRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneMXRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataMX `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneMXRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneMXRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *MXRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetMXRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetMXRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetMXRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetMXRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*MXRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateMXRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateMXRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataMX `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateMXRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateMXRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *MXRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteMXRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteMXRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteMXRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteMXRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneMXRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneMXRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataMX `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneMXRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneMXRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateNAPTRRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateNAPTRRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataNAPTR `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateNAPTRRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateNAPTRRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *NAPTRRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneNAPTRRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneNAPTRRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataNAPTR `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneNAPTRRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneNAPTRRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *NAPTRRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetNAPTRRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetNAPTRRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetNAPTRRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetNAPTRRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*NAPTRRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateNAPTRRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateNAPTRRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataNAPTR `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateNAPTRRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateNAPTRRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *NAPTRRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteNAPTRRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteNAPTRRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteNAPTRRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteNAPTRRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneNAPTRRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneNAPTRRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataNAPTR `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneNAPTRRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneNAPTRRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateNSAPRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateNSAPRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataNSAP `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateNSAPRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateNSAPRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *NSAPRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneNSAPRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneNSAPRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataNSAP `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneNSAPRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneNSAPRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *NSAPRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetNSAPRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetNSAPRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetNSAPRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetNSAPRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*NSAPRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateNSAPRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateNSAPRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataNSAP `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateNSAPRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateNSAPRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *NSAPRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteNSAPRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteNSAPRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteNSAPRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteNSAPRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneNSAPRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneNSAPRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataNSAP `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneNSAPRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneNSAPRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreatePOLICYRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreatePOLICYRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataPOLICY `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreatePOLICYRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreatePOLICYRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *POLICYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOnePOLICYRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOnePOLICYRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataPOLICY `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOnePOLICYRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOnePOLICYRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *POLICYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetPOLICYRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetPOLICYRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetPOLICYRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetPOLICYRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*POLICYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdatePOLICYRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdatePOLICYRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataPOLICY `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdatePOLICYRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdatePOLICYRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *POLICYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeletePOLICYRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeletePOLICYRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeletePOLICYRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeletePOLICYRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOnePOLICYRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOnePOLICYRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataPOLICY `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOnePOLICYRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOnePOLICYRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreatePTRRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreatePTRRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataPTR `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreatePTRRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreatePTRRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *PTRRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOnePTRRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOnePTRRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataPTR `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOnePTRRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOnePTRRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *PTRRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetPTRRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetPTRRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetPTRRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetPTRRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*PTRRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdatePTRRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdatePTRRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataPTR `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdatePTRRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdatePTRRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *PTRRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeletePTRRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeletePTRRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeletePTRRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeletePTRRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOnePTRRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOnePTRRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataPTR `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOnePTRRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOnePTRRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreatePXRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreatePXRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataPX `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreatePXRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreatePXRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *PXRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOnePXRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOnePXRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataPX `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOnePXRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOnePXRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *PXRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetPXRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetPXRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetPXRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetPXRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*PXRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdatePXRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdatePXRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataPX `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdatePXRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdatePXRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *PXRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeletePXRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeletePXRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeletePXRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeletePXRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOnePXRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOnePXRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataPX `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOnePXRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOnePXRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateRPRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateRPRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataRP `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateRPRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateRPRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *RPRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneRPRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneRPRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataRP `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneRPRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneRPRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *RPRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetRPRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetRPRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetRPRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetRPRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*RPRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateRPRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateRPRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataRP `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateRPRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateRPRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *RPRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteRPRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteRPRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteRPRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteRPRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneRPRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneRPRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataRP `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneRPRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneRPRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateSPFRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateSPFRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataSPF `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateSPFRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateSPFRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *SPFRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneSPFRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneSPFRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataSPF `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneSPFRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneSPFRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *SPFRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetSPFRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetSPFRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetSPFRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetSPFRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*SPFRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateSPFRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateSPFRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataSPF `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateSPFRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateSPFRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *SPFRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteSPFRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteSPFRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteSPFRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteSPFRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneSPFRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneSPFRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataSPF `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneSPFRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneSPFRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateSRVRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateSRVRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataSRV `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateSRVRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateSRVRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *SRVRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneSRVRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneSRVRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataSRV `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneSRVRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneSRVRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *SRVRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetSRVRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetSRVRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetSRVRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetSRVRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*SRVRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateSRVRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateSRVRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataSRV `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateSRVRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateSRVRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *SRVRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteSRVRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteSRVRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteSRVRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteSRVRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneSRVRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneSRVRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataSRV `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneSRVRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneSRVRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateSSHFPRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateSSHFPRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataSSHFP `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateSSHFPRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateSSHFPRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *SSHFPRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneSSHFPRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneSSHFPRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataSSHFP `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneSSHFPRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneSSHFPRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *SSHFPRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetSSHFPRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetSSHFPRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetSSHFPRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetSSHFPRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*SSHFPRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateSSHFPRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateSSHFPRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataSSHFP `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateSSHFPRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateSSHFPRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *SSHFPRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteSSHFPRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteSSHFPRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteSSHFPRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteSSHFPRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneSSHFPRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneSSHFPRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataSSHFP `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneSSHFPRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneSSHFPRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateTLSARecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateTLSARecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataTLSA `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateTLSARecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateTLSARecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *TLSARecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneTLSARecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneTLSARecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataTLSA `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneTLSARecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneTLSARecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *TLSARecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetTLSARecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetTLSARecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetTLSARecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetTLSARecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*TLSARecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateTLSARecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateTLSARecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataTLSA `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateTLSARecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateTLSARecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *TLSARecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteTLSARecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteTLSARecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteTLSARecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteTLSARecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneTLSARecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneTLSARecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataTLSA `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneTLSARecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneTLSARecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateTXTRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateTXTRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataTXT `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type CreateTXTRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateTXTRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *TXTRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneTXTRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneTXTRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataTXT `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneTXTRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneTXTRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *TXTRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetTXTRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetTXTRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetTXTRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetTXTRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*TXTRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateTXTRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateTXTRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataTXT `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` +} + +type UpdateTXTRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateTXTRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *TXTRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteTXTRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteTXTRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteTXTRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteTXTRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneTXTRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneTXTRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataTXT `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneTXTRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneTXTRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneSOARecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneSOARecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataSOA `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneSOARecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneSOARecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *SOARecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetSOARecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetSOARecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetSOARecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetSOARecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*SOARecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateSOARecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateSOARecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Serial_style string `xml:"serial_style,omitempty" json:"serial_style,omitempty"` + + Rdata *RDataSOAUpdate `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type UpdateSOARecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateSOARecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *SOARecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateNSRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateNSRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Rdata *RDataNS `xml:"rdata,omitempty" json:"rdata,omitempty"` + + Service_class string `xml:"service_class,omitempty" json:"service_class,omitempty"` +} + +type CreateNSRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateNSRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *NSRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneNSRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneNSRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataNS `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneNSRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneNSRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *NSRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetNSRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetNSRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetNSRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetNSRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*NSRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateNSRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateNSRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataNS `xml:"rdata,omitempty" json:"rdata,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + Service_class string `xml:"service_class,omitempty" json:"service_class,omitempty"` +} + +type UpdateNSRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateNSRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *NSRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteNSRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteNSRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteNSRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteNSRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneNSRecordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneNSRecordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` + + Rdata *RDataNS `xml:"rdata,omitempty" json:"rdata,omitempty"` +} + +type DeleteOneNSRecordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneNSRecordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceARecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceARecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + ARecords []*ARecordData `xml:"ARecords,omitempty" json:"ARecords,omitempty"` +} + +type ReplaceARecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceARecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*ARecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceAAAARecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceAAAARecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + AAAARecords []*AAAARecordData `xml:"AAAARecords,omitempty" json:"AAAARecords,omitempty"` +} + +type ReplaceAAAARecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceAAAARecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*AAAARecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceALIASRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceALIASRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + ALIASRecords []*ALIASRecordData `xml:"ALIASRecords,omitempty" json:"ALIASRecords,omitempty"` +} + +type ReplaceALIASRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceALIASRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*ALIASRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceCAARecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceCAARecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + CAARecords []*CAARecordData `xml:"CAARecords,omitempty" json:"CAARecords,omitempty"` +} + +type ReplaceCAARecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceCAARecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*CAARecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceCDNSKEYRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceCDNSKEYRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + CDNSKEYRecords []*CDNSKEYRecordData `xml:"CDNSKEYRecords,omitempty" json:"CDNSKEYRecords,omitempty"` +} + +type ReplaceCDNSKEYRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceCDNSKEYRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*CDNSKEYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceCDSRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceCDSRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + CDSRecords []*CDSRecordData `xml:"CDSRecords,omitempty" json:"CDSRecords,omitempty"` +} + +type ReplaceCDSRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceCDSRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*CDSRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceCERTRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceCERTRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + CERTRecords []*CERTRecordData `xml:"CERTRecords,omitempty" json:"CERTRecords,omitempty"` +} + +type ReplaceCERTRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceCERTRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*CERTRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceCNAMERecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceCNAMERecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + CNAMERecords []*CNAMERecordData `xml:"CNAMERecords,omitempty" json:"CNAMERecords,omitempty"` +} + +type ReplaceCNAMERecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceCNAMERecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*CNAMERecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceCSYNCRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceCSYNCRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + CSYNCRecords []*CSYNCRecordData `xml:"CSYNCRecords,omitempty" json:"CSYNCRecords,omitempty"` +} + +type ReplaceCSYNCRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceCSYNCRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*CSYNCRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceDHCIDRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceDHCIDRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + DHCIDRecords []*DHCIDRecordData `xml:"DHCIDRecords,omitempty" json:"DHCIDRecords,omitempty"` +} + +type ReplaceDHCIDRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceDHCIDRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*DHCIDRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceDNAMERecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceDNAMERecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + DNAMERecords []*DNAMERecordData `xml:"DNAMERecords,omitempty" json:"DNAMERecords,omitempty"` +} + +type ReplaceDNAMERecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceDNAMERecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*DNAMERecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceDNSKEYRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceDNSKEYRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + DNSKEYRecords []*DNSKEYRecordData `xml:"DNSKEYRecords,omitempty" json:"DNSKEYRecords,omitempty"` +} + +type ReplaceDNSKEYRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceDNSKEYRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*DNSKEYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceDSRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceDSRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + DSRecords []*DSRecordData `xml:"DSRecords,omitempty" json:"DSRecords,omitempty"` +} + +type ReplaceDSRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceDSRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*DSRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceIPSECKEYRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceIPSECKEYRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + IPSECKEYRecords []*IPSECKEYRecordData `xml:"IPSECKEYRecords,omitempty" json:"IPSECKEYRecords,omitempty"` +} + +type ReplaceIPSECKEYRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceIPSECKEYRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*IPSECKEYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceKEYRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceKEYRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + KEYRecords []*KEYRecordData `xml:"KEYRecords,omitempty" json:"KEYRecords,omitempty"` +} + +type ReplaceKEYRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceKEYRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*KEYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceKXRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceKXRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + KXRecords []*KXRecordData `xml:"KXRecords,omitempty" json:"KXRecords,omitempty"` +} + +type ReplaceKXRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceKXRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*KXRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceLOCRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceLOCRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + LOCRecords []*LOCRecordData `xml:"LOCRecords,omitempty" json:"LOCRecords,omitempty"` +} + +type ReplaceLOCRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceLOCRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*LOCRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceMXRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceMXRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + MXRecords []*MXRecordData `xml:"MXRecords,omitempty" json:"MXRecords,omitempty"` +} + +type ReplaceMXRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceMXRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*MXRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceNAPTRRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceNAPTRRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + NAPTRRecords []*NAPTRRecordData `xml:"NAPTRRecords,omitempty" json:"NAPTRRecords,omitempty"` +} + +type ReplaceNAPTRRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceNAPTRRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*NAPTRRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceNSAPRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceNSAPRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + NSAPRecords []*NSAPRecordData `xml:"NSAPRecords,omitempty" json:"NSAPRecords,omitempty"` +} + +type ReplaceNSAPRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceNSAPRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*NSAPRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplacePOLICYRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplacePOLICYRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + POLICYRecords []*POLICYRecordData `xml:"POLICYRecords,omitempty" json:"POLICYRecords,omitempty"` +} + +type ReplacePOLICYRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplacePOLICYRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*POLICYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplacePTRRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplacePTRRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + PTRRecords []*PTRRecordData `xml:"PTRRecords,omitempty" json:"PTRRecords,omitempty"` +} + +type ReplacePTRRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplacePTRRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*PTRRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplacePXRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplacePXRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + PXRecords []*PXRecordData `xml:"PXRecords,omitempty" json:"PXRecords,omitempty"` +} + +type ReplacePXRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplacePXRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*PXRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceRPRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceRPRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + RPRecords []*RPRecordData `xml:"RPRecords,omitempty" json:"RPRecords,omitempty"` +} + +type ReplaceRPRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceRPRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*RPRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceSPFRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceSPFRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + SPFRecords []*SPFRecordData `xml:"SPFRecords,omitempty" json:"SPFRecords,omitempty"` +} + +type ReplaceSPFRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceSPFRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*SPFRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceSRVRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceSRVRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + SRVRecords []*SRVRecordData `xml:"SRVRecords,omitempty" json:"SRVRecords,omitempty"` +} + +type ReplaceSRVRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceSRVRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*SRVRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceSSHFPRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceSSHFPRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + SSHFPRecords []*SSHFPRecordData `xml:"SSHFPRecords,omitempty" json:"SSHFPRecords,omitempty"` +} + +type ReplaceSSHFPRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceSSHFPRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*SSHFPRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceTLSARecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceTLSARecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + TLSARecords []*TLSARecordData `xml:"TLSARecords,omitempty" json:"TLSARecords,omitempty"` +} + +type ReplaceTLSARecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceTLSARecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*TLSARecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceTXTRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceTXTRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + TXTRecords []*TXTRecordData `xml:"TXTRecords,omitempty" json:"TXTRecords,omitempty"` +} + +type ReplaceTXTRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceTXTRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*TXTRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ReplaceNSRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceNSRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + NSRecords []*NSRecordData `xml:"NSRecords,omitempty" json:"NSRecords,omitempty"` +} + +type ReplaceNSRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ReplaceNSRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*NSRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetANYRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetANYRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetANYRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetANYRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ANYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetAllRecordsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetAllRecordsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetAllRecordsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetAllRecordsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ANYRecordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetAllAliasQNamesRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetAllAliasQNamesRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` +} + +type GetAllAliasQNamesResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetAllAliasQNamesResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *QNames `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneUserRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneUserRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of user + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` +} + +type GetOneUserResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneUserResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *UserData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneUserRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneUserRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of user + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` +} + +type DeleteOneUserResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneUserResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateUserRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateUserRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + Password string `xml:"password,omitempty" json:"password,omitempty"` + + Permission []string `xml:"permission,omitempty" json:"permission,omitempty"` + + Group_name []string `xml:"group_name,omitempty" json:"group_name,omitempty"` + + Zone []*PermissionZone `xml:"zone,omitempty" json:"zone,omitempty"` + + Forbid []*PermissionData `xml:"forbid,omitempty" json:"forbid,omitempty"` + + Nickname string `xml:"nickname,omitempty" json:"nickname,omitempty"` + + First_name string `xml:"first_name,omitempty" json:"first_name,omitempty"` + + Last_name string `xml:"last_name,omitempty" json:"last_name,omitempty"` + + Phone string `xml:"phone,omitempty" json:"phone,omitempty"` + + Fax string `xml:"fax,omitempty" json:"fax,omitempty"` + + Email string `xml:"email,omitempty" json:"email,omitempty"` + + Notify_email string `xml:"notify_email,omitempty" json:"notify_email,omitempty"` + + Pager_email string `xml:"pager_email,omitempty" json:"pager_email,omitempty"` + + Address string `xml:"address,omitempty" json:"address,omitempty"` + + Address_2 string `xml:"address_2,omitempty" json:"address_2,omitempty"` + + City string `xml:"city,omitempty" json:"city,omitempty"` + + State string `xml:"state,omitempty" json:"state,omitempty"` + + Post_code string `xml:"post_code,omitempty" json:"post_code,omitempty"` + + Country string `xml:"country,omitempty" json:"country,omitempty"` + + Website string `xml:"website,omitempty" json:"website,omitempty"` + + Organization string `xml:"organization,omitempty" json:"organization,omitempty"` +} + +type CreateUserResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateUserResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *UserData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateUserRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateUserRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + New_user_name string `xml:"new_user_name,omitempty" json:"new_user_name,omitempty"` + + Password string `xml:"password,omitempty" json:"password,omitempty"` + + Require_pw_change string `xml:"require_pw_change,omitempty" json:"require_pw_change,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Permission []string `xml:"permission,omitempty" json:"permission,omitempty"` + + Group_name []string `xml:"group_name,omitempty" json:"group_name,omitempty"` + + Zone []*PermissionZone `xml:"zone,omitempty" json:"zone,omitempty"` + + Forbid []*PermissionData `xml:"forbid,omitempty" json:"forbid,omitempty"` + + Nickname string `xml:"nickname,omitempty" json:"nickname,omitempty"` + + First_name string `xml:"first_name,omitempty" json:"first_name,omitempty"` + + Last_name string `xml:"last_name,omitempty" json:"last_name,omitempty"` + + Phone string `xml:"phone,omitempty" json:"phone,omitempty"` + + Fax string `xml:"fax,omitempty" json:"fax,omitempty"` + + Email string `xml:"email,omitempty" json:"email,omitempty"` + + Notify_email string `xml:"notify_email,omitempty" json:"notify_email,omitempty"` + + Pager_email string `xml:"pager_email,omitempty" json:"pager_email,omitempty"` + + Address string `xml:"address,omitempty" json:"address,omitempty"` + + Address_2 string `xml:"address_2,omitempty" json:"address_2,omitempty"` + + City string `xml:"city,omitempty" json:"city,omitempty"` + + State string `xml:"state,omitempty" json:"state,omitempty"` + + Post_code string `xml:"post_code,omitempty" json:"post_code,omitempty"` + + Country string `xml:"country,omitempty" json:"country,omitempty"` + + Website string `xml:"website,omitempty" json:"website,omitempty"` + + Organization string `xml:"organization,omitempty" json:"organization,omitempty"` +} + +type UpdateUserResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateUserResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *UserData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetUsersRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetUsersRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Search string `xml:"search,omitempty" json:"search,omitempty"` +} + +type GetUsersResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetUsersResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*UserData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetUpdateUsersRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetUpdateUsersRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` +} + +type GetUpdateUsersResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetUpdateUsersResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*UserData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateUpdateUserRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateUpdateUserRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + Password string `xml:"password,omitempty" json:"password,omitempty"` +} + +type UpdateUpdateUserResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateUpdateUserResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *UserData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneUpdateUserRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneUpdateUserRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` +} + +type DeleteOneUpdateUserResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneUpdateUserResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateUserPasswordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateUserPasswordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Password string `xml:"password,omitempty" json:"password,omitempty"` +} + +type UpdateUserPasswordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateUserPasswordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *UserData `xml:"data,omitempty" json:"data,omitempty"` +} + +type BlockUserRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ BlockUserRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` +} + +type BlockUserResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ BlockUserResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *UserData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UnblockUserRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UnblockUserRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` +} + +type UnblockUserResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UnblockUserResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *UserData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateContactRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateContactRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Nickname string `xml:"nickname,omitempty" json:"nickname,omitempty"` + + First_name string `xml:"first_name,omitempty" json:"first_name,omitempty"` + + Last_name string `xml:"last_name,omitempty" json:"last_name,omitempty"` + + Phone string `xml:"phone,omitempty" json:"phone,omitempty"` + + Fax string `xml:"fax,omitempty" json:"fax,omitempty"` + + Email string `xml:"email,omitempty" json:"email,omitempty"` + + Notify_email string `xml:"notify_email,omitempty" json:"notify_email,omitempty"` + + Pager_email string `xml:"pager_email,omitempty" json:"pager_email,omitempty"` + + Address string `xml:"address,omitempty" json:"address,omitempty"` + + Address_2 string `xml:"address_2,omitempty" json:"address_2,omitempty"` + + City string `xml:"city,omitempty" json:"city,omitempty"` + + State string `xml:"state,omitempty" json:"state,omitempty"` + + Post_code string `xml:"post_code,omitempty" json:"post_code,omitempty"` + + Country string `xml:"country,omitempty" json:"country,omitempty"` + + Website string `xml:"website,omitempty" json:"website,omitempty"` + + Organization string `xml:"organization,omitempty" json:"organization,omitempty"` +} + +type CreateContactResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateContactResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ContactData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneContactRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneContactRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Nickname string `xml:"nickname,omitempty" json:"nickname,omitempty"` +} + +type GetOneContactResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneContactResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ContactData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetContactsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetContactsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` +} + +type GetContactsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetContactsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*ContactData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneContactRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneContactRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Nickname string `xml:"nickname,omitempty" json:"nickname,omitempty"` +} + +type DeleteOneContactResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneContactResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateContactRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateContactRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Nickname string `xml:"nickname,omitempty" json:"nickname,omitempty"` + + New_nickname string `xml:"new_nickname,omitempty" json:"new_nickname,omitempty"` + + First_name string `xml:"first_name,omitempty" json:"first_name,omitempty"` + + Last_name string `xml:"last_name,omitempty" json:"last_name,omitempty"` + + Phone string `xml:"phone,omitempty" json:"phone,omitempty"` + + Fax string `xml:"fax,omitempty" json:"fax,omitempty"` + + Email string `xml:"email,omitempty" json:"email,omitempty"` + + Notify_email string `xml:"notify_email,omitempty" json:"notify_email,omitempty"` + + Pager_email string `xml:"pager_email,omitempty" json:"pager_email,omitempty"` + + Address string `xml:"address,omitempty" json:"address,omitempty"` + + Address_2 string `xml:"address_2,omitempty" json:"address_2,omitempty"` + + City string `xml:"city,omitempty" json:"city,omitempty"` + + State string `xml:"state,omitempty" json:"state,omitempty"` + + Post_code string `xml:"post_code,omitempty" json:"post_code,omitempty"` + + Country string `xml:"country,omitempty" json:"country,omitempty"` + + Website string `xml:"website,omitempty" json:"website,omitempty"` + + Organization string `xml:"organization,omitempty" json:"organization,omitempty"` +} + +type UpdateContactResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateContactResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ContactData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateCustomerRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateCustomerRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` + + Organization string `xml:"organization,omitempty" json:"organization,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Pool_id string `xml:"pool_id,omitempty" json:"pool_id,omitempty"` + + Type_ string `xml:"type,omitempty" json:"type,omitempty"` + + Level string `xml:"level,omitempty" json:"level,omitempty"` + + Primary_sales_agent string `xml:"primary_sales_agent,omitempty" json:"primary_sales_agent,omitempty"` + + Salesforce_id string `xml:"salesforce_id,omitempty" json:"salesforce_id,omitempty"` + + Owner *CustomerAdminData `xml:"owner,omitempty" json:"owner,omitempty"` + + Billing *CustomerAdminData `xml:"billing,omitempty" json:"billing,omitempty"` + + Permission []string `xml:"permission,omitempty" json:"permission,omitempty"` + + Forbid []string `xml:"forbid,omitempty" json:"forbid,omitempty"` +} + +type CreateCustomerResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateCustomerResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *CustomerData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateCustomerRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateCustomerRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` + + New_customer_name string `xml:"new_customer_name,omitempty" json:"new_customer_name,omitempty"` + + Organization string `xml:"organization,omitempty" json:"organization,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Note string `xml:"note,omitempty" json:"note,omitempty"` + + Pool_id string `xml:"pool_id,omitempty" json:"pool_id,omitempty"` + + Activated string `xml:"activated,omitempty" json:"activated,omitempty"` + + Type_ string `xml:"type,omitempty" json:"type,omitempty"` + + Level string `xml:"level,omitempty" json:"level,omitempty"` + + Primary_sales_agent string `xml:"primary_sales_agent,omitempty" json:"primary_sales_agent,omitempty"` + + Salesforce_id string `xml:"salesforce_id,omitempty" json:"salesforce_id,omitempty"` + + Owner_contact string `xml:"owner_contact,omitempty" json:"owner_contact,omitempty"` + + Billing_contact string `xml:"billing_contact,omitempty" json:"billing_contact,omitempty"` + + Permission []string `xml:"permission,omitempty" json:"permission,omitempty"` + + Forbid []string `xml:"forbid,omitempty" json:"forbid,omitempty"` +} + +type UpdateCustomerResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateCustomerResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *CustomerData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneCustomerRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneCustomerRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` +} + +type GetOneCustomerResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneCustomerResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *CustomerData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetCustomersRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetCustomersRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Simple string `xml:"simple,omitempty" json:"simple,omitempty"` + + Search string `xml:"search,omitempty" json:"search,omitempty"` +} + +type GetCustomersResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetCustomersResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*CustomerData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneCustomerRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneCustomerRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` + + Note string `xml:"note,omitempty" json:"note,omitempty"` +} + +type DeleteOneCustomerResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneCustomerResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetCustomerPrefsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetCustomerPrefsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // preference name; may be '*' to list all + Name string `xml:"name,omitempty" json:"name,omitempty"` + + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` +} + +type GetCustomerPrefsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetCustomerPrefsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*CustomerPrefData `xml:"data,omitempty" json:"data,omitempty"` +} + +type SetCustomerPrefsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetCustomerPrefsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Prefs []*CustomerPrefData `xml:"prefs,omitempty" json:"prefs,omitempty"` + + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` +} + +type SetCustomerPrefsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetCustomerPrefsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetCustomerIPACLRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetCustomerIPACLRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // customer name or ID to see ACLs for, defaults to current customer + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` + + // scope of the ACL to retrieve + Scope string `xml:"scope,omitempty" json:"scope,omitempty"` +} + +type GetCustomerIPACLResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetCustomerIPACLResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*CustomerIPACL `xml:"data,omitempty" json:"data,omitempty"` +} + +type SetCustomerIPACLRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetCustomerIPACLRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // customer name or ID to set ACLs for, defaults to current customer + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` + + Acl *CustomerIPACL `xml:"acl,omitempty" json:"acl,omitempty"` +} + +type SetCustomerIPACLResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetCustomerIPACLResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*CustomerIPACL `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateCustomerOracleMetadataRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateCustomerOracleMetadataRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of customer + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` + + // compartment id + Compartment_id string `xml:"compartment_id,omitempty" json:"compartment_id,omitempty"` + + // tenant id + Tenant string `xml:"tenant,omitempty" json:"tenant,omitempty"` +} + +type CreateCustomerOracleMetadataResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateCustomerOracleMetadataResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *CustomerOracleMetadataData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateCustomerOracleMetadataRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateCustomerOracleMetadataRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of customer + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` + + // compartment id + Compartment_id string `xml:"compartment_id,omitempty" json:"compartment_id,omitempty"` + + // tenant id + Tenant string `xml:"tenant,omitempty" json:"tenant,omitempty"` +} + +type UpdateCustomerOracleMetadataResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateCustomerOracleMetadataResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *CustomerOracleMetadataData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetCustomerOracleMetadataRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetCustomerOracleMetadataRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of customer + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` + + // compartment id + Compartment_id string `xml:"compartment_id,omitempty" json:"compartment_id,omitempty"` + + // tenant id + Tenant string `xml:"tenant,omitempty" json:"tenant,omitempty"` +} + +type GetCustomerOracleMetadataResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetCustomerOracleMetadataResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*CustomerOracleMetadataData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteCustomerOracleMetadataRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteCustomerOracleMetadataRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of customer + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` +} + +type DeleteCustomerOracleMetadataResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteCustomerOracleMetadataResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *CustomerOracleMetadataData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateZoneOracleMetadataRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateZoneOracleMetadataRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // compartment id + Compartment_id string `xml:"compartment_id,omitempty" json:"compartment_id,omitempty"` + + // public_id + Public_id string `xml:"public_id,omitempty" json:"public_id,omitempty"` +} + +type CreateZoneOracleMetadataResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateZoneOracleMetadataResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ZoneOracleMetadataData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateZoneOracleMetadataRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateZoneOracleMetadataRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // compartment id + Compartment_id string `xml:"compartment_id,omitempty" json:"compartment_id,omitempty"` + + // public_id + Public_id string `xml:"public_id,omitempty" json:"public_id,omitempty"` +} + +type UpdateZoneOracleMetadataResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateZoneOracleMetadataResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ZoneOracleMetadataData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetZoneOracleMetadataRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetZoneOracleMetadataRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // compartment id + Compartment_id string `xml:"compartment_id,omitempty" json:"compartment_id,omitempty"` + + // public id + Public_id string `xml:"public_id,omitempty" json:"public_id,omitempty"` +} + +type GetZoneOracleMetadataResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetZoneOracleMetadataResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*ZoneOracleMetadataData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteZoneOracleMetadataRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteZoneOracleMetadataRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteZoneOracleMetadataResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteZoneOracleMetadataResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ZoneOracleMetadataData `xml:"data,omitempty" json:"data,omitempty"` +} + +type OCIMigrateRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ OCIMigrateRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // , req + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // public_id + Zone_ocid string `xml:"zone_ocid,omitempty" json:"zone_ocid,omitempty"` + + // compartment id + Compartment_id string `xml:"compartment_id,omitempty" json:"compartment_id,omitempty"` + + // tenant id + Tenancy_id string `xml:"tenancy_id,omitempty" json:"tenancy_id,omitempty"` + + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` + + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` + + Password string `xml:"password,omitempty" json:"password,omitempty"` + + Replacements *Replacement `xml:"replacements,omitempty" json:"replacements,omitempty"` +} + +type OCIMigrateResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ OCIMigrateResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateDDNSRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDDNSRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // an IP address, either v4 or v6 + Address string `xml:"address,omitempty" json:"address,omitempty"` + + // either A or AAAA + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type CreateDDNSResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDDNSResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DDNSData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneDDNSRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDDNSRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // either A or AAAA + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneDDNSResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDDNSResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DDNSData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetDDNSsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDDNSsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetDDNSsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDDNSsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*DDNSData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateDDNSRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDDNSRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // either A or AAAA + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // an IP address, either v4 or v6 + Address string `xml:"address,omitempty" json:"address,omitempty"` +} + +type UpdateDDNSResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDDNSResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DDNSData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneDDNSRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDDNSRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // either A or AAAA + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type DeleteOneDDNSResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDDNSResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type ActivateDDNSRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ActivateDDNSRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // either A or AAAA + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` +} + +type ActivateDDNSResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ActivateDDNSResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DDNSData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeactivateDDNSRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeactivateDDNSRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // either A or AAAA + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` +} + +type DeactivateDDNSResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeactivateDDNSResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DDNSData `xml:"data,omitempty" json:"data,omitempty"` +} + +type ResetDDNSRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ResetDDNSRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // either A or AAAA + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` +} + +type ResetDDNSResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ResetDDNSResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DDNSData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetUpdateUserPasswordRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetUpdateUserPasswordRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + User_name string `xml:"user_name,omitempty" json:"user_name,omitempty"` +} + +type GetUpdateUserPasswordResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetUpdateUserPasswordResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *UpdateUserPasswordData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateDDNSHostRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDDNSHostRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // an IP address, either v4 or v6 + Address string `xml:"address,omitempty" json:"address,omitempty"` + + // either A or AAAA + Record_type string `xml:"record_type,omitempty" json:"record_type,omitempty"` + + // name of update user + User string `xml:"user,omitempty" json:"user,omitempty"` +} + +type CreateDDNSHostResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDDNSHostResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DDNSHostData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateUpdateUserRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateUpdateUserRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Nickname string `xml:"nickname,omitempty" json:"nickname,omitempty"` + + Password string `xml:"password,omitempty" json:"password,omitempty"` +} + +type CreateUpdateUserResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateUpdateUserResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *UpdateUser `xml:"data,omitempty" json:"data,omitempty"` +} + +type AddDDNSRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddDDNSRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Record_id int64 `xml:"record_id,omitempty" json:"record_id,omitempty"` +} + +type AddDDNSResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ AddDDNSResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DDNSData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateFailoverRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateFailoverRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // normally served address + Address string `xml:"address,omitempty" json:"address,omitempty"` + + // TTL (time-to-live) + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + // 'ip' or 'cname' + Failover_mode string `xml:"failover_mode,omitempty" json:"failover_mode,omitempty"` + + // address or CNAME to serve on failover + Failover_data string `xml:"failover_data,omitempty" json:"failover_data,omitempty"` + + // restore normal address automatically (Y) + Auto_recover string `xml:"auto_recover,omitempty" json:"auto_recover,omitempty"` + + // The number of consecutive monitoring intervals to delay before placing an IP address back in service + Recovery_delay int32 `xml:"recovery_delay,omitempty" json:"recovery_delay,omitempty"` + + // contact that gets status notification + Contact_nickname string `xml:"contact_nickname,omitempty" json:"contact_nickname,omitempty"` + + // when notifications are sent + Notify_events string `xml:"notify_events,omitempty" json:"notify_events,omitempty"` + + // The IP or hostname of a syslog server to send monitor events to + Syslog_server string `xml:"syslog_server,omitempty" json:"syslog_server,omitempty"` + + // The port of the syslog server. Defaults to 514 if not present + Syslog_port string `xml:"syslog_port,omitempty" json:"syslog_port,omitempty"` + + // The syslog ident to use. Defaults to 'dynect' + Syslog_ident string `xml:"syslog_ident,omitempty" json:"syslog_ident,omitempty"` + + // The syslog facility to use. Defaults to 'daemon' + Syslog_facility string `xml:"syslog_facility,omitempty" json:"syslog_facility,omitempty"` + + // When to deliver syslog message; 'change' or 'all' + Syslog_delivery string `xml:"syslog_delivery,omitempty" json:"syslog_delivery,omitempty"` + + // for custom syslog messages + Syslog_probe_fmt string `xml:"syslog_probe_fmt,omitempty" json:"syslog_probe_fmt,omitempty"` + + // for custom syslog messages + Syslog_status_fmt string `xml:"syslog_status_fmt,omitempty" json:"syslog_status_fmt,omitempty"` + + // details about monitoring + Monitor *MonitorData `xml:"monitor,omitempty" json:"monitor,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type CreateFailoverResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateFailoverResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *FailoverData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneFailoverRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneFailoverRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneFailoverResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneFailoverResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *FailoverData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetFailoversRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetFailoversRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetFailoversResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetFailoversResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*FailoverData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateFailoverRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateFailoverRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // normally served address + Address string `xml:"address,omitempty" json:"address,omitempty"` + + // TTL (time-to-live) + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + // 'ip' or 'cname' + Failover_mode string `xml:"failover_mode,omitempty" json:"failover_mode,omitempty"` + + // address or CNAME to serve on failover + Failover_data string `xml:"failover_data,omitempty" json:"failover_data,omitempty"` + + // restore normal address automatically (Y) + Auto_recover string `xml:"auto_recover,omitempty" json:"auto_recover,omitempty"` + + // The number of consecutive monitoring intervals to delay before placing an IP address back in service + Recovery_delay int32 `xml:"recovery_delay,omitempty" json:"recovery_delay,omitempty"` + + // contact that gets status notification + Contact_nickname string `xml:"contact_nickname,omitempty" json:"contact_nickname,omitempty"` + + // when notifications are sent + Notify_events string `xml:"notify_events,omitempty" json:"notify_events,omitempty"` + + // The IP or hostname of a syslog server to send monitor events to + Syslog_server string `xml:"syslog_server,omitempty" json:"syslog_server,omitempty"` + + // The port of the syslog server. Defaults to 514 if not present + Syslog_port string `xml:"syslog_port,omitempty" json:"syslog_port,omitempty"` + + // The syslog ident to use. Defaults to 'dynect' + Syslog_ident string `xml:"syslog_ident,omitempty" json:"syslog_ident,omitempty"` + + // The syslog facility to use. Defaults to 'daemon' + Syslog_facility string `xml:"syslog_facility,omitempty" json:"syslog_facility,omitempty"` + + // When to deliver syslog message; 'change' or 'all' + Syslog_delivery string `xml:"syslog_delivery,omitempty" json:"syslog_delivery,omitempty"` + + // for custom syslog messages + Syslog_probe_fmt string `xml:"syslog_probe_fmt,omitempty" json:"syslog_probe_fmt,omitempty"` + + // for custom syslog messages + Syslog_status_fmt string `xml:"syslog_status_fmt,omitempty" json:"syslog_status_fmt,omitempty"` + + // details about monitoring + Monitor *MonitorData `xml:"monitor,omitempty" json:"monitor,omitempty"` +} + +type UpdateFailoverResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateFailoverResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *FailoverData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneFailoverRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneFailoverRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type DeleteOneFailoverResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneFailoverResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type ActivateFailoverRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ActivateFailoverRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type ActivateFailoverResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ActivateFailoverResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *FailoverData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeactivateFailoverRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeactivateFailoverRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type DeactivateFailoverResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeactivateFailoverResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *FailoverData `xml:"data,omitempty" json:"data,omitempty"` +} + +type RecoverFailoverRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RecoverFailoverRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type RecoverFailoverResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RecoverFailoverResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *FailoverData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateLoadBalanceRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateLoadBalanceRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // pool of IP addresses to balance + Pool []*LoadBalanceAddress `xml:"pool,omitempty" json:"pool,omitempty"` + + // TTL (time-to-live) + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + // 'ip', 'global', or 'cname' + Failover_mode string `xml:"failover_mode,omitempty" json:"failover_mode,omitempty"` + + // for 'ip' or 'cname', what to serve on failover + Failover_data string `xml:"failover_data,omitempty" json:"failover_data,omitempty"` + + // restore normal address automatically (Y) + Auto_recover string `xml:"auto_recover,omitempty" json:"auto_recover,omitempty"` + + // The number of consecutive monitoring intervals to delay before placing an IP address back in service + Recovery_delay int32 `xml:"recovery_delay,omitempty" json:"recovery_delay,omitempty"` + + // contact that gets status notification + Contact_nickname string `xml:"contact_nickname,omitempty" json:"contact_nickname,omitempty"` + + // when notifications are sent + Notify_events string `xml:"notify_events,omitempty" json:"notify_events,omitempty"` + + // The IP or hostname of a syslog server to send monitor events to + Syslog_server string `xml:"syslog_server,omitempty" json:"syslog_server,omitempty"` + + // The port of the syslog server. Defaults to 514 if not present + Syslog_port string `xml:"syslog_port,omitempty" json:"syslog_port,omitempty"` + + // The syslog ident to use. Defaults to 'dynect' + Syslog_ident string `xml:"syslog_ident,omitempty" json:"syslog_ident,omitempty"` + + // The syslog facility to use. Defaults to 'daemon' + Syslog_facility string `xml:"syslog_facility,omitempty" json:"syslog_facility,omitempty"` + + // When to deliver syslog message; 'change' or 'all' + Syslog_delivery string `xml:"syslog_delivery,omitempty" json:"syslog_delivery,omitempty"` + + // for custom syslog messages + Syslog_probe_fmt string `xml:"syslog_probe_fmt,omitempty" json:"syslog_probe_fmt,omitempty"` + + // for custom syslog messages + Syslog_status_fmt string `xml:"syslog_status_fmt,omitempty" json:"syslog_status_fmt,omitempty"` + + // number of addresses in each DNS response + Serve_count int32 `xml:"serve_count,omitempty" json:"serve_count,omitempty"` + + // details about monitoring + Monitor *MonitorData `xml:"monitor,omitempty" json:"monitor,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type CreateLoadBalanceResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateLoadBalanceResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *LoadBalanceData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneLoadBalanceRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneLoadBalanceRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneLoadBalanceResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneLoadBalanceResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *LoadBalanceData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetLoadBalancesRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetLoadBalancesRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetLoadBalancesResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetLoadBalancesResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*LoadBalanceData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateLoadBalanceRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateLoadBalanceRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // pool of IP addresses to balance + Pool []*LoadBalanceAddress `xml:"pool,omitempty" json:"pool,omitempty"` + + // TTL (time-to-live) + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + // 'ip', 'global', or 'cname' + Failover_mode string `xml:"failover_mode,omitempty" json:"failover_mode,omitempty"` + + // for 'ip' or 'cname', what to serve on failover + Failover_data string `xml:"failover_data,omitempty" json:"failover_data,omitempty"` + + // restore normal address automatically (Y) + Auto_recover string `xml:"auto_recover,omitempty" json:"auto_recover,omitempty"` + + // The number of consecutive monitoring intervals to delay before placing an IP address back in service + Recovery_delay int32 `xml:"recovery_delay,omitempty" json:"recovery_delay,omitempty"` + + // contact that gets status notification + Contact_nickname string `xml:"contact_nickname,omitempty" json:"contact_nickname,omitempty"` + + // when notifications are sent + Notify_events string `xml:"notify_events,omitempty" json:"notify_events,omitempty"` + + // The IP or hostname of a syslog server to send monitor events to + Syslog_server string `xml:"syslog_server,omitempty" json:"syslog_server,omitempty"` + + // The port of the syslog server. Defaults to 514 if not present + Syslog_port string `xml:"syslog_port,omitempty" json:"syslog_port,omitempty"` + + // The syslog ident to use. Defaults to 'dynect' + Syslog_ident string `xml:"syslog_ident,omitempty" json:"syslog_ident,omitempty"` + + // The syslog facility to use. Defaults to 'daemon' + Syslog_facility string `xml:"syslog_facility,omitempty" json:"syslog_facility,omitempty"` + + // When to deliver syslog message; 'change' or 'all' + Syslog_delivery string `xml:"syslog_delivery,omitempty" json:"syslog_delivery,omitempty"` + + // for custom syslog messages + Syslog_probe_fmt string `xml:"syslog_probe_fmt,omitempty" json:"syslog_probe_fmt,omitempty"` + + // for custom syslog messages + Syslog_status_fmt string `xml:"syslog_status_fmt,omitempty" json:"syslog_status_fmt,omitempty"` + + // number of addresses in each DNS response + Serve_count int32 `xml:"serve_count,omitempty" json:"serve_count,omitempty"` + + // details about monitoring + Monitor *MonitorData `xml:"monitor,omitempty" json:"monitor,omitempty"` +} + +type UpdateLoadBalanceResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateLoadBalanceResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *LoadBalanceData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneLoadBalanceRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneLoadBalanceRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type DeleteOneLoadBalanceResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneLoadBalanceResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type ActivateLoadBalanceRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ActivateLoadBalanceRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type ActivateLoadBalanceResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ActivateLoadBalanceResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *LoadBalanceData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeactivateLoadBalanceRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeactivateLoadBalanceRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type DeactivateLoadBalanceResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeactivateLoadBalanceResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *LoadBalanceData `xml:"data,omitempty" json:"data,omitempty"` +} + +type RecoverLoadBalanceRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RecoverLoadBalanceRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type RecoverLoadBalanceResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RecoverLoadBalanceResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *LoadBalanceData `xml:"data,omitempty" json:"data,omitempty"` +} + +type RecoverLoadBalanceIPRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RecoverLoadBalanceIPRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Address string `xml:"address,omitempty" json:"address,omitempty"` +} + +type RecoverLoadBalanceIPResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RecoverLoadBalanceIPResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *LoadBalanceData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateLoadBalancePoolEntryRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateLoadBalancePoolEntryRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // an IP address to monitor and publish + Address string `xml:"address,omitempty" json:"address,omitempty"` + + // a human-readable label + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // how often this is served relative to others in pool + Weight int32 `xml:"weight,omitempty" json:"weight,omitempty"` + + // how this address reponds to monitoring: obey,remove,always,no + Serve_mode string `xml:"serve_mode,omitempty" json:"serve_mode,omitempty"` +} + +type CreateLoadBalancePoolEntryResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateLoadBalancePoolEntryResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *LoadBalancePoolEntry `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateLoadBalancePoolEntryRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateLoadBalancePoolEntryRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // The IP of the pool entry to update + Address string `xml:"address,omitempty" json:"address,omitempty"` + + // If specified, the new IP address for this entry + New_address string `xml:"new_address,omitempty" json:"new_address,omitempty"` + + // a human-readable label + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // how often this is served relative to others in pool + Weight int32 `xml:"weight,omitempty" json:"weight,omitempty"` + + // how this address reponds to monitoring: obey,remove,always,no + Serve_mode string `xml:"serve_mode,omitempty" json:"serve_mode,omitempty"` +} + +type UpdateLoadBalancePoolEntryResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateLoadBalancePoolEntryResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *LoadBalancePoolEntry `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneLoadBalancePoolEntryRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneLoadBalancePoolEntryRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // The IP of the pool entry to get + Address string `xml:"address,omitempty" json:"address,omitempty"` +} + +type GetOneLoadBalancePoolEntryResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneLoadBalancePoolEntryResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *LoadBalancePoolEntry `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetLoadBalancePoolEntriesRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetLoadBalancePoolEntriesRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetLoadBalancePoolEntriesResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetLoadBalancePoolEntriesResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*LoadBalancePoolEntry `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneLoadBalancePoolEntryRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneLoadBalancePoolEntryRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // The IP of the pool entry to delete + Address string `xml:"address,omitempty" json:"address,omitempty"` +} + +type DeleteOneLoadBalancePoolEntryResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneLoadBalancePoolEntryResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateGSLBRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateGSLBRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // per-region addresses and configuration + Region []*GSLBRegion `xml:"region,omitempty" json:"region,omitempty"` + + // TTL (time-to-live) + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + // restore normal address automatically (Y) + Auto_recover string `xml:"auto_recover,omitempty" json:"auto_recover,omitempty"` + + // The number of consecutive monitoring intervals to delay before placing an IP address back in service + Recovery_delay int32 `xml:"recovery_delay,omitempty" json:"recovery_delay,omitempty"` + + // contact that gets status notification + Contact_nickname string `xml:"contact_nickname,omitempty" json:"contact_nickname,omitempty"` + + // when notifications are sent + Notify_events string `xml:"notify_events,omitempty" json:"notify_events,omitempty"` + + // The IP or hostname of a syslog server to send monitor events to + Syslog_server string `xml:"syslog_server,omitempty" json:"syslog_server,omitempty"` + + // The port of the syslog server. Defaults to 514 if not present + Syslog_port string `xml:"syslog_port,omitempty" json:"syslog_port,omitempty"` + + // The syslog ident to use. Defaults to 'dynect' + Syslog_ident string `xml:"syslog_ident,omitempty" json:"syslog_ident,omitempty"` + + // The syslog facility to use. Defaults to 'daemon' + Syslog_facility string `xml:"syslog_facility,omitempty" json:"syslog_facility,omitempty"` + + // When to deliver syslog message; 'change' or 'all' + Syslog_delivery string `xml:"syslog_delivery,omitempty" json:"syslog_delivery,omitempty"` + + // for custom syslog messages + Syslog_probe_fmt string `xml:"syslog_probe_fmt,omitempty" json:"syslog_probe_fmt,omitempty"` + + // for custom syslog messages + Syslog_status_fmt string `xml:"syslog_status_fmt,omitempty" json:"syslog_status_fmt,omitempty"` + + // details about monitoring + Monitor *MonitorData `xml:"monitor,omitempty" json:"monitor,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type CreateGSLBResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateGSLBResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *GSLBData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneGSLBRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneGSLBRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneGSLBResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneGSLBResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *GSLBData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetGSLBsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetGSLBsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetGSLBsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetGSLBsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*GSLBData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateGSLBRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateGSLBRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // per-region addresses and configuration + Region []*GSLBRegion `xml:"region,omitempty" json:"region,omitempty"` + + // TTL (time-to-live) + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + // restore normal address automatically (Y) + Auto_recover string `xml:"auto_recover,omitempty" json:"auto_recover,omitempty"` + + // The number of consecutive monitoring intervals to delay before placing an IP address back in service + Recovery_delay int32 `xml:"recovery_delay,omitempty" json:"recovery_delay,omitempty"` + + // contact that gets status notification + Contact_nickname string `xml:"contact_nickname,omitempty" json:"contact_nickname,omitempty"` + + // when notifications are sent + Notify_events string `xml:"notify_events,omitempty" json:"notify_events,omitempty"` + + // The IP or hostname of a syslog server to send monitor events to + Syslog_server string `xml:"syslog_server,omitempty" json:"syslog_server,omitempty"` + + // The port of the syslog server. Defaults to 514 if not present + Syslog_port string `xml:"syslog_port,omitempty" json:"syslog_port,omitempty"` + + // The syslog ident to use. Defaults to 'dynect' + Syslog_ident string `xml:"syslog_ident,omitempty" json:"syslog_ident,omitempty"` + + // The syslog facility to use. Defaults to 'daemon' + Syslog_facility string `xml:"syslog_facility,omitempty" json:"syslog_facility,omitempty"` + + // When to deliver syslog message; 'change' or 'all' + Syslog_delivery string `xml:"syslog_delivery,omitempty" json:"syslog_delivery,omitempty"` + + // for custom syslog messages + Syslog_probe_fmt string `xml:"syslog_probe_fmt,omitempty" json:"syslog_probe_fmt,omitempty"` + + // for custom syslog messages + Syslog_status_fmt string `xml:"syslog_status_fmt,omitempty" json:"syslog_status_fmt,omitempty"` + + // details about monitoring + Monitor *MonitorData `xml:"monitor,omitempty" json:"monitor,omitempty"` +} + +type UpdateGSLBResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateGSLBResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *GSLBData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneGSLBRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneGSLBRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type DeleteOneGSLBResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneGSLBResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type ActivateGSLBRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ActivateGSLBRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type ActivateGSLBResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ActivateGSLBResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *GSLBData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeactivateGSLBRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeactivateGSLBRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type DeactivateGSLBResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeactivateGSLBResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *GSLBData `xml:"data,omitempty" json:"data,omitempty"` +} + +type RecoverGSLBRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RecoverGSLBRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type RecoverGSLBResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RecoverGSLBResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *GSLBData `xml:"data,omitempty" json:"data,omitempty"` +} + +type RecoverGSLBIPRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RecoverGSLBIPRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Address string `xml:"address,omitempty" json:"address,omitempty"` +} + +type RecoverGSLBIPResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RecoverGSLBIPResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *GSLBData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateGSLBRegionRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateGSLBRegionRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // 'global' or specific region code: 'US West', 'US Central', 'US East', 'EU West', 'EU Central', 'Asia', + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` + + // 'ip', 'global', or 'cname' + Failover_mode string `xml:"failover_mode,omitempty" json:"failover_mode,omitempty"` + + // for 'ip' or 'cname', what to serve on failover + Failover_data string `xml:"failover_data,omitempty" json:"failover_data,omitempty"` + + // number of addresses in each DNS response + Serve_count int32 `xml:"serve_count,omitempty" json:"serve_count,omitempty"` + + // number of 'ok' addresses before region fails over + Min_healthy int32 `xml:"min_healthy,omitempty" json:"min_healthy,omitempty"` + + // pool of IP addresses to balance + Pool []*GSLBAddress `xml:"pool,omitempty" json:"pool,omitempty"` +} + +type CreateGSLBRegionResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateGSLBRegionResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *GSLBRegionData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneGSLBRegionRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneGSLBRegionRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneGSLBRegionResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneGSLBRegionResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *GSLBRegionData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetGSLBRegionsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetGSLBRegionsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetGSLBRegionsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetGSLBRegionsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*GSLBRegionData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateGSLBRegionRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateGSLBRegionRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // 'ip', 'global', or 'cname' + Failover_mode string `xml:"failover_mode,omitempty" json:"failover_mode,omitempty"` + + // for 'ip' or 'cname', what to serve on failover + Failover_data string `xml:"failover_data,omitempty" json:"failover_data,omitempty"` + + // number of addresses in each DNS response + Serve_count int32 `xml:"serve_count,omitempty" json:"serve_count,omitempty"` + + // number of 'ok' addresses before region fails over + Min_healthy int32 `xml:"min_healthy,omitempty" json:"min_healthy,omitempty"` + + // pool of IP addresses to balance + Pool []*GSLBAddress `xml:"pool,omitempty" json:"pool,omitempty"` +} + +type UpdateGSLBRegionResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateGSLBRegionResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *GSLBRegionData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneGSLBRegionRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneGSLBRegionRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type DeleteOneGSLBRegionResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneGSLBRegionResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateGSLBRegionPoolEntryRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateGSLBRegionPoolEntryRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // 'global' or specific region code: 'US West', 'US Central', 'US East', 'EU West', 'EU Central', 'Asia', + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` + + // an IP address or FQDN to monitor and publish + Address string `xml:"address,omitempty" json:"address,omitempty"` + + // a human-readable label + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // how often this is served relative to others in pool + Weight int32 `xml:"weight,omitempty" json:"weight,omitempty"` + + // how this address reponds to monitoring: obey,remove,always,no + Serve_mode string `xml:"serve_mode,omitempty" json:"serve_mode,omitempty"` +} + +type CreateGSLBRegionPoolEntryResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateGSLBRegionPoolEntryResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *GSLBRegionPoolEntry `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateGSLBRegionPoolEntryRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateGSLBRegionPoolEntryRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // 'global' or specific region code: 'US West', 'US Central', 'US East', 'EU West', 'EU Central', 'Asia', + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` + + // The IP address or FQDN of the pool entry to update + Address string `xml:"address,omitempty" json:"address,omitempty"` + + // If specified, the new IP address for this entry + New_address string `xml:"new_address,omitempty" json:"new_address,omitempty"` + + // a human-readable label + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // how often this is served relative to others in pool + Weight int32 `xml:"weight,omitempty" json:"weight,omitempty"` + + // how this address reponds to monitoring: obey,remove,always,no + Serve_mode string `xml:"serve_mode,omitempty" json:"serve_mode,omitempty"` +} + +type UpdateGSLBRegionPoolEntryResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateGSLBRegionPoolEntryResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *GSLBRegionPoolEntry `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneGSLBRegionPoolEntryRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneGSLBRegionPoolEntryRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // 'global' or specific region code: 'US West', 'US Central', 'US East', 'EU West', 'EU Central', 'Asia', + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` + + // The IP address or FQDN of the pool entry to get + Address string `xml:"address,omitempty" json:"address,omitempty"` +} + +type GetOneGSLBRegionPoolEntryResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneGSLBRegionPoolEntryResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *GSLBRegionPoolEntry `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetGSLBRegionPoolEntriesRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetGSLBRegionPoolEntriesRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // 'global' or specific region code: 'US West', 'US Central', 'US East', 'EU West', 'EU Central', 'Asia', + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` +} + +type GetGSLBRegionPoolEntriesResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetGSLBRegionPoolEntriesResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*GSLBRegionPoolEntry `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneGSLBRegionPoolEntryRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneGSLBRegionPoolEntryRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // 'global' or specific region code: 'US West', 'US Central', 'US East', 'EU West', 'EU Central', 'Asia', + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` + + // The IP of the pool entry to delete + Address string `xml:"address,omitempty" json:"address,omitempty"` +} + +type DeleteOneGSLBRegionPoolEntryResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneGSLBRegionPoolEntryResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateRTTMRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateRTTMRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // per-region addresses and configuration + Region []*RTTMRegion `xml:"region,omitempty" json:"region,omitempty"` + + // TTL (time-to-live) + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + // restore normal address automatically (Y) + Auto_recover string `xml:"auto_recover,omitempty" json:"auto_recover,omitempty"` + + // The number of consecutive monitoring intervals to delay before placing an IP address back in service + Recovery_delay int32 `xml:"recovery_delay,omitempty" json:"recovery_delay,omitempty"` + + // contact that gets status notification + Contact_nickname string `xml:"contact_nickname,omitempty" json:"contact_nickname,omitempty"` + + // when notifications are sent + Notify_events string `xml:"notify_events,omitempty" json:"notify_events,omitempty"` + + // The IP or hostname of a syslog server to send monitor events to + Syslog_server string `xml:"syslog_server,omitempty" json:"syslog_server,omitempty"` + + // The port of the syslog server. Defaults to 514 if not present + Syslog_port string `xml:"syslog_port,omitempty" json:"syslog_port,omitempty"` + + // The syslog ident to use. Defaults to 'dynect' + Syslog_ident string `xml:"syslog_ident,omitempty" json:"syslog_ident,omitempty"` + + // The syslog facility to use. Defaults to 'daemon' + Syslog_facility string `xml:"syslog_facility,omitempty" json:"syslog_facility,omitempty"` + + // When to deliver syslog message; 'change' or 'all' + Syslog_delivery string `xml:"syslog_delivery,omitempty" json:"syslog_delivery,omitempty"` + + // for custom syslog messages + Syslog_probe_fmt string `xml:"syslog_probe_fmt,omitempty" json:"syslog_probe_fmt,omitempty"` + + // for custom syslog messages + Syslog_status_fmt string `xml:"syslog_status_fmt,omitempty" json:"syslog_status_fmt,omitempty"` + + // for custom syslog messages + Syslog_rttm_fmt string `xml:"syslog_rttm_fmt,omitempty" json:"syslog_rttm_fmt,omitempty"` + + // details about monitoring + Monitor *MonitorData `xml:"monitor,omitempty" json:"monitor,omitempty"` + + // details about performance monitoring + Performance_monitor *MonitorData `xml:"performance_monitor,omitempty" json:"performance_monitor,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type CreateRTTMResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateRTTMResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *RTTMData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneRTTMRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneRTTMRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneRTTMResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneRTTMResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *RTTMData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetRTTMsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetRTTMsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetRTTMsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetRTTMsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*RTTMData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateRTTMRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateRTTMRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // per-region addresses and configuration + Region []*RTTMRegion `xml:"region,omitempty" json:"region,omitempty"` + + // TTL (time-to-live) + Ttl int32 `xml:"ttl,omitempty" json:"ttl,omitempty"` + + // restore normal address automatically (Y) + Auto_recover string `xml:"auto_recover,omitempty" json:"auto_recover,omitempty"` + + // The number of consecutive monitoring intervals to delay before placing an IP address back in service + Recovery_delay int32 `xml:"recovery_delay,omitempty" json:"recovery_delay,omitempty"` + + // contact that gets status notification + Contact_nickname string `xml:"contact_nickname,omitempty" json:"contact_nickname,omitempty"` + + // when notifications are sent + Notify_events string `xml:"notify_events,omitempty" json:"notify_events,omitempty"` + + // The IP or hostname of a syslog server to send monitor events to + Syslog_server string `xml:"syslog_server,omitempty" json:"syslog_server,omitempty"` + + // The port of the syslog server. Defaults to 514 if not present + Syslog_port string `xml:"syslog_port,omitempty" json:"syslog_port,omitempty"` + + // The syslog ident to use. Defaults to 'dynect' + Syslog_ident string `xml:"syslog_ident,omitempty" json:"syslog_ident,omitempty"` + + // The syslog facility to use. Defaults to 'daemon' + Syslog_facility string `xml:"syslog_facility,omitempty" json:"syslog_facility,omitempty"` + + // When to deliver syslog message; 'change' or 'all' + Syslog_delivery string `xml:"syslog_delivery,omitempty" json:"syslog_delivery,omitempty"` + + // for custom syslog messages + Syslog_probe_fmt string `xml:"syslog_probe_fmt,omitempty" json:"syslog_probe_fmt,omitempty"` + + // for custom syslog messages + Syslog_status_fmt string `xml:"syslog_status_fmt,omitempty" json:"syslog_status_fmt,omitempty"` + + // for custom syslog messages + Syslog_rttm_fmt string `xml:"syslog_rttm_fmt,omitempty" json:"syslog_rttm_fmt,omitempty"` + + // details about monitoring + Monitor *MonitorData `xml:"monitor,omitempty" json:"monitor,omitempty"` + + // details about performance monitoring + Performance_monitor *MonitorData `xml:"performance_monitor,omitempty" json:"performance_monitor,omitempty"` +} + +type UpdateRTTMResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateRTTMResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *RTTMData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneRTTMRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneRTTMRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type DeleteOneRTTMResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneRTTMResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type ActivateRTTMRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ActivateRTTMRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type ActivateRTTMResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ActivateRTTMResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *RTTMData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeactivateRTTMRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeactivateRTTMRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type DeactivateRTTMResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeactivateRTTMResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *RTTMData `xml:"data,omitempty" json:"data,omitempty"` +} + +type RecoverRTTMRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RecoverRTTMRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type RecoverRTTMResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RecoverRTTMResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *RTTMData `xml:"data,omitempty" json:"data,omitempty"` +} + +type RecoverRTTMIPRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RecoverRTTMIPRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Address string `xml:"address,omitempty" json:"address,omitempty"` +} + +type RecoverRTTMIPResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RecoverRTTMIPResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *RTTMData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetRTTMLogsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetRTTMLogsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // The timestamp indicating the beginning of the period to report on + Start_ts int32 `xml:"start_ts,omitempty" json:"start_ts,omitempty"` + + // The timestamp indicating the end of the period to report on + End_ts int32 `xml:"end_ts,omitempty" json:"end_ts,omitempty"` +} + +type GetRTTMLogsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetRTTMLogsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*RTTMLogData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetRTTMRRSetsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetRTTMRRSetsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // The timestamp indicating the period to report on + Ts int32 `xml:"ts,omitempty" json:"ts,omitempty"` +} + +type GetRTTMRRSetsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetRTTMRRSetsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*RTTMLogData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateRTTMRegionRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateRTTMRegionRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // 'global' or specific region code: 'US West', 'US Central', 'US East', 'EU West', 'EU Central', 'Asia', + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` + + // 'Y' or 'N', if 'Y', region will filled in with global settings + Autopopulate string `xml:"autopopulate,omitempty" json:"autopopulate,omitempty"` + + // number of addresses in each DNS response + Serve_count int32 `xml:"serve_count,omitempty" json:"serve_count,omitempty"` + + // pool_count, number of addresses to be included in the serve pool + Ep int32 `xml:"ep,omitempty" json:"ep,omitempty"` + + // 'ip', 'global', 'region', default 'global' + Failover_mode string `xml:"failover_mode,omitempty" json:"failover_mode,omitempty"` + + // for 'ip' mode, address to serve on failover. For 'region' mode, region_code of the region to failover to. + Failover_data string `xml:"failover_data,omitempty" json:"failover_data,omitempty"` + + // failover_count, number of addresses that must be 'ok', otherwise a region is considered 'failover' + Apmc int32 `xml:"apmc,omitempty" json:"apmc,omitempty"` + + // failover_count2, number of addresses that must be 'ok', otherwise a region is considered 'failover' + Epmc int32 `xml:"epmc,omitempty" json:"epmc,omitempty"` + + // pool of IP addresses to balance + Pool []*RTTMAddress `xml:"pool,omitempty" json:"pool,omitempty"` +} + +type CreateRTTMRegionResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateRTTMRegionResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *RTTMRegionData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneRTTMRegionRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneRTTMRegionRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneRTTMRegionResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneRTTMRegionResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *RTTMRegionData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetRTTMRegionsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetRTTMRegionsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetRTTMRegionsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetRTTMRegionsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*RTTMRegionData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateRTTMRegionRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateRTTMRegionRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // 'Y' or 'N', if 'Y', region will filled in with global settings + Autopopulate string `xml:"autopopulate,omitempty" json:"autopopulate,omitempty"` + + // number of addresses in each DNS response + Serve_count int32 `xml:"serve_count,omitempty" json:"serve_count,omitempty"` + + // pool_count, number of addresses to be included in the serve pool + Ep int32 `xml:"ep,omitempty" json:"ep,omitempty"` + + // 'ip', 'global', 'region', default 'global' + Failover_mode string `xml:"failover_mode,omitempty" json:"failover_mode,omitempty"` + + // for 'ip' mode, address to serve on failover. For 'region' mode, region_code of the region to failover to. + Failover_data string `xml:"failover_data,omitempty" json:"failover_data,omitempty"` + + // failover_count, number of addresses that must be 'ok', otherwise a region is considered 'failover' + Apmc int32 `xml:"apmc,omitempty" json:"apmc,omitempty"` + + // failover_count2, number of addresses that must be 'ok', otherwise a region is considered 'failover' + Epmc int32 `xml:"epmc,omitempty" json:"epmc,omitempty"` + + // pool of IP addresses to balance + Pool []*RTTMAddress `xml:"pool,omitempty" json:"pool,omitempty"` +} + +type UpdateRTTMRegionResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateRTTMRegionResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *RTTMRegionData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneRTTMRegionRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneRTTMRegionRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type DeleteOneRTTMRegionResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneRTTMRegionResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateRTTMRegionPoolEntryRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateRTTMRegionPoolEntryRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // 'global' or specific region code: 'US West', 'US Central', 'US East', 'EU West', 'EU Central', 'Asia', + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` + + // an IP address to monitor and publish + Address string `xml:"address,omitempty" json:"address,omitempty"` + + // a human-readable label + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // how often this is served relative to others in pool + Weight int32 `xml:"weight,omitempty" json:"weight,omitempty"` + + // how this address reponds to monitoring: obey,remove,always,no + Serve_mode string `xml:"serve_mode,omitempty" json:"serve_mode,omitempty"` +} + +type CreateRTTMRegionPoolEntryResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateRTTMRegionPoolEntryResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *RTTMRegionPoolEntry `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateRTTMRegionPoolEntryRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateRTTMRegionPoolEntryRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // 'global' or specific region code: 'US West', 'US Central', 'US East', 'EU West', 'EU Central', 'Asia', + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` + + // The IP of the pool entry to update + Address string `xml:"address,omitempty" json:"address,omitempty"` + + // If specified, the new IP address for this entry + New_address string `xml:"new_address,omitempty" json:"new_address,omitempty"` + + // a human-readable label + Label string `xml:"label,omitempty" json:"label,omitempty"` + + // how often this is served relative to others in pool + Weight int32 `xml:"weight,omitempty" json:"weight,omitempty"` + + // how this address reponds to monitoring: obey,remove,always,no + Serve_mode string `xml:"serve_mode,omitempty" json:"serve_mode,omitempty"` +} + +type UpdateRTTMRegionPoolEntryResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateRTTMRegionPoolEntryResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *RTTMRegionPoolEntry `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneRTTMRegionPoolEntryRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneRTTMRegionPoolEntryRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // 'global' or specific region code: 'US West', 'US Central', 'US East', 'EU West', 'EU Central', 'Asia', + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` + + // The IP of the pool entry to get + Address string `xml:"address,omitempty" json:"address,omitempty"` +} + +type GetOneRTTMRegionPoolEntryResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneRTTMRegionPoolEntryResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *RTTMRegionPoolEntry `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetRTTMRegionPoolEntriesRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetRTTMRegionPoolEntriesRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // 'global' or specific region code: 'US West', 'US Central', 'US East', 'EU West', 'EU Central', 'Asia', + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` +} + +type GetRTTMRegionPoolEntriesResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetRTTMRegionPoolEntriesResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*RTTMRegionPoolEntry `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneRTTMRegionPoolEntryRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneRTTMRegionPoolEntryRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // 'global' or specific region code: 'US West', 'US Central', 'US East', 'EU West', 'EU Central', 'Asia', + Region_code string `xml:"region_code,omitempty" json:"region_code,omitempty"` + + // The IP of the pool entry to delete + Address string `xml:"address,omitempty" json:"address,omitempty"` +} + +type DeleteOneRTTMRegionPoolEntryResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneRTTMRegionPoolEntryResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateHTTPRedirectRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateHTTPRedirectRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // URL requests are redirecto to + Url string `xml:"url,omitempty" json:"url,omitempty"` + + // either '301' (temporary) or '302' (permanent) + Code string `xml:"code,omitempty" json:"code,omitempty"` + + // should redirected URL include requested URL + Keep_uri string `xml:"keep_uri,omitempty" json:"keep_uri,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type CreateHTTPRedirectResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateHTTPRedirectResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *HTTPRedirectData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneHTTPRedirectRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneHTTPRedirectRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneHTTPRedirectResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneHTTPRedirectResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *HTTPRedirectData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetHTTPRedirectsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetHTTPRedirectsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetHTTPRedirectsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetHTTPRedirectsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*HTTPRedirectData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateHTTPRedirectRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateHTTPRedirectRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // URL requests are redirecto to + Url string `xml:"url,omitempty" json:"url,omitempty"` + + // either '301' (temporary) or '302' (permanent) + Code string `xml:"code,omitempty" json:"code,omitempty"` + + // should redirected URL include requested URL + Keep_uri string `xml:"keep_uri,omitempty" json:"keep_uri,omitempty"` +} + +type UpdateHTTPRedirectResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateHTTPRedirectResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *HTTPRedirectData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneHTTPRedirectRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneHTTPRedirectRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + Publish string `xml:"publish,omitempty" json:"publish,omitempty"` +} + +type DeleteOneHTTPRedirectResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneHTTPRedirectResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateAdvRedirectRuleRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateAdvRedirectRuleRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // either '301' (temporary) or '302' (permanent) + Code string `xml:"code,omitempty" json:"code,omitempty"` + + // host portion of URL to match + Host_prefix string `xml:"host_prefix,omitempty" json:"host_prefix,omitempty"` + + // path portion of URL to match + Path string `xml:"path,omitempty" json:"path,omitempty"` + + // replacement pattern + Url_pattern string `xml:"url_pattern,omitempty" json:"url_pattern,omitempty"` + + // 'Y'/'N', default 'Y' + Active string `xml:"active,omitempty" json:"active,omitempty"` + + // Public ID of next AdvRedirect rule to be processed. (default to end of list) + Next_public_id string `xml:"next_public_id,omitempty" json:"next_public_id,omitempty"` +} + +type CreateAdvRedirectRuleResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateAdvRedirectRuleResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *AdvRedirectRuleData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateAdvRedirectRuleRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateAdvRedirectRuleRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // public_id of Rule + Public_id string `xml:"public_id,omitempty" json:"public_id,omitempty"` + + // either '301' (temporary) or '302' (permanent) + Code string `xml:"code,omitempty" json:"code,omitempty"` + + // host portion of URL to match + Host_prefix string `xml:"host_prefix,omitempty" json:"host_prefix,omitempty"` + + // path portion of URL to match + Path string `xml:"path,omitempty" json:"path,omitempty"` + + // replacement pattern + Url_pattern string `xml:"url_pattern,omitempty" json:"url_pattern,omitempty"` + + // 'Y'/'N', default 'Y' + Active string `xml:"active,omitempty" json:"active,omitempty"` + + // Public ID of next AdvRedirect rule to be processed. (default to end of list) + Next_public_id string `xml:"next_public_id,omitempty" json:"next_public_id,omitempty"` +} + +type UpdateAdvRedirectRuleResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateAdvRedirectRuleResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *AdvRedirectRuleData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneAdvRedirectRuleRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneAdvRedirectRuleRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // public_id of Rule + Public_id string `xml:"public_id,omitempty" json:"public_id,omitempty"` +} + +type GetOneAdvRedirectRuleResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneAdvRedirectRuleResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *AdvRedirectRuleData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetAdvRedirectRulesRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetAdvRedirectRulesRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetAdvRedirectRulesResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetAdvRedirectRulesResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*AdvRedirectRuleData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneAdvRedirectRuleRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneAdvRedirectRuleRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // public_id of Rule + Public_id string `xml:"public_id,omitempty" json:"public_id,omitempty"` +} + +type DeleteOneAdvRedirectRuleResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneAdvRedirectRuleResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *AdvRedirectRuleData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateAdvRedirectRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateAdvRedirectRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // 'Y'/'N', default 'Y' + Active string `xml:"active,omitempty" json:"active,omitempty"` + + // List of AdvRedirectRules + Rules []*AdvRedirectRuleData `xml:"rules,omitempty" json:"rules,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type CreateAdvRedirectResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateAdvRedirectResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *AdvRedirectData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneAdvRedirectRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneAdvRedirectRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneAdvRedirectResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneAdvRedirectResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *AdvRedirectData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetAdvRedirectsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetAdvRedirectsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Rules string `xml:"rules,omitempty" json:"rules,omitempty"` +} + +type GetAdvRedirectsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetAdvRedirectsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*AdvRedirectData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateAdvRedirectRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateAdvRedirectRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // 'Y'/'N', default 'Y' + Active string `xml:"active,omitempty" json:"active,omitempty"` + + // List of AdvRedirectRules + Rules []*AdvRedirectRuleData `xml:"rules,omitempty" json:"rules,omitempty"` +} + +type UpdateAdvRedirectResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateAdvRedirectResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *AdvRedirectData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneAdvRedirectRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneAdvRedirectRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // 'Y'/'N', default 'Y' + Active string `xml:"active,omitempty" json:"active,omitempty"` + + // List of AdvRedirectRules + Rules []*AdvRedirectRuleData `xml:"rules,omitempty" json:"rules,omitempty"` +} + +type DeleteOneAdvRedirectResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneAdvRedirectResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *AdvRedirectData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetNodeListRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetNodeListRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetNodeListResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetNodeListResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []string `xml:"data,omitempty" json:"data,omitempty"` +} + +type PublishZoneRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ PublishZoneRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Notes string `xml:"notes,omitempty" json:"notes,omitempty"` +} + +type PublishZoneResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ PublishZoneResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *PublishZoneData `xml:"data,omitempty" json:"data,omitempty"` +} + +type PruneZoneRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ PruneZoneRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type PruneZoneResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ PruneZoneResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ZoneData `xml:"data,omitempty" json:"data,omitempty"` +} + +type FreezeZoneRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ FreezeZoneRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type FreezeZoneResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ FreezeZoneResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type ThawZoneRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ThawZoneRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type ThawZoneResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ThawZoneResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type RestoreZoneRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RestoreZoneRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type RestoreZoneResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ RestoreZoneResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type BlockZoneRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ BlockZoneRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type BlockZoneResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ BlockZoneResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteZoneChangesetRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteZoneChangesetRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteZoneChangesetResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteZoneChangesetResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetZoneChangesetRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetZoneChangesetRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetZoneChangesetResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetZoneChangesetResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*ZoneChangeData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetZoneNotesRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetZoneNotesRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Limit int32 `xml:"limit,omitempty" json:"limit,omitempty"` + + Offset int32 `xml:"offset,omitempty" json:"offset,omitempty"` +} + +type GetZoneNotesResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetZoneNotesResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*ZoneNoteData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UploadZoneFileRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UploadZoneFileRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + File string `xml:"file,omitempty" json:"file,omitempty"` + + Create string `xml:"create,omitempty" json:"create,omitempty"` +} + +type UploadZoneFileResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UploadZoneFileResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *TaskIDData `xml:"data,omitempty" json:"data,omitempty"` +} + +type TransferZoneInRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ TransferZoneInRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Master_ip string `xml:"master_ip,omitempty" json:"master_ip,omitempty"` +} + +type TransferZoneInResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ TransferZoneInResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *TaskIDData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetTransferStatusRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetTransferStatusRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetTransferStatusResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetTransferStatusResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ZoneTransferStatus `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetZoneConfigOptionsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetZoneConfigOptionsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetZoneConfigOptionsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetZoneConfigOptionsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*ZoneConfigOptionData `xml:"data,omitempty" json:"data,omitempty"` +} + +type SetZoneConfigOptionsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetZoneConfigOptionsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + Option []*ZoneConfigOptionData `xml:"option,omitempty" json:"option,omitempty"` +} + +type SetZoneConfigOptionsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ SetZoneConfigOptionsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*ZoneConfigOptionData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateIPTrackRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateIPTrackRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // A, Dynamic_A, AAAA, Dynamic_AAAA + Record_types []string `xml:"record_types,omitempty" json:"record_types,omitempty"` + + // List of hostnames to watch for records + Hosts []string `xml:"hosts,omitempty" json:"hosts,omitempty"` + + // 'match', 'default', or a valid ttl + Ttl string `xml:"ttl,omitempty" json:"ttl,omitempty"` + + // Mask that records should match + Netmask string `xml:"netmask,omitempty" json:"netmask,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type CreateIPTrackResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateIPTrackResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *IPTrackData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneIPTrackRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneIPTrackRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Iptrack_id int64 `xml:"iptrack_id,omitempty" json:"iptrack_id,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type GetOneIPTrackResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneIPTrackResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *IPTrackData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetIPTracksRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetIPTracksRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetIPTracksResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetIPTracksResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*IPTrackData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateIPTrackRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateIPTrackRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Iptrack_id int64 `xml:"iptrack_id,omitempty" json:"iptrack_id,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` + + // A, Dynamic_A, AAAA, Dynamic_AAAA + Record_types []string `xml:"record_types,omitempty" json:"record_types,omitempty"` + + // List of hostnames to watch for records + Hosts []string `xml:"hosts,omitempty" json:"hosts,omitempty"` + + // 'match', 'default', or a valid ttl + Ttl string `xml:"ttl,omitempty" json:"ttl,omitempty"` + + // Mask that records should match + Netmask string `xml:"netmask,omitempty" json:"netmask,omitempty"` +} + +type UpdateIPTrackResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateIPTrackResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *IPTrackData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneIPTrackRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneIPTrackRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Iptrack_id int64 `xml:"iptrack_id,omitempty" json:"iptrack_id,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type DeleteOneIPTrackResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneIPTrackResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type ActivateIPTrackRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ActivateIPTrackRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Iptrack_id int64 `xml:"iptrack_id,omitempty" json:"iptrack_id,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type ActivateIPTrackResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ActivateIPTrackResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *IPTrackData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeactivateIPTrackRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeactivateIPTrackRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Iptrack_id int64 `xml:"iptrack_id,omitempty" json:"iptrack_id,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // hostname + Fqdn string `xml:"fqdn,omitempty" json:"fqdn,omitempty"` +} + +type DeactivateIPTrackResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeactivateIPTrackResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *IPTrackData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateDNSSECRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDNSSECRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // , contact that gets key notifications + Contact_nickname string `xml:"contact_nickname,omitempty" json:"contact_nickname,omitempty"` + + // when notifications are sent + Notify_events string `xml:"notify_events,omitempty" json:"notify_events,omitempty"` + + Keys []*DNSSECKey `xml:"keys,omitempty" json:"keys,omitempty"` +} + +type CreateDNSSECResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateDNSSECResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DNSSECData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneDNSSECRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDNSSECRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetOneDNSSECResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneDNSSECResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DNSSECData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetDNSSECsRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDNSSECsRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` +} + +type GetDNSSECsResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDNSSECsResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*DNSSECData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateDNSSECRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDNSSECRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // , contact that gets key notifications + Contact_nickname string `xml:"contact_nickname,omitempty" json:"contact_nickname,omitempty"` + + // when notifications are sent + Notify_events string `xml:"notify_events,omitempty" json:"notify_events,omitempty"` + + Keys []*DNSSECKey `xml:"keys,omitempty" json:"keys,omitempty"` +} + +type UpdateDNSSECResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateDNSSECResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DNSSECData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneDNSSECRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDNSSECRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteOneDNSSECResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneDNSSECResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type ActivateDNSSECRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ActivateDNSSECRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type ActivateDNSSECResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ ActivateDNSSECResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DNSSECData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeactivateDNSSECRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeactivateDNSSECRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeactivateDNSSECResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeactivateDNSSECResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *DNSSECData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetDNSSECTimelineRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDNSSECTimelineRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // name of zone + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // an epoch time, or 'now' + Start_ts string `xml:"start_ts,omitempty" json:"start_ts,omitempty"` + + // an epoch time, or 'now' + End_ts string `xml:"end_ts,omitempty" json:"end_ts,omitempty"` +} + +type GetDNSSECTimelineResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetDNSSECTimelineResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*DNSSECTimelineEvent `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetTasksRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetTasksRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Name string `xml:"name,omitempty" json:"name,omitempty"` + + Customer_name string `xml:"customer_name,omitempty" json:"customer_name,omitempty"` + + Zone_name string `xml:"zone_name,omitempty" json:"zone_name,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` +} + +type GetTasksResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetTasksResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*TaskData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneTaskRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneTaskRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Task_id string `xml:"task_id,omitempty" json:"task_id,omitempty"` +} + +type GetOneTaskResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneTaskResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *TaskData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CancelTaskRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CancelTaskRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + Task_id string `xml:"task_id,omitempty" json:"task_id,omitempty"` +} + +type CancelTaskResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CancelTaskResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *TaskData `xml:"data,omitempty" json:"data,omitempty"` +} + +type CreateExtNameserverRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateExtNameserverRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // can be empty or 'default' + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // Y/N - does this block requests or add them + Deny string `xml:"deny,omitempty" json:"deny,omitempty"` + + Hosts []*ExtNSEntry `xml:"hosts,omitempty" json:"hosts,omitempty"` + + Tsig_key_name string `xml:"tsig_key_name,omitempty" json:"tsig_key_name,omitempty"` + + Active string `xml:"active,omitempty" json:"active,omitempty"` +} + +type CreateExtNameserverResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ CreateExtNameserverResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ExtNameserverData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetOneExtNameserverRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneExtNameserverRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // can be empty or 'default' + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type GetOneExtNameserverResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetOneExtNameserverResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ExtNameserverData `xml:"data,omitempty" json:"data,omitempty"` +} + +type GetExtNameserversRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetExtNameserversRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` +} + +type GetExtNameserversResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ GetExtNameserversResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data []*ExtNameserverData `xml:"data,omitempty" json:"data,omitempty"` +} + +type UpdateExtNameserverRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateExtNameserverRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // can be empty or 'default' + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` + + // Y/N - does this block requests or add them + Deny string `xml:"deny,omitempty" json:"deny,omitempty"` + + Hosts []*ExtNSEntry `xml:"hosts,omitempty" json:"hosts,omitempty"` + + Tsig_key_name string `xml:"tsig_key_name,omitempty" json:"tsig_key_name,omitempty"` + + Active string `xml:"active,omitempty" json:"active,omitempty"` +} + +type UpdateExtNameserverResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ UpdateExtNameserverResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data *ExtNameserverData `xml:"data,omitempty" json:"data,omitempty"` +} + +type DeleteOneExtNameserverRequestType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneExtNameserverRequest"` + + Token string `xml:"token,omitempty" json:"token,omitempty"` + + Fault_incompat int32 `xml:"fault_incompat,omitempty" json:"fault_incompat,omitempty"` + + // can be empty or 'default' + Zone string `xml:"zone,omitempty" json:"zone,omitempty"` +} + +type DeleteOneExtNameserverResponseType struct { + XMLName xml.Name `xml:"https://api2.dynect.net/wsdl/3.7.16/Dynect/ DeleteOneExtNameserverResponse"` + + Job_id string `xml:"job_id,omitempty" json:"job_id,omitempty"` + + Status string `xml:"status,omitempty" json:"status,omitempty"` + + Msgs []*Messages `xml:"messages,omitempty" json:"msgs,omitempty"` + + Data string `xml:"data,omitempty" json:"data,omitempty"` +} + +type Dynect interface { + + // Error can be either of the following types: + // + // - fault + + GetJob(request *GetJobRequestType) (*GetJobResponseType, error) + + GetJobContext(ctx context.Context, request *GetJobRequestType) (*GetJobResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* starts a DynectAPI session */ + SessionLogin(request *SessionLoginRequestType) (*SessionLoginResponseType, error) + + SessionLoginContext(ctx context.Context, request *SessionLoginRequestType) (*SessionLoginResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* ends a DynectAPI session and invalidates the token */ + SessionLogout(request *SessionLogoutRequestType) (*SessionLogoutResponseType, error) + + SessionLogoutContext(ctx context.Context, request *SessionLogoutRequestType) (*SessionLogoutResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* checks where session and token are still valid */ + SessionIsAlive(request *SessionIsAliveRequestType) (*SessionIsAliveResponseType, error) + + SessionIsAliveContext(ctx context.Context, request *SessionIsAliveRequestType) (*SessionIsAliveResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* No operation, prevents sessions from timing out */ + SessionKeepAlive(request *SessionKeepAliveRequestType) (*SessionKeepAliveResponseType, error) + + SessionKeepAliveContext(ctx context.Context, request *SessionKeepAliveRequestType) (*SessionKeepAliveResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Support only; adds permissions from a given customer */ + ScopeIn(request *ScopeInRequestType) (*ScopeInResponseType, error) + + ScopeInContext(ctx context.Context, request *ScopeInRequestType) (*ScopeInResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Support only; changes permissions to those of some particular user */ + ScopeAs(request *ScopeAsRequestType) (*ScopeAsResponseType, error) + + ScopeAsContext(ctx context.Context, request *ScopeAsRequestType) (*ScopeAsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Undoes any ScopeIn or ScopeAs, returning to usual permissions */ + Unscope(request *UnscopeRequestType) (*UnscopeResponseType, error) + + UnscopeContext(ctx context.Context, request *UnscopeRequestType) (*UnscopeResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Retrieves Queries Per Second statistics in CSV format */ + GetQueryStats(request *GetQueryStatsRequestType) (*GetQueryStatsResponseType, error) + + GetQueryStatsContext(ctx context.Context, request *GetQueryStatsRequestType) (*GetQueryStatsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CreateGeo(request *CreateGeoRequestType) (*CreateGeoResponseType, error) + + CreateGeoContext(ctx context.Context, request *CreateGeoRequestType) (*CreateGeoResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateGeo(request *UpdateGeoRequestType) (*UpdateGeoResponseType, error) + + UpdateGeoContext(ctx context.Context, request *UpdateGeoRequestType) (*UpdateGeoResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetGeos(request *GetGeosRequestType) (*GetGeosResponseType, error) + + GetGeosContext(ctx context.Context, request *GetGeosRequestType) (*GetGeosResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetOneGeo(request *GetOneGeoRequestType) (*GetOneGeoResponseType, error) + + GetOneGeoContext(ctx context.Context, request *GetOneGeoRequestType) (*GetOneGeoResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeleteOneGeo(request *DeleteOneGeoRequestType) (*DeleteOneGeoResponseType, error) + + DeleteOneGeoContext(ctx context.Context, request *DeleteOneGeoRequestType) (*DeleteOneGeoResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ActivateGeo(request *ActivateGeoRequestType) (*ActivateGeoResponseType, error) + + ActivateGeoContext(ctx context.Context, request *ActivateGeoRequestType) (*ActivateGeoResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeactivateGeo(request *DeactivateGeoRequestType) (*DeactivateGeoResponseType, error) + + DeactivateGeoContext(ctx context.Context, request *DeactivateGeoRequestType) (*DeactivateGeoResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CreateGeoRegionGroup(request *CreateGeoRegionGroupRequestType) (*CreateGeoRegionGroupResponseType, error) + + CreateGeoRegionGroupContext(ctx context.Context, request *CreateGeoRegionGroupRequestType) (*CreateGeoRegionGroupResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateGeoRegionGroup(request *UpdateGeoRegionGroupRequestType) (*UpdateGeoRegionGroupResponseType, error) + + UpdateGeoRegionGroupContext(ctx context.Context, request *UpdateGeoRegionGroupRequestType) (*UpdateGeoRegionGroupResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeleteOneGeoRegionGroup(request *DeleteOneGeoRegionGroupRequestType) (*DeleteOneGeoRegionGroupResponseType, error) + + DeleteOneGeoRegionGroupContext(ctx context.Context, request *DeleteOneGeoRegionGroupRequestType) (*DeleteOneGeoRegionGroupResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetGeoRegionGroups(request *GetGeoRegionGroupsRequestType) (*GetGeoRegionGroupsResponseType, error) + + GetGeoRegionGroupsContext(ctx context.Context, request *GetGeoRegionGroupsRequestType) (*GetGeoRegionGroupsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetOneGeoRegionGroup(request *GetOneGeoRegionGroupRequestType) (*GetOneGeoRegionGroupResponseType, error) + + GetOneGeoRegionGroupContext(ctx context.Context, request *GetOneGeoRegionGroupRequestType) (*GetOneGeoRegionGroupResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CreateGeoNode(request *CreateGeoNodeRequestType) (*CreateGeoNodeResponseType, error) + + CreateGeoNodeContext(ctx context.Context, request *CreateGeoNodeRequestType) (*CreateGeoNodeResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeleteOneGeoNode(request *DeleteOneGeoNodeRequestType) (*DeleteOneGeoNodeResponseType, error) + + DeleteOneGeoNodeContext(ctx context.Context, request *DeleteOneGeoNodeRequestType) (*DeleteOneGeoNodeResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetGeoNodes(request *GetGeoNodesRequestType) (*GetGeoNodesResponseType, error) + + GetGeoNodesContext(ctx context.Context, request *GetGeoNodesRequestType) (*GetGeoNodesResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CreateDSF(request *CreateDSFRequestType) (*CreateDSFResponseType, error) + + CreateDSFContext(ctx context.Context, request *CreateDSFRequestType) (*CreateDSFResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateDSF(request *UpdateDSFRequestType) (*UpdateDSFResponseType, error) + + UpdateDSFContext(ctx context.Context, request *UpdateDSFRequestType) (*UpdateDSFResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetDSFs(request *GetDSFsRequestType) (*GetDSFsResponseType, error) + + GetDSFsContext(ctx context.Context, request *GetDSFsRequestType) (*GetDSFsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetDSFNotifiers(request *GetDSFNotifiersRequestType) (*GetDSFNotifiersResponseType, error) + + GetDSFNotifiersContext(ctx context.Context, request *GetDSFNotifiersRequestType) (*GetDSFNotifiersResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeleteOneDSF(request *DeleteOneDSFRequestType) (*DeleteOneDSFResponseType, error) + + DeleteOneDSFContext(ctx context.Context, request *DeleteOneDSFRequestType) (*DeleteOneDSFResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetOneDSF(request *GetOneDSFRequestType) (*GetOneDSFResponseType, error) + + GetOneDSFContext(ctx context.Context, request *GetOneDSFRequestType) (*GetOneDSFResponseType, error) + + // Error can be either of the following types: + // + // - fault + + RevertDSF(request *RevertDSFRequestType) (*RevertDSFResponseType, error) + + RevertDSFContext(ctx context.Context, request *RevertDSFRequestType) (*RevertDSFResponseType, error) + + // Error can be either of the following types: + // + // - fault + + PublishDSF(request *PublishDSFRequestType) (*PublishDSFResponseType, error) + + PublishDSFContext(ctx context.Context, request *PublishDSFRequestType) (*PublishDSFResponseType, error) + + // Error can be either of the following types: + // + // - fault + + AddDSFNotifier(request *AddDSFNotifierRequestType) (*AddDSFNotifierResponseType, error) + + AddDSFNotifierContext(ctx context.Context, request *AddDSFNotifierRequestType) (*AddDSFNotifierResponseType, error) + + // Error can be either of the following types: + // + // - fault + + RemoveDSFNotifier(request *RemoveDSFNotifierRequestType) (*RemoveDSFNotifierResponseType, error) + + RemoveDSFNotifierContext(ctx context.Context, request *RemoveDSFNotifierRequestType) (*RemoveDSFNotifierResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CreateDSFRuleset(request *CreateDSFRulesetRequestType) (*CreateDSFRulesetResponseType, error) + + CreateDSFRulesetContext(ctx context.Context, request *CreateDSFRulesetRequestType) (*CreateDSFRulesetResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateDSFRuleset(request *UpdateDSFRulesetRequestType) (*UpdateDSFRulesetResponseType, error) + + UpdateDSFRulesetContext(ctx context.Context, request *UpdateDSFRulesetRequestType) (*UpdateDSFRulesetResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetDSFRulesets(request *GetDSFRulesetsRequestType) (*GetDSFRulesetsResponseType, error) + + GetDSFRulesetsContext(ctx context.Context, request *GetDSFRulesetsRequestType) (*GetDSFRulesetsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetOneDSFRuleset(request *GetOneDSFRulesetRequestType) (*GetOneDSFRulesetResponseType, error) + + GetOneDSFRulesetContext(ctx context.Context, request *GetOneDSFRulesetRequestType) (*GetOneDSFRulesetResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeleteOneDSFRuleset(request *DeleteOneDSFRulesetRequestType) (*DeleteOneDSFRulesetResponseType, error) + + DeleteOneDSFRulesetContext(ctx context.Context, request *DeleteOneDSFRulesetRequestType) (*DeleteOneDSFRulesetResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CreateDSFResponsePool(request *CreateDSFResponsePoolRequestType) (*CreateDSFResponsePoolResponseType, error) + + CreateDSFResponsePoolContext(ctx context.Context, request *CreateDSFResponsePoolRequestType) (*CreateDSFResponsePoolResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateDSFResponsePool(request *UpdateDSFResponsePoolRequestType) (*UpdateDSFResponsePoolResponseType, error) + + UpdateDSFResponsePoolContext(ctx context.Context, request *UpdateDSFResponsePoolRequestType) (*UpdateDSFResponsePoolResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetDSFResponsePools(request *GetDSFResponsePoolsRequestType) (*GetDSFResponsePoolsResponseType, error) + + GetDSFResponsePoolsContext(ctx context.Context, request *GetDSFResponsePoolsRequestType) (*GetDSFResponsePoolsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetOneDSFResponsePool(request *GetOneDSFResponsePoolRequestType) (*GetOneDSFResponsePoolResponseType, error) + + GetOneDSFResponsePoolContext(ctx context.Context, request *GetOneDSFResponsePoolRequestType) (*GetOneDSFResponsePoolResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeleteOneDSFResponsePool(request *DeleteOneDSFResponsePoolRequestType) (*DeleteOneDSFResponsePoolResponseType, error) + + DeleteOneDSFResponsePoolContext(ctx context.Context, request *DeleteOneDSFResponsePoolRequestType) (*DeleteOneDSFResponsePoolResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CreateDSFRecordSetFailoverChain(request *CreateDSFRecordSetFailoverChainRequestType) (*CreateDSFRecordSetFailoverChainResponseType, error) + + CreateDSFRecordSetFailoverChainContext(ctx context.Context, request *CreateDSFRecordSetFailoverChainRequestType) (*CreateDSFRecordSetFailoverChainResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateDSFRecordSetFailoverChain(request *UpdateDSFRecordSetFailoverChainRequestType) (*UpdateDSFRecordSetFailoverChainResponseType, error) + + UpdateDSFRecordSetFailoverChainContext(ctx context.Context, request *UpdateDSFRecordSetFailoverChainRequestType) (*UpdateDSFRecordSetFailoverChainResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetDSFRecordSetFailoverChains(request *GetDSFRecordSetFailoverChainsRequestType) (*GetDSFRecordSetFailoverChainsResponseType, error) + + GetDSFRecordSetFailoverChainsContext(ctx context.Context, request *GetDSFRecordSetFailoverChainsRequestType) (*GetDSFRecordSetFailoverChainsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetOneDSFRecordSetFailoverChain(request *GetOneDSFRecordSetFailoverChainRequestType) (*GetOneDSFRecordSetFailoverChainResponseType, error) + + GetOneDSFRecordSetFailoverChainContext(ctx context.Context, request *GetOneDSFRecordSetFailoverChainRequestType) (*GetOneDSFRecordSetFailoverChainResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeleteOneDSFRecordSetFailoverChain(request *DeleteOneDSFRecordSetFailoverChainRequestType) (*DeleteOneDSFRecordSetFailoverChainResponseType, error) + + DeleteOneDSFRecordSetFailoverChainContext(ctx context.Context, request *DeleteOneDSFRecordSetFailoverChainRequestType) (*DeleteOneDSFRecordSetFailoverChainResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CreateDSFRecordSet(request *CreateDSFRecordSetRequestType) (*CreateDSFRecordSetResponseType, error) + + CreateDSFRecordSetContext(ctx context.Context, request *CreateDSFRecordSetRequestType) (*CreateDSFRecordSetResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateDSFRecordSet(request *UpdateDSFRecordSetRequestType) (*UpdateDSFRecordSetResponseType, error) + + UpdateDSFRecordSetContext(ctx context.Context, request *UpdateDSFRecordSetRequestType) (*UpdateDSFRecordSetResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetOneDSFRecordSet(request *GetOneDSFRecordSetRequestType) (*GetOneDSFRecordSetResponseType, error) + + GetOneDSFRecordSetContext(ctx context.Context, request *GetOneDSFRecordSetRequestType) (*GetOneDSFRecordSetResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetDSFRecordSets(request *GetDSFRecordSetsRequestType) (*GetDSFRecordSetsResponseType, error) + + GetDSFRecordSetsContext(ctx context.Context, request *GetDSFRecordSetsRequestType) (*GetDSFRecordSetsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeleteOneDSFRecordSet(request *DeleteOneDSFRecordSetRequestType) (*DeleteOneDSFRecordSetResponseType, error) + + DeleteOneDSFRecordSetContext(ctx context.Context, request *DeleteOneDSFRecordSetRequestType) (*DeleteOneDSFRecordSetResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CreateDSFRecord(request *CreateDSFRecordRequestType) (*CreateDSFRecordResponseType, error) + + CreateDSFRecordContext(ctx context.Context, request *CreateDSFRecordRequestType) (*CreateDSFRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateDSFRecord(request *UpdateDSFRecordRequestType) (*UpdateDSFRecordResponseType, error) + + UpdateDSFRecordContext(ctx context.Context, request *UpdateDSFRecordRequestType) (*UpdateDSFRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetOneDSFRecord(request *GetOneDSFRecordRequestType) (*GetOneDSFRecordResponseType, error) + + GetOneDSFRecordContext(ctx context.Context, request *GetOneDSFRecordRequestType) (*GetOneDSFRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetDSFRecords(request *GetDSFRecordsRequestType) (*GetDSFRecordsResponseType, error) + + GetDSFRecordsContext(ctx context.Context, request *GetDSFRecordsRequestType) (*GetDSFRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeleteOneDSFRecord(request *DeleteOneDSFRecordRequestType) (*DeleteOneDSFRecordResponseType, error) + + DeleteOneDSFRecordContext(ctx context.Context, request *DeleteOneDSFRecordRequestType) (*DeleteOneDSFRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + + AddDSFNode(request *AddDSFNodeRequestType) (*AddDSFNodeResponseType, error) + + AddDSFNodeContext(ctx context.Context, request *AddDSFNodeRequestType) (*AddDSFNodeResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateDSFNodes(request *UpdateDSFNodesRequestType) (*UpdateDSFNodesResponseType, error) + + UpdateDSFNodesContext(ctx context.Context, request *UpdateDSFNodesRequestType) (*UpdateDSFNodesResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetDSFNodes(request *GetDSFNodesRequestType) (*GetDSFNodesResponseType, error) + + GetDSFNodesContext(ctx context.Context, request *GetDSFNodesRequestType) (*GetDSFNodesResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeleteOneDSFNode(request *DeleteOneDSFNodeRequestType) (*DeleteOneDSFNodeResponseType, error) + + DeleteOneDSFNodeContext(ctx context.Context, request *DeleteOneDSFNodeRequestType) (*DeleteOneDSFNodeResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CreateDSFMonitor(request *CreateDSFMonitorRequestType) (*CreateDSFMonitorResponseType, error) + + CreateDSFMonitorContext(ctx context.Context, request *CreateDSFMonitorRequestType) (*CreateDSFMonitorResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateDSFMonitor(request *UpdateDSFMonitorRequestType) (*UpdateDSFMonitorResponseType, error) + + UpdateDSFMonitorContext(ctx context.Context, request *UpdateDSFMonitorRequestType) (*UpdateDSFMonitorResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetOneDSFMonitor(request *GetOneDSFMonitorRequestType) (*GetOneDSFMonitorResponseType, error) + + GetOneDSFMonitorContext(ctx context.Context, request *GetOneDSFMonitorRequestType) (*GetOneDSFMonitorResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetDSFMonitors(request *GetDSFMonitorsRequestType) (*GetDSFMonitorsResponseType, error) + + GetDSFMonitorsContext(ctx context.Context, request *GetDSFMonitorsRequestType) (*GetDSFMonitorsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeleteOneDSFMonitor(request *DeleteOneDSFMonitorRequestType) (*DeleteOneDSFMonitorResponseType, error) + + DeleteOneDSFMonitorContext(ctx context.Context, request *DeleteOneDSFMonitorRequestType) (*DeleteOneDSFMonitorResponseType, error) + + // Error can be either of the following types: + // + // - fault + + AddDSFMonitorNotifier(request *AddDSFMonitorNotifierRequestType) (*AddDSFMonitorNotifierResponseType, error) + + AddDSFMonitorNotifierContext(ctx context.Context, request *AddDSFMonitorNotifierRequestType) (*AddDSFMonitorNotifierResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetDSFMonitorSites(request *GetDSFMonitorSitesRequestType) (*GetDSFMonitorSitesResponseType, error) + + GetDSFMonitorSitesContext(ctx context.Context, request *GetDSFMonitorSitesRequestType) (*GetDSFMonitorSitesResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CreateNotifier(request *CreateNotifierRequestType) (*CreateNotifierResponseType, error) + + CreateNotifierContext(ctx context.Context, request *CreateNotifierRequestType) (*CreateNotifierResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateNotifier(request *UpdateNotifierRequestType) (*UpdateNotifierResponseType, error) + + UpdateNotifierContext(ctx context.Context, request *UpdateNotifierRequestType) (*UpdateNotifierResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetOneNotifier(request *GetOneNotifierRequestType) (*GetOneNotifierResponseType, error) + + GetOneNotifierContext(ctx context.Context, request *GetOneNotifierRequestType) (*GetOneNotifierResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetNotifiers(request *GetNotifiersRequestType) (*GetNotifiersResponseType, error) + + GetNotifiersContext(ctx context.Context, request *GetNotifiersRequestType) (*GetNotifiersResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeleteOneNotifier(request *DeleteOneNotifierRequestType) (*DeleteOneNotifierResponseType, error) + + DeleteOneNotifierContext(ctx context.Context, request *DeleteOneNotifierRequestType) (*DeleteOneNotifierResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CreateConfigLimit(request *CreateConfigLimitRequestType) (*CreateConfigLimitResponseType, error) + + CreateConfigLimitContext(ctx context.Context, request *CreateConfigLimitRequestType) (*CreateConfigLimitResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetOneConfigLimit(request *GetOneConfigLimitRequestType) (*GetOneConfigLimitResponseType, error) + + GetOneConfigLimitContext(ctx context.Context, request *GetOneConfigLimitRequestType) (*GetOneConfigLimitResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetConfigLimits(request *GetConfigLimitsRequestType) (*GetConfigLimitsResponseType, error) + + GetConfigLimitsContext(ctx context.Context, request *GetConfigLimitsRequestType) (*GetConfigLimitsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateConfigLimit(request *UpdateConfigLimitRequestType) (*UpdateConfigLimitResponseType, error) + + UpdateConfigLimitContext(ctx context.Context, request *UpdateConfigLimitRequestType) (*UpdateConfigLimitResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeleteOneConfigLimit(request *DeleteOneConfigLimitRequestType) (*DeleteOneConfigLimitResponseType, error) + + DeleteOneConfigLimitContext(ctx context.Context, request *DeleteOneConfigLimitRequestType) (*DeleteOneConfigLimitResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new PermissionGroup */ + CreatePermissionGroup(request *CreatePermissionGroupRequestType) (*CreatePermissionGroupResponseType, error) + + CreatePermissionGroupContext(ctx context.Context, request *CreatePermissionGroupRequestType) (*CreatePermissionGroupResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single PermissionGroup */ + GetOnePermissionGroup(request *GetOnePermissionGroupRequestType) (*GetOnePermissionGroupResponseType, error) + + GetOnePermissionGroupContext(ctx context.Context, request *GetOnePermissionGroupRequestType) (*GetOnePermissionGroupResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every PermissionGroup */ + GetPermissionGroups(request *GetPermissionGroupsRequestType) (*GetPermissionGroupsResponseType, error) + + GetPermissionGroupsContext(ctx context.Context, request *GetPermissionGroupsRequestType) (*GetPermissionGroupsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single PermissionGroup */ + DeleteOnePermissionGroup(request *DeleteOnePermissionGroupRequestType) (*DeleteOnePermissionGroupResponseType, error) + + DeleteOnePermissionGroupContext(ctx context.Context, request *DeleteOnePermissionGroupRequestType) (*DeleteOnePermissionGroupResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdatePermissionGroup(request *UpdatePermissionGroupRequestType) (*UpdatePermissionGroupResponseType, error) + + UpdatePermissionGroupContext(ctx context.Context, request *UpdatePermissionGroupRequestType) (*UpdatePermissionGroupResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetCustomerPermissions(request *GetCustomerPermissionsRequestType) (*GetCustomerPermissionsResponseType, error) + + GetCustomerPermissionsContext(ctx context.Context, request *GetCustomerPermissionsRequestType) (*GetCustomerPermissionsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetUserPermissions(request *GetUserPermissionsRequestType) (*GetUserPermissionsResponseType, error) + + GetUserPermissionsContext(ctx context.Context, request *GetUserPermissionsRequestType) (*GetUserPermissionsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CheckPermissions(request *CheckPermissionsRequestType) (*CheckPermissionsResponseType, error) + + CheckPermissionsContext(ctx context.Context, request *CheckPermissionsRequestType) (*CheckPermissionsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + AddPermissionGroupUsers(request *AddPermissionGroupUsersRequestType) (*AddPermissionGroupUsersResponseType, error) + + AddPermissionGroupUsersContext(ctx context.Context, request *AddPermissionGroupUsersRequestType) (*AddPermissionGroupUsersResponseType, error) + + // Error can be either of the following types: + // + // - fault + + SetPermissionGroupUsers(request *SetPermissionGroupUsersRequestType) (*SetPermissionGroupUsersResponseType, error) + + SetPermissionGroupUsersContext(ctx context.Context, request *SetPermissionGroupUsersRequestType) (*SetPermissionGroupUsersResponseType, error) + + // Error can be either of the following types: + // + // - fault + + RemovePermissionGroupUsers(request *RemovePermissionGroupUsersRequestType) (*RemovePermissionGroupUsersResponseType, error) + + RemovePermissionGroupUsersContext(ctx context.Context, request *RemovePermissionGroupUsersRequestType) (*RemovePermissionGroupUsersResponseType, error) + + // Error can be either of the following types: + // + // - fault + + AddPermissionGroupSubgroups(request *AddPermissionGroupSubgroupsRequestType) (*AddPermissionGroupSubgroupsResponseType, error) + + AddPermissionGroupSubgroupsContext(ctx context.Context, request *AddPermissionGroupSubgroupsRequestType) (*AddPermissionGroupSubgroupsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + SetPermissionGroupSubgroups(request *SetPermissionGroupSubgroupsRequestType) (*SetPermissionGroupSubgroupsResponseType, error) + + SetPermissionGroupSubgroupsContext(ctx context.Context, request *SetPermissionGroupSubgroupsRequestType) (*SetPermissionGroupSubgroupsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + RemovePermissionGroupSubgroups(request *RemovePermissionGroupSubgroupsRequestType) (*RemovePermissionGroupSubgroupsResponseType, error) + + RemovePermissionGroupSubgroupsContext(ctx context.Context, request *RemovePermissionGroupSubgroupsRequestType) (*RemovePermissionGroupSubgroupsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + AddPermissionGroupPermissions(request *AddPermissionGroupPermissionsRequestType) (*AddPermissionGroupPermissionsResponseType, error) + + AddPermissionGroupPermissionsContext(ctx context.Context, request *AddPermissionGroupPermissionsRequestType) (*AddPermissionGroupPermissionsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + SetPermissionGroupPermissions(request *SetPermissionGroupPermissionsRequestType) (*SetPermissionGroupPermissionsResponseType, error) + + SetPermissionGroupPermissionsContext(ctx context.Context, request *SetPermissionGroupPermissionsRequestType) (*SetPermissionGroupPermissionsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + RemovePermissionGroupPermissions(request *RemovePermissionGroupPermissionsRequestType) (*RemovePermissionGroupPermissionsResponseType, error) + + RemovePermissionGroupPermissionsContext(ctx context.Context, request *RemovePermissionGroupPermissionsRequestType) (*RemovePermissionGroupPermissionsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + AddPermissionGroupZones(request *AddPermissionGroupZonesRequestType) (*AddPermissionGroupZonesResponseType, error) + + AddPermissionGroupZonesContext(ctx context.Context, request *AddPermissionGroupZonesRequestType) (*AddPermissionGroupZonesResponseType, error) + + // Error can be either of the following types: + // + // - fault + + SetPermissionGroupZones(request *SetPermissionGroupZonesRequestType) (*SetPermissionGroupZonesResponseType, error) + + SetPermissionGroupZonesContext(ctx context.Context, request *SetPermissionGroupZonesRequestType) (*SetPermissionGroupZonesResponseType, error) + + // Error can be either of the following types: + // + // - fault + + RemovePermissionGroupZones(request *RemovePermissionGroupZonesRequestType) (*RemovePermissionGroupZonesResponseType, error) + + RemovePermissionGroupZonesContext(ctx context.Context, request *RemovePermissionGroupZonesRequestType) (*RemovePermissionGroupZonesResponseType, error) + + // Error can be either of the following types: + // + // - fault + + AddUserGroups(request *AddUserGroupsRequestType) (*AddUserGroupsResponseType, error) + + AddUserGroupsContext(ctx context.Context, request *AddUserGroupsRequestType) (*AddUserGroupsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + SetUserGroups(request *SetUserGroupsRequestType) (*SetUserGroupsResponseType, error) + + SetUserGroupsContext(ctx context.Context, request *SetUserGroupsRequestType) (*SetUserGroupsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + RemoveUserGroups(request *RemoveUserGroupsRequestType) (*RemoveUserGroupsResponseType, error) + + RemoveUserGroupsContext(ctx context.Context, request *RemoveUserGroupsRequestType) (*RemoveUserGroupsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + AddUserZones(request *AddUserZonesRequestType) (*AddUserZonesResponseType, error) + + AddUserZonesContext(ctx context.Context, request *AddUserZonesRequestType) (*AddUserZonesResponseType, error) + + // Error can be either of the following types: + // + // - fault + + SetUserZones(request *SetUserZonesRequestType) (*SetUserZonesResponseType, error) + + SetUserZonesContext(ctx context.Context, request *SetUserZonesRequestType) (*SetUserZonesResponseType, error) + + // Error can be either of the following types: + // + // - fault + + RemoveUserZones(request *RemoveUserZonesRequestType) (*RemoveUserZonesResponseType, error) + + RemoveUserZonesContext(ctx context.Context, request *RemoveUserZonesRequestType) (*RemoveUserZonesResponseType, error) + + // Error can be either of the following types: + // + // - fault + + AddUserPermissions(request *AddUserPermissionsRequestType) (*AddUserPermissionsResponseType, error) + + AddUserPermissionsContext(ctx context.Context, request *AddUserPermissionsRequestType) (*AddUserPermissionsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + SetUserPermissions(request *SetUserPermissionsRequestType) (*SetUserPermissionsResponseType, error) + + SetUserPermissionsContext(ctx context.Context, request *SetUserPermissionsRequestType) (*SetUserPermissionsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + RemoveUserPermissions(request *RemoveUserPermissionsRequestType) (*RemoveUserPermissionsResponseType, error) + + RemoveUserPermissionsContext(ctx context.Context, request *RemoveUserPermissionsRequestType) (*RemoveUserPermissionsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + AddUserForbids(request *AddUserForbidsRequestType) (*AddUserForbidsResponseType, error) + + AddUserForbidsContext(ctx context.Context, request *AddUserForbidsRequestType) (*AddUserForbidsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + SetUserForbids(request *SetUserForbidsRequestType) (*SetUserForbidsResponseType, error) + + SetUserForbidsContext(ctx context.Context, request *SetUserForbidsRequestType) (*SetUserForbidsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + RemoveUserForbids(request *RemoveUserForbidsRequestType) (*RemoveUserForbidsResponseType, error) + + RemoveUserForbidsContext(ctx context.Context, request *RemoveUserForbidsRequestType) (*RemoveUserForbidsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + AddCustomerPermissions(request *AddCustomerPermissionsRequestType) (*AddCustomerPermissionsResponseType, error) + + AddCustomerPermissionsContext(ctx context.Context, request *AddCustomerPermissionsRequestType) (*AddCustomerPermissionsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + SetCustomerPermissions(request *SetCustomerPermissionsRequestType) (*SetCustomerPermissionsResponseType, error) + + SetCustomerPermissionsContext(ctx context.Context, request *SetCustomerPermissionsRequestType) (*SetCustomerPermissionsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + RemoveCustomerPermissions(request *RemoveCustomerPermissionsRequestType) (*RemoveCustomerPermissionsResponseType, error) + + RemoveCustomerPermissionsContext(ctx context.Context, request *RemoveCustomerPermissionsRequestType) (*RemoveCustomerPermissionsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + AddCustomerForbids(request *AddCustomerForbidsRequestType) (*AddCustomerForbidsResponseType, error) + + AddCustomerForbidsContext(ctx context.Context, request *AddCustomerForbidsRequestType) (*AddCustomerForbidsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + SetCustomerForbids(request *SetCustomerForbidsRequestType) (*SetCustomerForbidsResponseType, error) + + SetCustomerForbidsContext(ctx context.Context, request *SetCustomerForbidsRequestType) (*SetCustomerForbidsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + RemoveCustomerForbids(request *RemoveCustomerForbidsRequestType) (*RemoveCustomerForbidsResponseType, error) + + RemoveCustomerForbidsContext(ctx context.Context, request *RemoveCustomerForbidsRequestType) (*RemoveCustomerForbidsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetHostStatsFlags(request *GetHostStatsFlagsRequestType) (*GetHostStatsFlagsResponseType, error) + + GetHostStatsFlagsContext(ctx context.Context, request *GetHostStatsFlagsRequestType) (*GetHostStatsFlagsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + SetHostStatsFlags(request *SetHostStatsFlagsRequestType) (*SetHostStatsFlagsResponseType, error) + + SetHostStatsFlagsContext(ctx context.Context, request *SetHostStatsFlagsRequestType) (*SetHostStatsFlagsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CreateTSIGKey(request *CreateTSIGKeyRequestType) (*CreateTSIGKeyResponseType, error) + + CreateTSIGKeyContext(ctx context.Context, request *CreateTSIGKeyRequestType) (*CreateTSIGKeyResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetOneTSIGKey(request *GetOneTSIGKeyRequestType) (*GetOneTSIGKeyResponseType, error) + + GetOneTSIGKeyContext(ctx context.Context, request *GetOneTSIGKeyRequestType) (*GetOneTSIGKeyResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetTSIGKeys(request *GetTSIGKeysRequestType) (*GetTSIGKeysResponseType, error) + + GetTSIGKeysContext(ctx context.Context, request *GetTSIGKeysRequestType) (*GetTSIGKeysResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateTSIGKey(request *UpdateTSIGKeyRequestType) (*UpdateTSIGKeyResponseType, error) + + UpdateTSIGKeyContext(ctx context.Context, request *UpdateTSIGKeyRequestType) (*UpdateTSIGKeyResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeleteOneTSIGKey(request *DeleteOneTSIGKeyRequestType) (*DeleteOneTSIGKeyResponseType, error) + + DeleteOneTSIGKeyContext(ctx context.Context, request *DeleteOneTSIGKeyRequestType) (*DeleteOneTSIGKeyResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new Zone */ + CreateZone(request *CreateZoneRequestType) (*CreateZoneResponseType, error) + + CreateZoneContext(ctx context.Context, request *CreateZoneRequestType) (*CreateZoneResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single Zone */ + GetOneZone(request *GetOneZoneRequestType) (*GetOneZoneResponseType, error) + + GetOneZoneContext(ctx context.Context, request *GetOneZoneRequestType) (*GetOneZoneResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every Zone */ + GetZones(request *GetZonesRequestType) (*GetZonesResponseType, error) + + GetZonesContext(ctx context.Context, request *GetZonesRequestType) (*GetZonesResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single Zone */ + DeleteOneZone(request *DeleteOneZoneRequestType) (*DeleteOneZoneResponseType, error) + + DeleteOneZoneContext(ctx context.Context, request *DeleteOneZoneRequestType) (*DeleteOneZoneResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CreateSecondaryZone(request *CreateSecondaryZoneRequestType) (*CreateSecondaryZoneResponseType, error) + + CreateSecondaryZoneContext(ctx context.Context, request *CreateSecondaryZoneRequestType) (*CreateSecondaryZoneResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateSecondary(request *UpdateSecondaryRequestType) (*UpdateSecondaryResponseType, error) + + UpdateSecondaryContext(ctx context.Context, request *UpdateSecondaryRequestType) (*UpdateSecondaryResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ActivateSecondary(request *ActivateSecondaryRequestType) (*ActivateSecondaryResponseType, error) + + ActivateSecondaryContext(ctx context.Context, request *ActivateSecondaryRequestType) (*ActivateSecondaryResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeactivateSecondary(request *DeactivateSecondaryRequestType) (*DeactivateSecondaryResponseType, error) + + DeactivateSecondaryContext(ctx context.Context, request *DeactivateSecondaryRequestType) (*DeactivateSecondaryResponseType, error) + + // Error can be either of the following types: + // + // - fault + + RetransferSecondary(request *RetransferSecondaryRequestType) (*RetransferSecondaryResponseType, error) + + RetransferSecondaryContext(ctx context.Context, request *RetransferSecondaryRequestType) (*RetransferSecondaryResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetOneSecondary(request *GetOneSecondaryRequestType) (*GetOneSecondaryResponseType, error) + + GetOneSecondaryContext(ctx context.Context, request *GetOneSecondaryRequestType) (*GetOneSecondaryResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetSecondaries(request *GetSecondariesRequestType) (*GetSecondariesResponseType, error) + + GetSecondariesContext(ctx context.Context, request *GetSecondariesRequestType) (*GetSecondariesResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetZoneApex(request *GetZoneApexRequestType) (*GetZoneApexResponseType, error) + + GetZoneApexContext(ctx context.Context, request *GetZoneApexRequestType) (*GetZoneApexResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new A record */ + CreateARecord(request *CreateARecordRequestType) (*CreateARecordResponseType, error) + + CreateARecordContext(ctx context.Context, request *CreateARecordRequestType) (*CreateARecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single A record */ + GetOneARecord(request *GetOneARecordRequestType) (*GetOneARecordResponseType, error) + + GetOneARecordContext(ctx context.Context, request *GetOneARecordRequestType) (*GetOneARecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every A record */ + GetARecords(request *GetARecordsRequestType) (*GetARecordsResponseType, error) + + GetARecordsContext(ctx context.Context, request *GetARecordsRequestType) (*GetARecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single A record */ + UpdateARecord(request *UpdateARecordRequestType) (*UpdateARecordResponseType, error) + + UpdateARecordContext(ctx context.Context, request *UpdateARecordRequestType) (*UpdateARecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every A record */ + DeleteARecords(request *DeleteARecordsRequestType) (*DeleteARecordsResponseType, error) + + DeleteARecordsContext(ctx context.Context, request *DeleteARecordsRequestType) (*DeleteARecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single A record */ + DeleteOneARecord(request *DeleteOneARecordRequestType) (*DeleteOneARecordResponseType, error) + + DeleteOneARecordContext(ctx context.Context, request *DeleteOneARecordRequestType) (*DeleteOneARecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new AAAA record */ + CreateAAAARecord(request *CreateAAAARecordRequestType) (*CreateAAAARecordResponseType, error) + + CreateAAAARecordContext(ctx context.Context, request *CreateAAAARecordRequestType) (*CreateAAAARecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single AAAA record */ + GetOneAAAARecord(request *GetOneAAAARecordRequestType) (*GetOneAAAARecordResponseType, error) + + GetOneAAAARecordContext(ctx context.Context, request *GetOneAAAARecordRequestType) (*GetOneAAAARecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every AAAA record */ + GetAAAARecords(request *GetAAAARecordsRequestType) (*GetAAAARecordsResponseType, error) + + GetAAAARecordsContext(ctx context.Context, request *GetAAAARecordsRequestType) (*GetAAAARecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single AAAA record */ + UpdateAAAARecord(request *UpdateAAAARecordRequestType) (*UpdateAAAARecordResponseType, error) + + UpdateAAAARecordContext(ctx context.Context, request *UpdateAAAARecordRequestType) (*UpdateAAAARecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every AAAA record */ + DeleteAAAARecords(request *DeleteAAAARecordsRequestType) (*DeleteAAAARecordsResponseType, error) + + DeleteAAAARecordsContext(ctx context.Context, request *DeleteAAAARecordsRequestType) (*DeleteAAAARecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single AAAA record */ + DeleteOneAAAARecord(request *DeleteOneAAAARecordRequestType) (*DeleteOneAAAARecordResponseType, error) + + DeleteOneAAAARecordContext(ctx context.Context, request *DeleteOneAAAARecordRequestType) (*DeleteOneAAAARecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new ALIAS record */ + CreateALIASRecord(request *CreateALIASRecordRequestType) (*CreateALIASRecordResponseType, error) + + CreateALIASRecordContext(ctx context.Context, request *CreateALIASRecordRequestType) (*CreateALIASRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single ALIAS record */ + GetOneALIASRecord(request *GetOneALIASRecordRequestType) (*GetOneALIASRecordResponseType, error) + + GetOneALIASRecordContext(ctx context.Context, request *GetOneALIASRecordRequestType) (*GetOneALIASRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every ALIAS record */ + GetALIASRecords(request *GetALIASRecordsRequestType) (*GetALIASRecordsResponseType, error) + + GetALIASRecordsContext(ctx context.Context, request *GetALIASRecordsRequestType) (*GetALIASRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single ALIAS record */ + UpdateALIASRecord(request *UpdateALIASRecordRequestType) (*UpdateALIASRecordResponseType, error) + + UpdateALIASRecordContext(ctx context.Context, request *UpdateALIASRecordRequestType) (*UpdateALIASRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every ALIAS record */ + DeleteALIASRecords(request *DeleteALIASRecordsRequestType) (*DeleteALIASRecordsResponseType, error) + + DeleteALIASRecordsContext(ctx context.Context, request *DeleteALIASRecordsRequestType) (*DeleteALIASRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single ALIAS record */ + DeleteOneALIASRecord(request *DeleteOneALIASRecordRequestType) (*DeleteOneALIASRecordResponseType, error) + + DeleteOneALIASRecordContext(ctx context.Context, request *DeleteOneALIASRecordRequestType) (*DeleteOneALIASRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new CAA record */ + CreateCAARecord(request *CreateCAARecordRequestType) (*CreateCAARecordResponseType, error) + + CreateCAARecordContext(ctx context.Context, request *CreateCAARecordRequestType) (*CreateCAARecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single CAA record */ + GetOneCAARecord(request *GetOneCAARecordRequestType) (*GetOneCAARecordResponseType, error) + + GetOneCAARecordContext(ctx context.Context, request *GetOneCAARecordRequestType) (*GetOneCAARecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every CAA record */ + GetCAARecords(request *GetCAARecordsRequestType) (*GetCAARecordsResponseType, error) + + GetCAARecordsContext(ctx context.Context, request *GetCAARecordsRequestType) (*GetCAARecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single CAA record */ + UpdateCAARecord(request *UpdateCAARecordRequestType) (*UpdateCAARecordResponseType, error) + + UpdateCAARecordContext(ctx context.Context, request *UpdateCAARecordRequestType) (*UpdateCAARecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every CAA record */ + DeleteCAARecords(request *DeleteCAARecordsRequestType) (*DeleteCAARecordsResponseType, error) + + DeleteCAARecordsContext(ctx context.Context, request *DeleteCAARecordsRequestType) (*DeleteCAARecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single CAA record */ + DeleteOneCAARecord(request *DeleteOneCAARecordRequestType) (*DeleteOneCAARecordResponseType, error) + + DeleteOneCAARecordContext(ctx context.Context, request *DeleteOneCAARecordRequestType) (*DeleteOneCAARecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new CDNSKEY record */ + CreateCDNSKEYRecord(request *CreateCDNSKEYRecordRequestType) (*CreateCDNSKEYRecordResponseType, error) + + CreateCDNSKEYRecordContext(ctx context.Context, request *CreateCDNSKEYRecordRequestType) (*CreateCDNSKEYRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single CDNSKEY record */ + GetOneCDNSKEYRecord(request *GetOneCDNSKEYRecordRequestType) (*GetOneCDNSKEYRecordResponseType, error) + + GetOneCDNSKEYRecordContext(ctx context.Context, request *GetOneCDNSKEYRecordRequestType) (*GetOneCDNSKEYRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every CDNSKEY record */ + GetCDNSKEYRecords(request *GetCDNSKEYRecordsRequestType) (*GetCDNSKEYRecordsResponseType, error) + + GetCDNSKEYRecordsContext(ctx context.Context, request *GetCDNSKEYRecordsRequestType) (*GetCDNSKEYRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single CDNSKEY record */ + UpdateCDNSKEYRecord(request *UpdateCDNSKEYRecordRequestType) (*UpdateCDNSKEYRecordResponseType, error) + + UpdateCDNSKEYRecordContext(ctx context.Context, request *UpdateCDNSKEYRecordRequestType) (*UpdateCDNSKEYRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every CDNSKEY record */ + DeleteCDNSKEYRecords(request *DeleteCDNSKEYRecordsRequestType) (*DeleteCDNSKEYRecordsResponseType, error) + + DeleteCDNSKEYRecordsContext(ctx context.Context, request *DeleteCDNSKEYRecordsRequestType) (*DeleteCDNSKEYRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single CDNSKEY record */ + DeleteOneCDNSKEYRecord(request *DeleteOneCDNSKEYRecordRequestType) (*DeleteOneCDNSKEYRecordResponseType, error) + + DeleteOneCDNSKEYRecordContext(ctx context.Context, request *DeleteOneCDNSKEYRecordRequestType) (*DeleteOneCDNSKEYRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new CDS record */ + CreateCDSRecord(request *CreateCDSRecordRequestType) (*CreateCDSRecordResponseType, error) + + CreateCDSRecordContext(ctx context.Context, request *CreateCDSRecordRequestType) (*CreateCDSRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single CDS record */ + GetOneCDSRecord(request *GetOneCDSRecordRequestType) (*GetOneCDSRecordResponseType, error) + + GetOneCDSRecordContext(ctx context.Context, request *GetOneCDSRecordRequestType) (*GetOneCDSRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every CDS record */ + GetCDSRecords(request *GetCDSRecordsRequestType) (*GetCDSRecordsResponseType, error) + + GetCDSRecordsContext(ctx context.Context, request *GetCDSRecordsRequestType) (*GetCDSRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single CDS record */ + UpdateCDSRecord(request *UpdateCDSRecordRequestType) (*UpdateCDSRecordResponseType, error) + + UpdateCDSRecordContext(ctx context.Context, request *UpdateCDSRecordRequestType) (*UpdateCDSRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every CDS record */ + DeleteCDSRecords(request *DeleteCDSRecordsRequestType) (*DeleteCDSRecordsResponseType, error) + + DeleteCDSRecordsContext(ctx context.Context, request *DeleteCDSRecordsRequestType) (*DeleteCDSRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single CDS record */ + DeleteOneCDSRecord(request *DeleteOneCDSRecordRequestType) (*DeleteOneCDSRecordResponseType, error) + + DeleteOneCDSRecordContext(ctx context.Context, request *DeleteOneCDSRecordRequestType) (*DeleteOneCDSRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new CERT record */ + CreateCERTRecord(request *CreateCERTRecordRequestType) (*CreateCERTRecordResponseType, error) + + CreateCERTRecordContext(ctx context.Context, request *CreateCERTRecordRequestType) (*CreateCERTRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single CERT record */ + GetOneCERTRecord(request *GetOneCERTRecordRequestType) (*GetOneCERTRecordResponseType, error) + + GetOneCERTRecordContext(ctx context.Context, request *GetOneCERTRecordRequestType) (*GetOneCERTRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every CERT record */ + GetCERTRecords(request *GetCERTRecordsRequestType) (*GetCERTRecordsResponseType, error) + + GetCERTRecordsContext(ctx context.Context, request *GetCERTRecordsRequestType) (*GetCERTRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single CERT record */ + UpdateCERTRecord(request *UpdateCERTRecordRequestType) (*UpdateCERTRecordResponseType, error) + + UpdateCERTRecordContext(ctx context.Context, request *UpdateCERTRecordRequestType) (*UpdateCERTRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every CERT record */ + DeleteCERTRecords(request *DeleteCERTRecordsRequestType) (*DeleteCERTRecordsResponseType, error) + + DeleteCERTRecordsContext(ctx context.Context, request *DeleteCERTRecordsRequestType) (*DeleteCERTRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single CERT record */ + DeleteOneCERTRecord(request *DeleteOneCERTRecordRequestType) (*DeleteOneCERTRecordResponseType, error) + + DeleteOneCERTRecordContext(ctx context.Context, request *DeleteOneCERTRecordRequestType) (*DeleteOneCERTRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new CNAME record */ + CreateCNAMERecord(request *CreateCNAMERecordRequestType) (*CreateCNAMERecordResponseType, error) + + CreateCNAMERecordContext(ctx context.Context, request *CreateCNAMERecordRequestType) (*CreateCNAMERecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single CNAME record */ + GetOneCNAMERecord(request *GetOneCNAMERecordRequestType) (*GetOneCNAMERecordResponseType, error) + + GetOneCNAMERecordContext(ctx context.Context, request *GetOneCNAMERecordRequestType) (*GetOneCNAMERecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every CNAME record */ + GetCNAMERecords(request *GetCNAMERecordsRequestType) (*GetCNAMERecordsResponseType, error) + + GetCNAMERecordsContext(ctx context.Context, request *GetCNAMERecordsRequestType) (*GetCNAMERecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single CNAME record */ + UpdateCNAMERecord(request *UpdateCNAMERecordRequestType) (*UpdateCNAMERecordResponseType, error) + + UpdateCNAMERecordContext(ctx context.Context, request *UpdateCNAMERecordRequestType) (*UpdateCNAMERecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every CNAME record */ + DeleteCNAMERecords(request *DeleteCNAMERecordsRequestType) (*DeleteCNAMERecordsResponseType, error) + + DeleteCNAMERecordsContext(ctx context.Context, request *DeleteCNAMERecordsRequestType) (*DeleteCNAMERecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single CNAME record */ + DeleteOneCNAMERecord(request *DeleteOneCNAMERecordRequestType) (*DeleteOneCNAMERecordResponseType, error) + + DeleteOneCNAMERecordContext(ctx context.Context, request *DeleteOneCNAMERecordRequestType) (*DeleteOneCNAMERecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new CSYNC record */ + CreateCSYNCRecord(request *CreateCSYNCRecordRequestType) (*CreateCSYNCRecordResponseType, error) + + CreateCSYNCRecordContext(ctx context.Context, request *CreateCSYNCRecordRequestType) (*CreateCSYNCRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single CSYNC record */ + GetOneCSYNCRecord(request *GetOneCSYNCRecordRequestType) (*GetOneCSYNCRecordResponseType, error) + + GetOneCSYNCRecordContext(ctx context.Context, request *GetOneCSYNCRecordRequestType) (*GetOneCSYNCRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every CSYNC record */ + GetCSYNCRecords(request *GetCSYNCRecordsRequestType) (*GetCSYNCRecordsResponseType, error) + + GetCSYNCRecordsContext(ctx context.Context, request *GetCSYNCRecordsRequestType) (*GetCSYNCRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single CSYNC record */ + UpdateCSYNCRecord(request *UpdateCSYNCRecordRequestType) (*UpdateCSYNCRecordResponseType, error) + + UpdateCSYNCRecordContext(ctx context.Context, request *UpdateCSYNCRecordRequestType) (*UpdateCSYNCRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every CSYNC record */ + DeleteCSYNCRecords(request *DeleteCSYNCRecordsRequestType) (*DeleteCSYNCRecordsResponseType, error) + + DeleteCSYNCRecordsContext(ctx context.Context, request *DeleteCSYNCRecordsRequestType) (*DeleteCSYNCRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single CSYNC record */ + DeleteOneCSYNCRecord(request *DeleteOneCSYNCRecordRequestType) (*DeleteOneCSYNCRecordResponseType, error) + + DeleteOneCSYNCRecordContext(ctx context.Context, request *DeleteOneCSYNCRecordRequestType) (*DeleteOneCSYNCRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new DHCID record */ + CreateDHCIDRecord(request *CreateDHCIDRecordRequestType) (*CreateDHCIDRecordResponseType, error) + + CreateDHCIDRecordContext(ctx context.Context, request *CreateDHCIDRecordRequestType) (*CreateDHCIDRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single DHCID record */ + GetOneDHCIDRecord(request *GetOneDHCIDRecordRequestType) (*GetOneDHCIDRecordResponseType, error) + + GetOneDHCIDRecordContext(ctx context.Context, request *GetOneDHCIDRecordRequestType) (*GetOneDHCIDRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every DHCID record */ + GetDHCIDRecords(request *GetDHCIDRecordsRequestType) (*GetDHCIDRecordsResponseType, error) + + GetDHCIDRecordsContext(ctx context.Context, request *GetDHCIDRecordsRequestType) (*GetDHCIDRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single DHCID record */ + UpdateDHCIDRecord(request *UpdateDHCIDRecordRequestType) (*UpdateDHCIDRecordResponseType, error) + + UpdateDHCIDRecordContext(ctx context.Context, request *UpdateDHCIDRecordRequestType) (*UpdateDHCIDRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every DHCID record */ + DeleteDHCIDRecords(request *DeleteDHCIDRecordsRequestType) (*DeleteDHCIDRecordsResponseType, error) + + DeleteDHCIDRecordsContext(ctx context.Context, request *DeleteDHCIDRecordsRequestType) (*DeleteDHCIDRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single DHCID record */ + DeleteOneDHCIDRecord(request *DeleteOneDHCIDRecordRequestType) (*DeleteOneDHCIDRecordResponseType, error) + + DeleteOneDHCIDRecordContext(ctx context.Context, request *DeleteOneDHCIDRecordRequestType) (*DeleteOneDHCIDRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new DNAME record */ + CreateDNAMERecord(request *CreateDNAMERecordRequestType) (*CreateDNAMERecordResponseType, error) + + CreateDNAMERecordContext(ctx context.Context, request *CreateDNAMERecordRequestType) (*CreateDNAMERecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single DNAME record */ + GetOneDNAMERecord(request *GetOneDNAMERecordRequestType) (*GetOneDNAMERecordResponseType, error) + + GetOneDNAMERecordContext(ctx context.Context, request *GetOneDNAMERecordRequestType) (*GetOneDNAMERecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every DNAME record */ + GetDNAMERecords(request *GetDNAMERecordsRequestType) (*GetDNAMERecordsResponseType, error) + + GetDNAMERecordsContext(ctx context.Context, request *GetDNAMERecordsRequestType) (*GetDNAMERecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single DNAME record */ + UpdateDNAMERecord(request *UpdateDNAMERecordRequestType) (*UpdateDNAMERecordResponseType, error) + + UpdateDNAMERecordContext(ctx context.Context, request *UpdateDNAMERecordRequestType) (*UpdateDNAMERecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every DNAME record */ + DeleteDNAMERecords(request *DeleteDNAMERecordsRequestType) (*DeleteDNAMERecordsResponseType, error) + + DeleteDNAMERecordsContext(ctx context.Context, request *DeleteDNAMERecordsRequestType) (*DeleteDNAMERecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single DNAME record */ + DeleteOneDNAMERecord(request *DeleteOneDNAMERecordRequestType) (*DeleteOneDNAMERecordResponseType, error) + + DeleteOneDNAMERecordContext(ctx context.Context, request *DeleteOneDNAMERecordRequestType) (*DeleteOneDNAMERecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new DNSKEY record */ + CreateDNSKEYRecord(request *CreateDNSKEYRecordRequestType) (*CreateDNSKEYRecordResponseType, error) + + CreateDNSKEYRecordContext(ctx context.Context, request *CreateDNSKEYRecordRequestType) (*CreateDNSKEYRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single DNSKEY record */ + GetOneDNSKEYRecord(request *GetOneDNSKEYRecordRequestType) (*GetOneDNSKEYRecordResponseType, error) + + GetOneDNSKEYRecordContext(ctx context.Context, request *GetOneDNSKEYRecordRequestType) (*GetOneDNSKEYRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every DNSKEY record */ + GetDNSKEYRecords(request *GetDNSKEYRecordsRequestType) (*GetDNSKEYRecordsResponseType, error) + + GetDNSKEYRecordsContext(ctx context.Context, request *GetDNSKEYRecordsRequestType) (*GetDNSKEYRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single DNSKEY record */ + UpdateDNSKEYRecord(request *UpdateDNSKEYRecordRequestType) (*UpdateDNSKEYRecordResponseType, error) + + UpdateDNSKEYRecordContext(ctx context.Context, request *UpdateDNSKEYRecordRequestType) (*UpdateDNSKEYRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every DNSKEY record */ + DeleteDNSKEYRecords(request *DeleteDNSKEYRecordsRequestType) (*DeleteDNSKEYRecordsResponseType, error) + + DeleteDNSKEYRecordsContext(ctx context.Context, request *DeleteDNSKEYRecordsRequestType) (*DeleteDNSKEYRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single DNSKEY record */ + DeleteOneDNSKEYRecord(request *DeleteOneDNSKEYRecordRequestType) (*DeleteOneDNSKEYRecordResponseType, error) + + DeleteOneDNSKEYRecordContext(ctx context.Context, request *DeleteOneDNSKEYRecordRequestType) (*DeleteOneDNSKEYRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new DS record */ + CreateDSRecord(request *CreateDSRecordRequestType) (*CreateDSRecordResponseType, error) + + CreateDSRecordContext(ctx context.Context, request *CreateDSRecordRequestType) (*CreateDSRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single DS record */ + GetOneDSRecord(request *GetOneDSRecordRequestType) (*GetOneDSRecordResponseType, error) + + GetOneDSRecordContext(ctx context.Context, request *GetOneDSRecordRequestType) (*GetOneDSRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every DS record */ + GetDSRecords(request *GetDSRecordsRequestType) (*GetDSRecordsResponseType, error) + + GetDSRecordsContext(ctx context.Context, request *GetDSRecordsRequestType) (*GetDSRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single DS record */ + UpdateDSRecord(request *UpdateDSRecordRequestType) (*UpdateDSRecordResponseType, error) + + UpdateDSRecordContext(ctx context.Context, request *UpdateDSRecordRequestType) (*UpdateDSRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every DS record */ + DeleteDSRecords(request *DeleteDSRecordsRequestType) (*DeleteDSRecordsResponseType, error) + + DeleteDSRecordsContext(ctx context.Context, request *DeleteDSRecordsRequestType) (*DeleteDSRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single DS record */ + DeleteOneDSRecord(request *DeleteOneDSRecordRequestType) (*DeleteOneDSRecordResponseType, error) + + DeleteOneDSRecordContext(ctx context.Context, request *DeleteOneDSRecordRequestType) (*DeleteOneDSRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new IPSECKEY record */ + CreateIPSECKEYRecord(request *CreateIPSECKEYRecordRequestType) (*CreateIPSECKEYRecordResponseType, error) + + CreateIPSECKEYRecordContext(ctx context.Context, request *CreateIPSECKEYRecordRequestType) (*CreateIPSECKEYRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single IPSECKEY record */ + GetOneIPSECKEYRecord(request *GetOneIPSECKEYRecordRequestType) (*GetOneIPSECKEYRecordResponseType, error) + + GetOneIPSECKEYRecordContext(ctx context.Context, request *GetOneIPSECKEYRecordRequestType) (*GetOneIPSECKEYRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every IPSECKEY record */ + GetIPSECKEYRecords(request *GetIPSECKEYRecordsRequestType) (*GetIPSECKEYRecordsResponseType, error) + + GetIPSECKEYRecordsContext(ctx context.Context, request *GetIPSECKEYRecordsRequestType) (*GetIPSECKEYRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single IPSECKEY record */ + UpdateIPSECKEYRecord(request *UpdateIPSECKEYRecordRequestType) (*UpdateIPSECKEYRecordResponseType, error) + + UpdateIPSECKEYRecordContext(ctx context.Context, request *UpdateIPSECKEYRecordRequestType) (*UpdateIPSECKEYRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every IPSECKEY record */ + DeleteIPSECKEYRecords(request *DeleteIPSECKEYRecordsRequestType) (*DeleteIPSECKEYRecordsResponseType, error) + + DeleteIPSECKEYRecordsContext(ctx context.Context, request *DeleteIPSECKEYRecordsRequestType) (*DeleteIPSECKEYRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single IPSECKEY record */ + DeleteOneIPSECKEYRecord(request *DeleteOneIPSECKEYRecordRequestType) (*DeleteOneIPSECKEYRecordResponseType, error) + + DeleteOneIPSECKEYRecordContext(ctx context.Context, request *DeleteOneIPSECKEYRecordRequestType) (*DeleteOneIPSECKEYRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new KEY record */ + CreateKEYRecord(request *CreateKEYRecordRequestType) (*CreateKEYRecordResponseType, error) + + CreateKEYRecordContext(ctx context.Context, request *CreateKEYRecordRequestType) (*CreateKEYRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single KEY record */ + GetOneKEYRecord(request *GetOneKEYRecordRequestType) (*GetOneKEYRecordResponseType, error) + + GetOneKEYRecordContext(ctx context.Context, request *GetOneKEYRecordRequestType) (*GetOneKEYRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every KEY record */ + GetKEYRecords(request *GetKEYRecordsRequestType) (*GetKEYRecordsResponseType, error) + + GetKEYRecordsContext(ctx context.Context, request *GetKEYRecordsRequestType) (*GetKEYRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single KEY record */ + UpdateKEYRecord(request *UpdateKEYRecordRequestType) (*UpdateKEYRecordResponseType, error) + + UpdateKEYRecordContext(ctx context.Context, request *UpdateKEYRecordRequestType) (*UpdateKEYRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every KEY record */ + DeleteKEYRecords(request *DeleteKEYRecordsRequestType) (*DeleteKEYRecordsResponseType, error) + + DeleteKEYRecordsContext(ctx context.Context, request *DeleteKEYRecordsRequestType) (*DeleteKEYRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single KEY record */ + DeleteOneKEYRecord(request *DeleteOneKEYRecordRequestType) (*DeleteOneKEYRecordResponseType, error) + + DeleteOneKEYRecordContext(ctx context.Context, request *DeleteOneKEYRecordRequestType) (*DeleteOneKEYRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new KX record */ + CreateKXRecord(request *CreateKXRecordRequestType) (*CreateKXRecordResponseType, error) + + CreateKXRecordContext(ctx context.Context, request *CreateKXRecordRequestType) (*CreateKXRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single KX record */ + GetOneKXRecord(request *GetOneKXRecordRequestType) (*GetOneKXRecordResponseType, error) + + GetOneKXRecordContext(ctx context.Context, request *GetOneKXRecordRequestType) (*GetOneKXRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every KX record */ + GetKXRecords(request *GetKXRecordsRequestType) (*GetKXRecordsResponseType, error) + + GetKXRecordsContext(ctx context.Context, request *GetKXRecordsRequestType) (*GetKXRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single KX record */ + UpdateKXRecord(request *UpdateKXRecordRequestType) (*UpdateKXRecordResponseType, error) + + UpdateKXRecordContext(ctx context.Context, request *UpdateKXRecordRequestType) (*UpdateKXRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every KX record */ + DeleteKXRecords(request *DeleteKXRecordsRequestType) (*DeleteKXRecordsResponseType, error) + + DeleteKXRecordsContext(ctx context.Context, request *DeleteKXRecordsRequestType) (*DeleteKXRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single KX record */ + DeleteOneKXRecord(request *DeleteOneKXRecordRequestType) (*DeleteOneKXRecordResponseType, error) + + DeleteOneKXRecordContext(ctx context.Context, request *DeleteOneKXRecordRequestType) (*DeleteOneKXRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new LOC record */ + CreateLOCRecord(request *CreateLOCRecordRequestType) (*CreateLOCRecordResponseType, error) + + CreateLOCRecordContext(ctx context.Context, request *CreateLOCRecordRequestType) (*CreateLOCRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single LOC record */ + GetOneLOCRecord(request *GetOneLOCRecordRequestType) (*GetOneLOCRecordResponseType, error) + + GetOneLOCRecordContext(ctx context.Context, request *GetOneLOCRecordRequestType) (*GetOneLOCRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every LOC record */ + GetLOCRecords(request *GetLOCRecordsRequestType) (*GetLOCRecordsResponseType, error) + + GetLOCRecordsContext(ctx context.Context, request *GetLOCRecordsRequestType) (*GetLOCRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single LOC record */ + UpdateLOCRecord(request *UpdateLOCRecordRequestType) (*UpdateLOCRecordResponseType, error) + + UpdateLOCRecordContext(ctx context.Context, request *UpdateLOCRecordRequestType) (*UpdateLOCRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every LOC record */ + DeleteLOCRecords(request *DeleteLOCRecordsRequestType) (*DeleteLOCRecordsResponseType, error) + + DeleteLOCRecordsContext(ctx context.Context, request *DeleteLOCRecordsRequestType) (*DeleteLOCRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single LOC record */ + DeleteOneLOCRecord(request *DeleteOneLOCRecordRequestType) (*DeleteOneLOCRecordResponseType, error) + + DeleteOneLOCRecordContext(ctx context.Context, request *DeleteOneLOCRecordRequestType) (*DeleteOneLOCRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new MX record */ + CreateMXRecord(request *CreateMXRecordRequestType) (*CreateMXRecordResponseType, error) + + CreateMXRecordContext(ctx context.Context, request *CreateMXRecordRequestType) (*CreateMXRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single MX record */ + GetOneMXRecord(request *GetOneMXRecordRequestType) (*GetOneMXRecordResponseType, error) + + GetOneMXRecordContext(ctx context.Context, request *GetOneMXRecordRequestType) (*GetOneMXRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every MX record */ + GetMXRecords(request *GetMXRecordsRequestType) (*GetMXRecordsResponseType, error) + + GetMXRecordsContext(ctx context.Context, request *GetMXRecordsRequestType) (*GetMXRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single MX record */ + UpdateMXRecord(request *UpdateMXRecordRequestType) (*UpdateMXRecordResponseType, error) + + UpdateMXRecordContext(ctx context.Context, request *UpdateMXRecordRequestType) (*UpdateMXRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every MX record */ + DeleteMXRecords(request *DeleteMXRecordsRequestType) (*DeleteMXRecordsResponseType, error) + + DeleteMXRecordsContext(ctx context.Context, request *DeleteMXRecordsRequestType) (*DeleteMXRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single MX record */ + DeleteOneMXRecord(request *DeleteOneMXRecordRequestType) (*DeleteOneMXRecordResponseType, error) + + DeleteOneMXRecordContext(ctx context.Context, request *DeleteOneMXRecordRequestType) (*DeleteOneMXRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new NAPTR record */ + CreateNAPTRRecord(request *CreateNAPTRRecordRequestType) (*CreateNAPTRRecordResponseType, error) + + CreateNAPTRRecordContext(ctx context.Context, request *CreateNAPTRRecordRequestType) (*CreateNAPTRRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single NAPTR record */ + GetOneNAPTRRecord(request *GetOneNAPTRRecordRequestType) (*GetOneNAPTRRecordResponseType, error) + + GetOneNAPTRRecordContext(ctx context.Context, request *GetOneNAPTRRecordRequestType) (*GetOneNAPTRRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every NAPTR record */ + GetNAPTRRecords(request *GetNAPTRRecordsRequestType) (*GetNAPTRRecordsResponseType, error) + + GetNAPTRRecordsContext(ctx context.Context, request *GetNAPTRRecordsRequestType) (*GetNAPTRRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single NAPTR record */ + UpdateNAPTRRecord(request *UpdateNAPTRRecordRequestType) (*UpdateNAPTRRecordResponseType, error) + + UpdateNAPTRRecordContext(ctx context.Context, request *UpdateNAPTRRecordRequestType) (*UpdateNAPTRRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every NAPTR record */ + DeleteNAPTRRecords(request *DeleteNAPTRRecordsRequestType) (*DeleteNAPTRRecordsResponseType, error) + + DeleteNAPTRRecordsContext(ctx context.Context, request *DeleteNAPTRRecordsRequestType) (*DeleteNAPTRRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single NAPTR record */ + DeleteOneNAPTRRecord(request *DeleteOneNAPTRRecordRequestType) (*DeleteOneNAPTRRecordResponseType, error) + + DeleteOneNAPTRRecordContext(ctx context.Context, request *DeleteOneNAPTRRecordRequestType) (*DeleteOneNAPTRRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new NSAP record */ + CreateNSAPRecord(request *CreateNSAPRecordRequestType) (*CreateNSAPRecordResponseType, error) + + CreateNSAPRecordContext(ctx context.Context, request *CreateNSAPRecordRequestType) (*CreateNSAPRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single NSAP record */ + GetOneNSAPRecord(request *GetOneNSAPRecordRequestType) (*GetOneNSAPRecordResponseType, error) + + GetOneNSAPRecordContext(ctx context.Context, request *GetOneNSAPRecordRequestType) (*GetOneNSAPRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every NSAP record */ + GetNSAPRecords(request *GetNSAPRecordsRequestType) (*GetNSAPRecordsResponseType, error) + + GetNSAPRecordsContext(ctx context.Context, request *GetNSAPRecordsRequestType) (*GetNSAPRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single NSAP record */ + UpdateNSAPRecord(request *UpdateNSAPRecordRequestType) (*UpdateNSAPRecordResponseType, error) + + UpdateNSAPRecordContext(ctx context.Context, request *UpdateNSAPRecordRequestType) (*UpdateNSAPRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every NSAP record */ + DeleteNSAPRecords(request *DeleteNSAPRecordsRequestType) (*DeleteNSAPRecordsResponseType, error) + + DeleteNSAPRecordsContext(ctx context.Context, request *DeleteNSAPRecordsRequestType) (*DeleteNSAPRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single NSAP record */ + DeleteOneNSAPRecord(request *DeleteOneNSAPRecordRequestType) (*DeleteOneNSAPRecordResponseType, error) + + DeleteOneNSAPRecordContext(ctx context.Context, request *DeleteOneNSAPRecordRequestType) (*DeleteOneNSAPRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new POLICY record */ + CreatePOLICYRecord(request *CreatePOLICYRecordRequestType) (*CreatePOLICYRecordResponseType, error) + + CreatePOLICYRecordContext(ctx context.Context, request *CreatePOLICYRecordRequestType) (*CreatePOLICYRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single POLICY record */ + GetOnePOLICYRecord(request *GetOnePOLICYRecordRequestType) (*GetOnePOLICYRecordResponseType, error) + + GetOnePOLICYRecordContext(ctx context.Context, request *GetOnePOLICYRecordRequestType) (*GetOnePOLICYRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every POLICY record */ + GetPOLICYRecords(request *GetPOLICYRecordsRequestType) (*GetPOLICYRecordsResponseType, error) + + GetPOLICYRecordsContext(ctx context.Context, request *GetPOLICYRecordsRequestType) (*GetPOLICYRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single POLICY record */ + UpdatePOLICYRecord(request *UpdatePOLICYRecordRequestType) (*UpdatePOLICYRecordResponseType, error) + + UpdatePOLICYRecordContext(ctx context.Context, request *UpdatePOLICYRecordRequestType) (*UpdatePOLICYRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every POLICY record */ + DeletePOLICYRecords(request *DeletePOLICYRecordsRequestType) (*DeletePOLICYRecordsResponseType, error) + + DeletePOLICYRecordsContext(ctx context.Context, request *DeletePOLICYRecordsRequestType) (*DeletePOLICYRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single POLICY record */ + DeleteOnePOLICYRecord(request *DeleteOnePOLICYRecordRequestType) (*DeleteOnePOLICYRecordResponseType, error) + + DeleteOnePOLICYRecordContext(ctx context.Context, request *DeleteOnePOLICYRecordRequestType) (*DeleteOnePOLICYRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new PTR record */ + CreatePTRRecord(request *CreatePTRRecordRequestType) (*CreatePTRRecordResponseType, error) + + CreatePTRRecordContext(ctx context.Context, request *CreatePTRRecordRequestType) (*CreatePTRRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single PTR record */ + GetOnePTRRecord(request *GetOnePTRRecordRequestType) (*GetOnePTRRecordResponseType, error) + + GetOnePTRRecordContext(ctx context.Context, request *GetOnePTRRecordRequestType) (*GetOnePTRRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every PTR record */ + GetPTRRecords(request *GetPTRRecordsRequestType) (*GetPTRRecordsResponseType, error) + + GetPTRRecordsContext(ctx context.Context, request *GetPTRRecordsRequestType) (*GetPTRRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single PTR record */ + UpdatePTRRecord(request *UpdatePTRRecordRequestType) (*UpdatePTRRecordResponseType, error) + + UpdatePTRRecordContext(ctx context.Context, request *UpdatePTRRecordRequestType) (*UpdatePTRRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every PTR record */ + DeletePTRRecords(request *DeletePTRRecordsRequestType) (*DeletePTRRecordsResponseType, error) + + DeletePTRRecordsContext(ctx context.Context, request *DeletePTRRecordsRequestType) (*DeletePTRRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single PTR record */ + DeleteOnePTRRecord(request *DeleteOnePTRRecordRequestType) (*DeleteOnePTRRecordResponseType, error) + + DeleteOnePTRRecordContext(ctx context.Context, request *DeleteOnePTRRecordRequestType) (*DeleteOnePTRRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new PX record */ + CreatePXRecord(request *CreatePXRecordRequestType) (*CreatePXRecordResponseType, error) + + CreatePXRecordContext(ctx context.Context, request *CreatePXRecordRequestType) (*CreatePXRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single PX record */ + GetOnePXRecord(request *GetOnePXRecordRequestType) (*GetOnePXRecordResponseType, error) + + GetOnePXRecordContext(ctx context.Context, request *GetOnePXRecordRequestType) (*GetOnePXRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every PX record */ + GetPXRecords(request *GetPXRecordsRequestType) (*GetPXRecordsResponseType, error) + + GetPXRecordsContext(ctx context.Context, request *GetPXRecordsRequestType) (*GetPXRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single PX record */ + UpdatePXRecord(request *UpdatePXRecordRequestType) (*UpdatePXRecordResponseType, error) + + UpdatePXRecordContext(ctx context.Context, request *UpdatePXRecordRequestType) (*UpdatePXRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every PX record */ + DeletePXRecords(request *DeletePXRecordsRequestType) (*DeletePXRecordsResponseType, error) + + DeletePXRecordsContext(ctx context.Context, request *DeletePXRecordsRequestType) (*DeletePXRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single PX record */ + DeleteOnePXRecord(request *DeleteOnePXRecordRequestType) (*DeleteOnePXRecordResponseType, error) + + DeleteOnePXRecordContext(ctx context.Context, request *DeleteOnePXRecordRequestType) (*DeleteOnePXRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new RP record */ + CreateRPRecord(request *CreateRPRecordRequestType) (*CreateRPRecordResponseType, error) + + CreateRPRecordContext(ctx context.Context, request *CreateRPRecordRequestType) (*CreateRPRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single RP record */ + GetOneRPRecord(request *GetOneRPRecordRequestType) (*GetOneRPRecordResponseType, error) + + GetOneRPRecordContext(ctx context.Context, request *GetOneRPRecordRequestType) (*GetOneRPRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every RP record */ + GetRPRecords(request *GetRPRecordsRequestType) (*GetRPRecordsResponseType, error) + + GetRPRecordsContext(ctx context.Context, request *GetRPRecordsRequestType) (*GetRPRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single RP record */ + UpdateRPRecord(request *UpdateRPRecordRequestType) (*UpdateRPRecordResponseType, error) + + UpdateRPRecordContext(ctx context.Context, request *UpdateRPRecordRequestType) (*UpdateRPRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every RP record */ + DeleteRPRecords(request *DeleteRPRecordsRequestType) (*DeleteRPRecordsResponseType, error) + + DeleteRPRecordsContext(ctx context.Context, request *DeleteRPRecordsRequestType) (*DeleteRPRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single RP record */ + DeleteOneRPRecord(request *DeleteOneRPRecordRequestType) (*DeleteOneRPRecordResponseType, error) + + DeleteOneRPRecordContext(ctx context.Context, request *DeleteOneRPRecordRequestType) (*DeleteOneRPRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new SPF record */ + CreateSPFRecord(request *CreateSPFRecordRequestType) (*CreateSPFRecordResponseType, error) + + CreateSPFRecordContext(ctx context.Context, request *CreateSPFRecordRequestType) (*CreateSPFRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single SPF record */ + GetOneSPFRecord(request *GetOneSPFRecordRequestType) (*GetOneSPFRecordResponseType, error) + + GetOneSPFRecordContext(ctx context.Context, request *GetOneSPFRecordRequestType) (*GetOneSPFRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every SPF record */ + GetSPFRecords(request *GetSPFRecordsRequestType) (*GetSPFRecordsResponseType, error) + + GetSPFRecordsContext(ctx context.Context, request *GetSPFRecordsRequestType) (*GetSPFRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single SPF record */ + UpdateSPFRecord(request *UpdateSPFRecordRequestType) (*UpdateSPFRecordResponseType, error) + + UpdateSPFRecordContext(ctx context.Context, request *UpdateSPFRecordRequestType) (*UpdateSPFRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every SPF record */ + DeleteSPFRecords(request *DeleteSPFRecordsRequestType) (*DeleteSPFRecordsResponseType, error) + + DeleteSPFRecordsContext(ctx context.Context, request *DeleteSPFRecordsRequestType) (*DeleteSPFRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single SPF record */ + DeleteOneSPFRecord(request *DeleteOneSPFRecordRequestType) (*DeleteOneSPFRecordResponseType, error) + + DeleteOneSPFRecordContext(ctx context.Context, request *DeleteOneSPFRecordRequestType) (*DeleteOneSPFRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new SRV record */ + CreateSRVRecord(request *CreateSRVRecordRequestType) (*CreateSRVRecordResponseType, error) + + CreateSRVRecordContext(ctx context.Context, request *CreateSRVRecordRequestType) (*CreateSRVRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single SRV record */ + GetOneSRVRecord(request *GetOneSRVRecordRequestType) (*GetOneSRVRecordResponseType, error) + + GetOneSRVRecordContext(ctx context.Context, request *GetOneSRVRecordRequestType) (*GetOneSRVRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every SRV record */ + GetSRVRecords(request *GetSRVRecordsRequestType) (*GetSRVRecordsResponseType, error) + + GetSRVRecordsContext(ctx context.Context, request *GetSRVRecordsRequestType) (*GetSRVRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single SRV record */ + UpdateSRVRecord(request *UpdateSRVRecordRequestType) (*UpdateSRVRecordResponseType, error) + + UpdateSRVRecordContext(ctx context.Context, request *UpdateSRVRecordRequestType) (*UpdateSRVRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every SRV record */ + DeleteSRVRecords(request *DeleteSRVRecordsRequestType) (*DeleteSRVRecordsResponseType, error) + + DeleteSRVRecordsContext(ctx context.Context, request *DeleteSRVRecordsRequestType) (*DeleteSRVRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single SRV record */ + DeleteOneSRVRecord(request *DeleteOneSRVRecordRequestType) (*DeleteOneSRVRecordResponseType, error) + + DeleteOneSRVRecordContext(ctx context.Context, request *DeleteOneSRVRecordRequestType) (*DeleteOneSRVRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new SSHFP record */ + CreateSSHFPRecord(request *CreateSSHFPRecordRequestType) (*CreateSSHFPRecordResponseType, error) + + CreateSSHFPRecordContext(ctx context.Context, request *CreateSSHFPRecordRequestType) (*CreateSSHFPRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single SSHFP record */ + GetOneSSHFPRecord(request *GetOneSSHFPRecordRequestType) (*GetOneSSHFPRecordResponseType, error) + + GetOneSSHFPRecordContext(ctx context.Context, request *GetOneSSHFPRecordRequestType) (*GetOneSSHFPRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every SSHFP record */ + GetSSHFPRecords(request *GetSSHFPRecordsRequestType) (*GetSSHFPRecordsResponseType, error) + + GetSSHFPRecordsContext(ctx context.Context, request *GetSSHFPRecordsRequestType) (*GetSSHFPRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single SSHFP record */ + UpdateSSHFPRecord(request *UpdateSSHFPRecordRequestType) (*UpdateSSHFPRecordResponseType, error) + + UpdateSSHFPRecordContext(ctx context.Context, request *UpdateSSHFPRecordRequestType) (*UpdateSSHFPRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every SSHFP record */ + DeleteSSHFPRecords(request *DeleteSSHFPRecordsRequestType) (*DeleteSSHFPRecordsResponseType, error) + + DeleteSSHFPRecordsContext(ctx context.Context, request *DeleteSSHFPRecordsRequestType) (*DeleteSSHFPRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single SSHFP record */ + DeleteOneSSHFPRecord(request *DeleteOneSSHFPRecordRequestType) (*DeleteOneSSHFPRecordResponseType, error) + + DeleteOneSSHFPRecordContext(ctx context.Context, request *DeleteOneSSHFPRecordRequestType) (*DeleteOneSSHFPRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new TLSA record */ + CreateTLSARecord(request *CreateTLSARecordRequestType) (*CreateTLSARecordResponseType, error) + + CreateTLSARecordContext(ctx context.Context, request *CreateTLSARecordRequestType) (*CreateTLSARecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single TLSA record */ + GetOneTLSARecord(request *GetOneTLSARecordRequestType) (*GetOneTLSARecordResponseType, error) + + GetOneTLSARecordContext(ctx context.Context, request *GetOneTLSARecordRequestType) (*GetOneTLSARecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every TLSA record */ + GetTLSARecords(request *GetTLSARecordsRequestType) (*GetTLSARecordsResponseType, error) + + GetTLSARecordsContext(ctx context.Context, request *GetTLSARecordsRequestType) (*GetTLSARecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single TLSA record */ + UpdateTLSARecord(request *UpdateTLSARecordRequestType) (*UpdateTLSARecordResponseType, error) + + UpdateTLSARecordContext(ctx context.Context, request *UpdateTLSARecordRequestType) (*UpdateTLSARecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every TLSA record */ + DeleteTLSARecords(request *DeleteTLSARecordsRequestType) (*DeleteTLSARecordsResponseType, error) + + DeleteTLSARecordsContext(ctx context.Context, request *DeleteTLSARecordsRequestType) (*DeleteTLSARecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single TLSA record */ + DeleteOneTLSARecord(request *DeleteOneTLSARecordRequestType) (*DeleteOneTLSARecordResponseType, error) + + DeleteOneTLSARecordContext(ctx context.Context, request *DeleteOneTLSARecordRequestType) (*DeleteOneTLSARecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new TXT record */ + CreateTXTRecord(request *CreateTXTRecordRequestType) (*CreateTXTRecordResponseType, error) + + CreateTXTRecordContext(ctx context.Context, request *CreateTXTRecordRequestType) (*CreateTXTRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single TXT record */ + GetOneTXTRecord(request *GetOneTXTRecordRequestType) (*GetOneTXTRecordResponseType, error) + + GetOneTXTRecordContext(ctx context.Context, request *GetOneTXTRecordRequestType) (*GetOneTXTRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every TXT record */ + GetTXTRecords(request *GetTXTRecordsRequestType) (*GetTXTRecordsResponseType, error) + + GetTXTRecordsContext(ctx context.Context, request *GetTXTRecordsRequestType) (*GetTXTRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single TXT record */ + UpdateTXTRecord(request *UpdateTXTRecordRequestType) (*UpdateTXTRecordResponseType, error) + + UpdateTXTRecordContext(ctx context.Context, request *UpdateTXTRecordRequestType) (*UpdateTXTRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every TXT record */ + DeleteTXTRecords(request *DeleteTXTRecordsRequestType) (*DeleteTXTRecordsResponseType, error) + + DeleteTXTRecordsContext(ctx context.Context, request *DeleteTXTRecordsRequestType) (*DeleteTXTRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single TXT record */ + DeleteOneTXTRecord(request *DeleteOneTXTRecordRequestType) (*DeleteOneTXTRecordResponseType, error) + + DeleteOneTXTRecordContext(ctx context.Context, request *DeleteOneTXTRecordRequestType) (*DeleteOneTXTRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single SOA record */ + GetOneSOARecord(request *GetOneSOARecordRequestType) (*GetOneSOARecordResponseType, error) + + GetOneSOARecordContext(ctx context.Context, request *GetOneSOARecordRequestType) (*GetOneSOARecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every SOA record */ + GetSOARecords(request *GetSOARecordsRequestType) (*GetSOARecordsResponseType, error) + + GetSOARecordsContext(ctx context.Context, request *GetSOARecordsRequestType) (*GetSOARecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateSOARecord(request *UpdateSOARecordRequestType) (*UpdateSOARecordResponseType, error) + + UpdateSOARecordContext(ctx context.Context, request *UpdateSOARecordRequestType) (*UpdateSOARecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new NS record */ + CreateNSRecord(request *CreateNSRecordRequestType) (*CreateNSRecordResponseType, error) + + CreateNSRecordContext(ctx context.Context, request *CreateNSRecordRequestType) (*CreateNSRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single NS record */ + GetOneNSRecord(request *GetOneNSRecordRequestType) (*GetOneNSRecordResponseType, error) + + GetOneNSRecordContext(ctx context.Context, request *GetOneNSRecordRequestType) (*GetOneNSRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every NS record */ + GetNSRecords(request *GetNSRecordsRequestType) (*GetNSRecordsResponseType, error) + + GetNSRecordsContext(ctx context.Context, request *GetNSRecordsRequestType) (*GetNSRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single NS record */ + UpdateNSRecord(request *UpdateNSRecordRequestType) (*UpdateNSRecordResponseType, error) + + UpdateNSRecordContext(ctx context.Context, request *UpdateNSRecordRequestType) (*UpdateNSRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes every NS record */ + DeleteNSRecords(request *DeleteNSRecordsRequestType) (*DeleteNSRecordsResponseType, error) + + DeleteNSRecordsContext(ctx context.Context, request *DeleteNSRecordsRequestType) (*DeleteNSRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single NS record */ + DeleteOneNSRecord(request *DeleteOneNSRecordRequestType) (*DeleteOneNSRecordResponseType, error) + + DeleteOneNSRecordContext(ctx context.Context, request *DeleteOneNSRecordRequestType) (*DeleteOneNSRecordResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceARecords(request *ReplaceARecordsRequestType) (*ReplaceARecordsResponseType, error) + + ReplaceARecordsContext(ctx context.Context, request *ReplaceARecordsRequestType) (*ReplaceARecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceAAAARecords(request *ReplaceAAAARecordsRequestType) (*ReplaceAAAARecordsResponseType, error) + + ReplaceAAAARecordsContext(ctx context.Context, request *ReplaceAAAARecordsRequestType) (*ReplaceAAAARecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceALIASRecords(request *ReplaceALIASRecordsRequestType) (*ReplaceALIASRecordsResponseType, error) + + ReplaceALIASRecordsContext(ctx context.Context, request *ReplaceALIASRecordsRequestType) (*ReplaceALIASRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceCAARecords(request *ReplaceCAARecordsRequestType) (*ReplaceCAARecordsResponseType, error) + + ReplaceCAARecordsContext(ctx context.Context, request *ReplaceCAARecordsRequestType) (*ReplaceCAARecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceCDNSKEYRecords(request *ReplaceCDNSKEYRecordsRequestType) (*ReplaceCDNSKEYRecordsResponseType, error) + + ReplaceCDNSKEYRecordsContext(ctx context.Context, request *ReplaceCDNSKEYRecordsRequestType) (*ReplaceCDNSKEYRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceCDSRecords(request *ReplaceCDSRecordsRequestType) (*ReplaceCDSRecordsResponseType, error) + + ReplaceCDSRecordsContext(ctx context.Context, request *ReplaceCDSRecordsRequestType) (*ReplaceCDSRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceCERTRecords(request *ReplaceCERTRecordsRequestType) (*ReplaceCERTRecordsResponseType, error) + + ReplaceCERTRecordsContext(ctx context.Context, request *ReplaceCERTRecordsRequestType) (*ReplaceCERTRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceCNAMERecords(request *ReplaceCNAMERecordsRequestType) (*ReplaceCNAMERecordsResponseType, error) + + ReplaceCNAMERecordsContext(ctx context.Context, request *ReplaceCNAMERecordsRequestType) (*ReplaceCNAMERecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceCSYNCRecords(request *ReplaceCSYNCRecordsRequestType) (*ReplaceCSYNCRecordsResponseType, error) + + ReplaceCSYNCRecordsContext(ctx context.Context, request *ReplaceCSYNCRecordsRequestType) (*ReplaceCSYNCRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceDHCIDRecords(request *ReplaceDHCIDRecordsRequestType) (*ReplaceDHCIDRecordsResponseType, error) + + ReplaceDHCIDRecordsContext(ctx context.Context, request *ReplaceDHCIDRecordsRequestType) (*ReplaceDHCIDRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceDNAMERecords(request *ReplaceDNAMERecordsRequestType) (*ReplaceDNAMERecordsResponseType, error) + + ReplaceDNAMERecordsContext(ctx context.Context, request *ReplaceDNAMERecordsRequestType) (*ReplaceDNAMERecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceDNSKEYRecords(request *ReplaceDNSKEYRecordsRequestType) (*ReplaceDNSKEYRecordsResponseType, error) + + ReplaceDNSKEYRecordsContext(ctx context.Context, request *ReplaceDNSKEYRecordsRequestType) (*ReplaceDNSKEYRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceDSRecords(request *ReplaceDSRecordsRequestType) (*ReplaceDSRecordsResponseType, error) + + ReplaceDSRecordsContext(ctx context.Context, request *ReplaceDSRecordsRequestType) (*ReplaceDSRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceIPSECKEYRecords(request *ReplaceIPSECKEYRecordsRequestType) (*ReplaceIPSECKEYRecordsResponseType, error) + + ReplaceIPSECKEYRecordsContext(ctx context.Context, request *ReplaceIPSECKEYRecordsRequestType) (*ReplaceIPSECKEYRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceKEYRecords(request *ReplaceKEYRecordsRequestType) (*ReplaceKEYRecordsResponseType, error) + + ReplaceKEYRecordsContext(ctx context.Context, request *ReplaceKEYRecordsRequestType) (*ReplaceKEYRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceKXRecords(request *ReplaceKXRecordsRequestType) (*ReplaceKXRecordsResponseType, error) + + ReplaceKXRecordsContext(ctx context.Context, request *ReplaceKXRecordsRequestType) (*ReplaceKXRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceLOCRecords(request *ReplaceLOCRecordsRequestType) (*ReplaceLOCRecordsResponseType, error) + + ReplaceLOCRecordsContext(ctx context.Context, request *ReplaceLOCRecordsRequestType) (*ReplaceLOCRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceMXRecords(request *ReplaceMXRecordsRequestType) (*ReplaceMXRecordsResponseType, error) + + ReplaceMXRecordsContext(ctx context.Context, request *ReplaceMXRecordsRequestType) (*ReplaceMXRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceNAPTRRecords(request *ReplaceNAPTRRecordsRequestType) (*ReplaceNAPTRRecordsResponseType, error) + + ReplaceNAPTRRecordsContext(ctx context.Context, request *ReplaceNAPTRRecordsRequestType) (*ReplaceNAPTRRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceNSAPRecords(request *ReplaceNSAPRecordsRequestType) (*ReplaceNSAPRecordsResponseType, error) + + ReplaceNSAPRecordsContext(ctx context.Context, request *ReplaceNSAPRecordsRequestType) (*ReplaceNSAPRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplacePOLICYRecords(request *ReplacePOLICYRecordsRequestType) (*ReplacePOLICYRecordsResponseType, error) + + ReplacePOLICYRecordsContext(ctx context.Context, request *ReplacePOLICYRecordsRequestType) (*ReplacePOLICYRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplacePTRRecords(request *ReplacePTRRecordsRequestType) (*ReplacePTRRecordsResponseType, error) + + ReplacePTRRecordsContext(ctx context.Context, request *ReplacePTRRecordsRequestType) (*ReplacePTRRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplacePXRecords(request *ReplacePXRecordsRequestType) (*ReplacePXRecordsResponseType, error) + + ReplacePXRecordsContext(ctx context.Context, request *ReplacePXRecordsRequestType) (*ReplacePXRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceRPRecords(request *ReplaceRPRecordsRequestType) (*ReplaceRPRecordsResponseType, error) + + ReplaceRPRecordsContext(ctx context.Context, request *ReplaceRPRecordsRequestType) (*ReplaceRPRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceSPFRecords(request *ReplaceSPFRecordsRequestType) (*ReplaceSPFRecordsResponseType, error) + + ReplaceSPFRecordsContext(ctx context.Context, request *ReplaceSPFRecordsRequestType) (*ReplaceSPFRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceSRVRecords(request *ReplaceSRVRecordsRequestType) (*ReplaceSRVRecordsResponseType, error) + + ReplaceSRVRecordsContext(ctx context.Context, request *ReplaceSRVRecordsRequestType) (*ReplaceSRVRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceSSHFPRecords(request *ReplaceSSHFPRecordsRequestType) (*ReplaceSSHFPRecordsResponseType, error) + + ReplaceSSHFPRecordsContext(ctx context.Context, request *ReplaceSSHFPRecordsRequestType) (*ReplaceSSHFPRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceTLSARecords(request *ReplaceTLSARecordsRequestType) (*ReplaceTLSARecordsResponseType, error) + + ReplaceTLSARecordsContext(ctx context.Context, request *ReplaceTLSARecordsRequestType) (*ReplaceTLSARecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceTXTRecords(request *ReplaceTXTRecordsRequestType) (*ReplaceTXTRecordsResponseType, error) + + ReplaceTXTRecordsContext(ctx context.Context, request *ReplaceTXTRecordsRequestType) (*ReplaceTXTRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ReplaceNSRecords(request *ReplaceNSRecordsRequestType) (*ReplaceNSRecordsResponseType, error) + + ReplaceNSRecordsContext(ctx context.Context, request *ReplaceNSRecordsRequestType) (*ReplaceNSRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetANYRecords(request *GetANYRecordsRequestType) (*GetANYRecordsResponseType, error) + + GetANYRecordsContext(ctx context.Context, request *GetANYRecordsRequestType) (*GetANYRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetAllRecords(request *GetAllRecordsRequestType) (*GetAllRecordsResponseType, error) + + GetAllRecordsContext(ctx context.Context, request *GetAllRecordsRequestType) (*GetAllRecordsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetAllAliasQNames(request *GetAllAliasQNamesRequestType) (*GetAllAliasQNamesResponseType, error) + + GetAllAliasQNamesContext(ctx context.Context, request *GetAllAliasQNamesRequestType) (*GetAllAliasQNamesResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single User */ + GetOneUser(request *GetOneUserRequestType) (*GetOneUserResponseType, error) + + GetOneUserContext(ctx context.Context, request *GetOneUserRequestType) (*GetOneUserResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single User */ + DeleteOneUser(request *DeleteOneUserRequestType) (*DeleteOneUserResponseType, error) + + DeleteOneUserContext(ctx context.Context, request *DeleteOneUserRequestType) (*DeleteOneUserResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CreateUser(request *CreateUserRequestType) (*CreateUserResponseType, error) + + CreateUserContext(ctx context.Context, request *CreateUserRequestType) (*CreateUserResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateUser(request *UpdateUserRequestType) (*UpdateUserResponseType, error) + + UpdateUserContext(ctx context.Context, request *UpdateUserRequestType) (*UpdateUserResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetUsers(request *GetUsersRequestType) (*GetUsersResponseType, error) + + GetUsersContext(ctx context.Context, request *GetUsersRequestType) (*GetUsersResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetUpdateUsers(request *GetUpdateUsersRequestType) (*GetUpdateUsersResponseType, error) + + GetUpdateUsersContext(ctx context.Context, request *GetUpdateUsersRequestType) (*GetUpdateUsersResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateUpdateUser(request *UpdateUpdateUserRequestType) (*UpdateUpdateUserResponseType, error) + + UpdateUpdateUserContext(ctx context.Context, request *UpdateUpdateUserRequestType) (*UpdateUpdateUserResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeleteOneUpdateUser(request *DeleteOneUpdateUserRequestType) (*DeleteOneUpdateUserResponseType, error) + + DeleteOneUpdateUserContext(ctx context.Context, request *DeleteOneUpdateUserRequestType) (*DeleteOneUpdateUserResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateUserPassword(request *UpdateUserPasswordRequestType) (*UpdateUserPasswordResponseType, error) + + UpdateUserPasswordContext(ctx context.Context, request *UpdateUserPasswordRequestType) (*UpdateUserPasswordResponseType, error) + + // Error can be either of the following types: + // + // - fault + + BlockUser(request *BlockUserRequestType) (*BlockUserResponseType, error) + + BlockUserContext(ctx context.Context, request *BlockUserRequestType) (*BlockUserResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UnblockUser(request *UnblockUserRequestType) (*UnblockUserResponseType, error) + + UnblockUserContext(ctx context.Context, request *UnblockUserRequestType) (*UnblockUserResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new Contact */ + CreateContact(request *CreateContactRequestType) (*CreateContactResponseType, error) + + CreateContactContext(ctx context.Context, request *CreateContactRequestType) (*CreateContactResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single Contact */ + GetOneContact(request *GetOneContactRequestType) (*GetOneContactResponseType, error) + + GetOneContactContext(ctx context.Context, request *GetOneContactRequestType) (*GetOneContactResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every Contact */ + GetContacts(request *GetContactsRequestType) (*GetContactsResponseType, error) + + GetContactsContext(ctx context.Context, request *GetContactsRequestType) (*GetContactsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single Contact */ + DeleteOneContact(request *DeleteOneContactRequestType) (*DeleteOneContactResponseType, error) + + DeleteOneContactContext(ctx context.Context, request *DeleteOneContactRequestType) (*DeleteOneContactResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateContact(request *UpdateContactRequestType) (*UpdateContactResponseType, error) + + UpdateContactContext(ctx context.Context, request *UpdateContactRequestType) (*UpdateContactResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CreateCustomer(request *CreateCustomerRequestType) (*CreateCustomerResponseType, error) + + CreateCustomerContext(ctx context.Context, request *CreateCustomerRequestType) (*CreateCustomerResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateCustomer(request *UpdateCustomerRequestType) (*UpdateCustomerResponseType, error) + + UpdateCustomerContext(ctx context.Context, request *UpdateCustomerRequestType) (*UpdateCustomerResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetOneCustomer(request *GetOneCustomerRequestType) (*GetOneCustomerResponseType, error) + + GetOneCustomerContext(ctx context.Context, request *GetOneCustomerRequestType) (*GetOneCustomerResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetCustomers(request *GetCustomersRequestType) (*GetCustomersResponseType, error) + + GetCustomersContext(ctx context.Context, request *GetCustomersRequestType) (*GetCustomersResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeleteOneCustomer(request *DeleteOneCustomerRequestType) (*DeleteOneCustomerResponseType, error) + + DeleteOneCustomerContext(ctx context.Context, request *DeleteOneCustomerRequestType) (*DeleteOneCustomerResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetCustomerPrefs(request *GetCustomerPrefsRequestType) (*GetCustomerPrefsResponseType, error) + + GetCustomerPrefsContext(ctx context.Context, request *GetCustomerPrefsRequestType) (*GetCustomerPrefsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + SetCustomerPrefs(request *SetCustomerPrefsRequestType) (*SetCustomerPrefsResponseType, error) + + SetCustomerPrefsContext(ctx context.Context, request *SetCustomerPrefsRequestType) (*SetCustomerPrefsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetCustomerIPACL(request *GetCustomerIPACLRequestType) (*GetCustomerIPACLResponseType, error) + + GetCustomerIPACLContext(ctx context.Context, request *GetCustomerIPACLRequestType) (*GetCustomerIPACLResponseType, error) + + // Error can be either of the following types: + // + // - fault + + SetCustomerIPACL(request *SetCustomerIPACLRequestType) (*SetCustomerIPACLResponseType, error) + + SetCustomerIPACLContext(ctx context.Context, request *SetCustomerIPACLRequestType) (*SetCustomerIPACLResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CreateCustomerOracleMetadata(request *CreateCustomerOracleMetadataRequestType) (*CreateCustomerOracleMetadataResponseType, error) + + CreateCustomerOracleMetadataContext(ctx context.Context, request *CreateCustomerOracleMetadataRequestType) (*CreateCustomerOracleMetadataResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateCustomerOracleMetadata(request *UpdateCustomerOracleMetadataRequestType) (*UpdateCustomerOracleMetadataResponseType, error) + + UpdateCustomerOracleMetadataContext(ctx context.Context, request *UpdateCustomerOracleMetadataRequestType) (*UpdateCustomerOracleMetadataResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetCustomerOracleMetadata(request *GetCustomerOracleMetadataRequestType) (*GetCustomerOracleMetadataResponseType, error) + + GetCustomerOracleMetadataContext(ctx context.Context, request *GetCustomerOracleMetadataRequestType) (*GetCustomerOracleMetadataResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeleteCustomerOracleMetadata(request *DeleteCustomerOracleMetadataRequestType) (*DeleteCustomerOracleMetadataResponseType, error) + + DeleteCustomerOracleMetadataContext(ctx context.Context, request *DeleteCustomerOracleMetadataRequestType) (*DeleteCustomerOracleMetadataResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CreateZoneOracleMetadata(request *CreateZoneOracleMetadataRequestType) (*CreateZoneOracleMetadataResponseType, error) + + CreateZoneOracleMetadataContext(ctx context.Context, request *CreateZoneOracleMetadataRequestType) (*CreateZoneOracleMetadataResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateZoneOracleMetadata(request *UpdateZoneOracleMetadataRequestType) (*UpdateZoneOracleMetadataResponseType, error) + + UpdateZoneOracleMetadataContext(ctx context.Context, request *UpdateZoneOracleMetadataRequestType) (*UpdateZoneOracleMetadataResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetZoneOracleMetadata(request *GetZoneOracleMetadataRequestType) (*GetZoneOracleMetadataResponseType, error) + + GetZoneOracleMetadataContext(ctx context.Context, request *GetZoneOracleMetadataRequestType) (*GetZoneOracleMetadataResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeleteZoneOracleMetadata(request *DeleteZoneOracleMetadataRequestType) (*DeleteZoneOracleMetadataResponseType, error) + + DeleteZoneOracleMetadataContext(ctx context.Context, request *DeleteZoneOracleMetadataRequestType) (*DeleteZoneOracleMetadataResponseType, error) + + // Error can be either of the following types: + // + // - fault + + OCIMigrate(request *OCIMigrateRequestType) (*OCIMigrateResponseType, error) + + OCIMigrateContext(ctx context.Context, request *OCIMigrateRequestType) (*OCIMigrateResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new Dynamic DNS service */ + CreateDDNS(request *CreateDDNSRequestType) (*CreateDDNSResponseType, error) + + CreateDDNSContext(ctx context.Context, request *CreateDDNSRequestType) (*CreateDDNSResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single Dynamic DNS service */ + GetOneDDNS(request *GetOneDDNSRequestType) (*GetOneDDNSResponseType, error) + + GetOneDDNSContext(ctx context.Context, request *GetOneDDNSRequestType) (*GetOneDDNSResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every Dynamic DNS service */ + GetDDNSs(request *GetDDNSsRequestType) (*GetDDNSsResponseType, error) + + GetDDNSsContext(ctx context.Context, request *GetDDNSsRequestType) (*GetDDNSsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single Dynamic DNS service */ + UpdateDDNS(request *UpdateDDNSRequestType) (*UpdateDDNSResponseType, error) + + UpdateDDNSContext(ctx context.Context, request *UpdateDDNSRequestType) (*UpdateDDNSResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single Dynamic DNS service */ + DeleteOneDDNS(request *DeleteOneDDNSRequestType) (*DeleteOneDDNSResponseType, error) + + DeleteOneDDNSContext(ctx context.Context, request *DeleteOneDDNSRequestType) (*DeleteOneDDNSResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ActivateDDNS(request *ActivateDDNSRequestType) (*ActivateDDNSResponseType, error) + + ActivateDDNSContext(ctx context.Context, request *ActivateDDNSRequestType) (*ActivateDDNSResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeactivateDDNS(request *DeactivateDDNSRequestType) (*DeactivateDDNSResponseType, error) + + DeactivateDDNSContext(ctx context.Context, request *DeactivateDDNSRequestType) (*DeactivateDDNSResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ResetDDNS(request *ResetDDNSRequestType) (*ResetDDNSResponseType, error) + + ResetDDNSContext(ctx context.Context, request *ResetDDNSRequestType) (*ResetDDNSResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetUpdateUserPassword(request *GetUpdateUserPasswordRequestType) (*GetUpdateUserPasswordResponseType, error) + + GetUpdateUserPasswordContext(ctx context.Context, request *GetUpdateUserPasswordRequestType) (*GetUpdateUserPasswordResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CreateDDNSHost(request *CreateDDNSHostRequestType) (*CreateDDNSHostResponseType, error) + + CreateDDNSHostContext(ctx context.Context, request *CreateDDNSHostRequestType) (*CreateDDNSHostResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CreateUpdateUser(request *CreateUpdateUserRequestType) (*CreateUpdateUserResponseType, error) + + CreateUpdateUserContext(ctx context.Context, request *CreateUpdateUserRequestType) (*CreateUpdateUserResponseType, error) + + // Error can be either of the following types: + // + // - fault + + AddDDNS(request *AddDDNSRequestType) (*AddDDNSResponseType, error) + + AddDDNSContext(ctx context.Context, request *AddDDNSRequestType) (*AddDDNSResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new Simple Failover service */ + CreateFailover(request *CreateFailoverRequestType) (*CreateFailoverResponseType, error) + + CreateFailoverContext(ctx context.Context, request *CreateFailoverRequestType) (*CreateFailoverResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single Simple Failover service */ + GetOneFailover(request *GetOneFailoverRequestType) (*GetOneFailoverResponseType, error) + + GetOneFailoverContext(ctx context.Context, request *GetOneFailoverRequestType) (*GetOneFailoverResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every Simple Failover service */ + GetFailovers(request *GetFailoversRequestType) (*GetFailoversResponseType, error) + + GetFailoversContext(ctx context.Context, request *GetFailoversRequestType) (*GetFailoversResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single Simple Failover service */ + UpdateFailover(request *UpdateFailoverRequestType) (*UpdateFailoverResponseType, error) + + UpdateFailoverContext(ctx context.Context, request *UpdateFailoverRequestType) (*UpdateFailoverResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single Simple Failover service */ + DeleteOneFailover(request *DeleteOneFailoverRequestType) (*DeleteOneFailoverResponseType, error) + + DeleteOneFailoverContext(ctx context.Context, request *DeleteOneFailoverRequestType) (*DeleteOneFailoverResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ActivateFailover(request *ActivateFailoverRequestType) (*ActivateFailoverResponseType, error) + + ActivateFailoverContext(ctx context.Context, request *ActivateFailoverRequestType) (*ActivateFailoverResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeactivateFailover(request *DeactivateFailoverRequestType) (*DeactivateFailoverResponseType, error) + + DeactivateFailoverContext(ctx context.Context, request *DeactivateFailoverRequestType) (*DeactivateFailoverResponseType, error) + + // Error can be either of the following types: + // + // - fault + + RecoverFailover(request *RecoverFailoverRequestType) (*RecoverFailoverResponseType, error) + + RecoverFailoverContext(ctx context.Context, request *RecoverFailoverRequestType) (*RecoverFailoverResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new basic LoadBalance service */ + CreateLoadBalance(request *CreateLoadBalanceRequestType) (*CreateLoadBalanceResponseType, error) + + CreateLoadBalanceContext(ctx context.Context, request *CreateLoadBalanceRequestType) (*CreateLoadBalanceResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single basic LoadBalance service */ + GetOneLoadBalance(request *GetOneLoadBalanceRequestType) (*GetOneLoadBalanceResponseType, error) + + GetOneLoadBalanceContext(ctx context.Context, request *GetOneLoadBalanceRequestType) (*GetOneLoadBalanceResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every basic LoadBalance service */ + GetLoadBalances(request *GetLoadBalancesRequestType) (*GetLoadBalancesResponseType, error) + + GetLoadBalancesContext(ctx context.Context, request *GetLoadBalancesRequestType) (*GetLoadBalancesResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single basic LoadBalance service */ + UpdateLoadBalance(request *UpdateLoadBalanceRequestType) (*UpdateLoadBalanceResponseType, error) + + UpdateLoadBalanceContext(ctx context.Context, request *UpdateLoadBalanceRequestType) (*UpdateLoadBalanceResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single basic LoadBalance service */ + DeleteOneLoadBalance(request *DeleteOneLoadBalanceRequestType) (*DeleteOneLoadBalanceResponseType, error) + + DeleteOneLoadBalanceContext(ctx context.Context, request *DeleteOneLoadBalanceRequestType) (*DeleteOneLoadBalanceResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ActivateLoadBalance(request *ActivateLoadBalanceRequestType) (*ActivateLoadBalanceResponseType, error) + + ActivateLoadBalanceContext(ctx context.Context, request *ActivateLoadBalanceRequestType) (*ActivateLoadBalanceResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeactivateLoadBalance(request *DeactivateLoadBalanceRequestType) (*DeactivateLoadBalanceResponseType, error) + + DeactivateLoadBalanceContext(ctx context.Context, request *DeactivateLoadBalanceRequestType) (*DeactivateLoadBalanceResponseType, error) + + // Error can be either of the following types: + // + // - fault + + RecoverLoadBalance(request *RecoverLoadBalanceRequestType) (*RecoverLoadBalanceResponseType, error) + + RecoverLoadBalanceContext(ctx context.Context, request *RecoverLoadBalanceRequestType) (*RecoverLoadBalanceResponseType, error) + + // Error can be either of the following types: + // + // - fault + + RecoverLoadBalanceIP(request *RecoverLoadBalanceIPRequestType) (*RecoverLoadBalanceIPResponseType, error) + + RecoverLoadBalanceIPContext(ctx context.Context, request *RecoverLoadBalanceIPRequestType) (*RecoverLoadBalanceIPResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CreateLoadBalancePoolEntry(request *CreateLoadBalancePoolEntryRequestType) (*CreateLoadBalancePoolEntryResponseType, error) + + CreateLoadBalancePoolEntryContext(ctx context.Context, request *CreateLoadBalancePoolEntryRequestType) (*CreateLoadBalancePoolEntryResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateLoadBalancePoolEntry(request *UpdateLoadBalancePoolEntryRequestType) (*UpdateLoadBalancePoolEntryResponseType, error) + + UpdateLoadBalancePoolEntryContext(ctx context.Context, request *UpdateLoadBalancePoolEntryRequestType) (*UpdateLoadBalancePoolEntryResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetOneLoadBalancePoolEntry(request *GetOneLoadBalancePoolEntryRequestType) (*GetOneLoadBalancePoolEntryResponseType, error) + + GetOneLoadBalancePoolEntryContext(ctx context.Context, request *GetOneLoadBalancePoolEntryRequestType) (*GetOneLoadBalancePoolEntryResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetLoadBalancePoolEntries(request *GetLoadBalancePoolEntriesRequestType) (*GetLoadBalancePoolEntriesResponseType, error) + + GetLoadBalancePoolEntriesContext(ctx context.Context, request *GetLoadBalancePoolEntriesRequestType) (*GetLoadBalancePoolEntriesResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeleteOneLoadBalancePoolEntry(request *DeleteOneLoadBalancePoolEntryRequestType) (*DeleteOneLoadBalancePoolEntryResponseType, error) + + DeleteOneLoadBalancePoolEntryContext(ctx context.Context, request *DeleteOneLoadBalancePoolEntryRequestType) (*DeleteOneLoadBalancePoolEntryResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new GSLB */ + CreateGSLB(request *CreateGSLBRequestType) (*CreateGSLBResponseType, error) + + CreateGSLBContext(ctx context.Context, request *CreateGSLBRequestType) (*CreateGSLBResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single GSLB */ + GetOneGSLB(request *GetOneGSLBRequestType) (*GetOneGSLBResponseType, error) + + GetOneGSLBContext(ctx context.Context, request *GetOneGSLBRequestType) (*GetOneGSLBResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every GSLB */ + GetGSLBs(request *GetGSLBsRequestType) (*GetGSLBsResponseType, error) + + GetGSLBsContext(ctx context.Context, request *GetGSLBsRequestType) (*GetGSLBsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single GSLB */ + UpdateGSLB(request *UpdateGSLBRequestType) (*UpdateGSLBResponseType, error) + + UpdateGSLBContext(ctx context.Context, request *UpdateGSLBRequestType) (*UpdateGSLBResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single GSLB */ + DeleteOneGSLB(request *DeleteOneGSLBRequestType) (*DeleteOneGSLBResponseType, error) + + DeleteOneGSLBContext(ctx context.Context, request *DeleteOneGSLBRequestType) (*DeleteOneGSLBResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ActivateGSLB(request *ActivateGSLBRequestType) (*ActivateGSLBResponseType, error) + + ActivateGSLBContext(ctx context.Context, request *ActivateGSLBRequestType) (*ActivateGSLBResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeactivateGSLB(request *DeactivateGSLBRequestType) (*DeactivateGSLBResponseType, error) + + DeactivateGSLBContext(ctx context.Context, request *DeactivateGSLBRequestType) (*DeactivateGSLBResponseType, error) + + // Error can be either of the following types: + // + // - fault + + RecoverGSLB(request *RecoverGSLBRequestType) (*RecoverGSLBResponseType, error) + + RecoverGSLBContext(ctx context.Context, request *RecoverGSLBRequestType) (*RecoverGSLBResponseType, error) + + // Error can be either of the following types: + // + // - fault + + RecoverGSLBIP(request *RecoverGSLBIPRequestType) (*RecoverGSLBIPResponseType, error) + + RecoverGSLBIPContext(ctx context.Context, request *RecoverGSLBIPRequestType) (*RecoverGSLBIPResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new GSLBRegion */ + CreateGSLBRegion(request *CreateGSLBRegionRequestType) (*CreateGSLBRegionResponseType, error) + + CreateGSLBRegionContext(ctx context.Context, request *CreateGSLBRegionRequestType) (*CreateGSLBRegionResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single GSLBRegion */ + GetOneGSLBRegion(request *GetOneGSLBRegionRequestType) (*GetOneGSLBRegionResponseType, error) + + GetOneGSLBRegionContext(ctx context.Context, request *GetOneGSLBRegionRequestType) (*GetOneGSLBRegionResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every GSLBRegion */ + GetGSLBRegions(request *GetGSLBRegionsRequestType) (*GetGSLBRegionsResponseType, error) + + GetGSLBRegionsContext(ctx context.Context, request *GetGSLBRegionsRequestType) (*GetGSLBRegionsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single GSLBRegion */ + UpdateGSLBRegion(request *UpdateGSLBRegionRequestType) (*UpdateGSLBRegionResponseType, error) + + UpdateGSLBRegionContext(ctx context.Context, request *UpdateGSLBRegionRequestType) (*UpdateGSLBRegionResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single GSLBRegion */ + DeleteOneGSLBRegion(request *DeleteOneGSLBRegionRequestType) (*DeleteOneGSLBRegionResponseType, error) + + DeleteOneGSLBRegionContext(ctx context.Context, request *DeleteOneGSLBRegionRequestType) (*DeleteOneGSLBRegionResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CreateGSLBRegionPoolEntry(request *CreateGSLBRegionPoolEntryRequestType) (*CreateGSLBRegionPoolEntryResponseType, error) + + CreateGSLBRegionPoolEntryContext(ctx context.Context, request *CreateGSLBRegionPoolEntryRequestType) (*CreateGSLBRegionPoolEntryResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateGSLBRegionPoolEntry(request *UpdateGSLBRegionPoolEntryRequestType) (*UpdateGSLBRegionPoolEntryResponseType, error) + + UpdateGSLBRegionPoolEntryContext(ctx context.Context, request *UpdateGSLBRegionPoolEntryRequestType) (*UpdateGSLBRegionPoolEntryResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetOneGSLBRegionPoolEntry(request *GetOneGSLBRegionPoolEntryRequestType) (*GetOneGSLBRegionPoolEntryResponseType, error) + + GetOneGSLBRegionPoolEntryContext(ctx context.Context, request *GetOneGSLBRegionPoolEntryRequestType) (*GetOneGSLBRegionPoolEntryResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetGSLBRegionPoolEntries(request *GetGSLBRegionPoolEntriesRequestType) (*GetGSLBRegionPoolEntriesResponseType, error) + + GetGSLBRegionPoolEntriesContext(ctx context.Context, request *GetGSLBRegionPoolEntriesRequestType) (*GetGSLBRegionPoolEntriesResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeleteOneGSLBRegionPoolEntry(request *DeleteOneGSLBRegionPoolEntryRequestType) (*DeleteOneGSLBRegionPoolEntryResponseType, error) + + DeleteOneGSLBRegionPoolEntryContext(ctx context.Context, request *DeleteOneGSLBRegionPoolEntryRequestType) (*DeleteOneGSLBRegionPoolEntryResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new RTTM */ + CreateRTTM(request *CreateRTTMRequestType) (*CreateRTTMResponseType, error) + + CreateRTTMContext(ctx context.Context, request *CreateRTTMRequestType) (*CreateRTTMResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single RTTM */ + GetOneRTTM(request *GetOneRTTMRequestType) (*GetOneRTTMResponseType, error) + + GetOneRTTMContext(ctx context.Context, request *GetOneRTTMRequestType) (*GetOneRTTMResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every RTTM */ + GetRTTMs(request *GetRTTMsRequestType) (*GetRTTMsResponseType, error) + + GetRTTMsContext(ctx context.Context, request *GetRTTMsRequestType) (*GetRTTMsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single RTTM */ + UpdateRTTM(request *UpdateRTTMRequestType) (*UpdateRTTMResponseType, error) + + UpdateRTTMContext(ctx context.Context, request *UpdateRTTMRequestType) (*UpdateRTTMResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single RTTM */ + DeleteOneRTTM(request *DeleteOneRTTMRequestType) (*DeleteOneRTTMResponseType, error) + + DeleteOneRTTMContext(ctx context.Context, request *DeleteOneRTTMRequestType) (*DeleteOneRTTMResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ActivateRTTM(request *ActivateRTTMRequestType) (*ActivateRTTMResponseType, error) + + ActivateRTTMContext(ctx context.Context, request *ActivateRTTMRequestType) (*ActivateRTTMResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeactivateRTTM(request *DeactivateRTTMRequestType) (*DeactivateRTTMResponseType, error) + + DeactivateRTTMContext(ctx context.Context, request *DeactivateRTTMRequestType) (*DeactivateRTTMResponseType, error) + + // Error can be either of the following types: + // + // - fault + + RecoverRTTM(request *RecoverRTTMRequestType) (*RecoverRTTMResponseType, error) + + RecoverRTTMContext(ctx context.Context, request *RecoverRTTMRequestType) (*RecoverRTTMResponseType, error) + + // Error can be either of the following types: + // + // - fault + + RecoverRTTMIP(request *RecoverRTTMIPRequestType) (*RecoverRTTMIPResponseType, error) + + RecoverRTTMIPContext(ctx context.Context, request *RecoverRTTMIPRequestType) (*RecoverRTTMIPResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetRTTMLogs(request *GetRTTMLogsRequestType) (*GetRTTMLogsResponseType, error) + + GetRTTMLogsContext(ctx context.Context, request *GetRTTMLogsRequestType) (*GetRTTMLogsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetRTTMRRSets(request *GetRTTMRRSetsRequestType) (*GetRTTMRRSetsResponseType, error) + + GetRTTMRRSetsContext(ctx context.Context, request *GetRTTMRRSetsRequestType) (*GetRTTMRRSetsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new RTTMRegion */ + CreateRTTMRegion(request *CreateRTTMRegionRequestType) (*CreateRTTMRegionResponseType, error) + + CreateRTTMRegionContext(ctx context.Context, request *CreateRTTMRegionRequestType) (*CreateRTTMRegionResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single RTTMRegion */ + GetOneRTTMRegion(request *GetOneRTTMRegionRequestType) (*GetOneRTTMRegionResponseType, error) + + GetOneRTTMRegionContext(ctx context.Context, request *GetOneRTTMRegionRequestType) (*GetOneRTTMRegionResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every RTTMRegion */ + GetRTTMRegions(request *GetRTTMRegionsRequestType) (*GetRTTMRegionsResponseType, error) + + GetRTTMRegionsContext(ctx context.Context, request *GetRTTMRegionsRequestType) (*GetRTTMRegionsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single RTTMRegion */ + UpdateRTTMRegion(request *UpdateRTTMRegionRequestType) (*UpdateRTTMRegionResponseType, error) + + UpdateRTTMRegionContext(ctx context.Context, request *UpdateRTTMRegionRequestType) (*UpdateRTTMRegionResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single RTTMRegion */ + DeleteOneRTTMRegion(request *DeleteOneRTTMRegionRequestType) (*DeleteOneRTTMRegionResponseType, error) + + DeleteOneRTTMRegionContext(ctx context.Context, request *DeleteOneRTTMRegionRequestType) (*DeleteOneRTTMRegionResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CreateRTTMRegionPoolEntry(request *CreateRTTMRegionPoolEntryRequestType) (*CreateRTTMRegionPoolEntryResponseType, error) + + CreateRTTMRegionPoolEntryContext(ctx context.Context, request *CreateRTTMRegionPoolEntryRequestType) (*CreateRTTMRegionPoolEntryResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateRTTMRegionPoolEntry(request *UpdateRTTMRegionPoolEntryRequestType) (*UpdateRTTMRegionPoolEntryResponseType, error) + + UpdateRTTMRegionPoolEntryContext(ctx context.Context, request *UpdateRTTMRegionPoolEntryRequestType) (*UpdateRTTMRegionPoolEntryResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetOneRTTMRegionPoolEntry(request *GetOneRTTMRegionPoolEntryRequestType) (*GetOneRTTMRegionPoolEntryResponseType, error) + + GetOneRTTMRegionPoolEntryContext(ctx context.Context, request *GetOneRTTMRegionPoolEntryRequestType) (*GetOneRTTMRegionPoolEntryResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetRTTMRegionPoolEntries(request *GetRTTMRegionPoolEntriesRequestType) (*GetRTTMRegionPoolEntriesResponseType, error) + + GetRTTMRegionPoolEntriesContext(ctx context.Context, request *GetRTTMRegionPoolEntriesRequestType) (*GetRTTMRegionPoolEntriesResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeleteOneRTTMRegionPoolEntry(request *DeleteOneRTTMRegionPoolEntryRequestType) (*DeleteOneRTTMRegionPoolEntryResponseType, error) + + DeleteOneRTTMRegionPoolEntryContext(ctx context.Context, request *DeleteOneRTTMRegionPoolEntryRequestType) (*DeleteOneRTTMRegionPoolEntryResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new HTTPRedirect */ + CreateHTTPRedirect(request *CreateHTTPRedirectRequestType) (*CreateHTTPRedirectResponseType, error) + + CreateHTTPRedirectContext(ctx context.Context, request *CreateHTTPRedirectRequestType) (*CreateHTTPRedirectResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single HTTPRedirect */ + GetOneHTTPRedirect(request *GetOneHTTPRedirectRequestType) (*GetOneHTTPRedirectResponseType, error) + + GetOneHTTPRedirectContext(ctx context.Context, request *GetOneHTTPRedirectRequestType) (*GetOneHTTPRedirectResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every HTTPRedirect */ + GetHTTPRedirects(request *GetHTTPRedirectsRequestType) (*GetHTTPRedirectsResponseType, error) + + GetHTTPRedirectsContext(ctx context.Context, request *GetHTTPRedirectsRequestType) (*GetHTTPRedirectsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single HTTPRedirect */ + UpdateHTTPRedirect(request *UpdateHTTPRedirectRequestType) (*UpdateHTTPRedirectResponseType, error) + + UpdateHTTPRedirectContext(ctx context.Context, request *UpdateHTTPRedirectRequestType) (*UpdateHTTPRedirectResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single HTTPRedirect */ + DeleteOneHTTPRedirect(request *DeleteOneHTTPRedirectRequestType) (*DeleteOneHTTPRedirectResponseType, error) + + DeleteOneHTTPRedirectContext(ctx context.Context, request *DeleteOneHTTPRedirectRequestType) (*DeleteOneHTTPRedirectResponseType, error) + + // Error can be either of the following types: + // + // - fault + + CreateAdvRedirectRule(request *CreateAdvRedirectRuleRequestType) (*CreateAdvRedirectRuleResponseType, error) + + CreateAdvRedirectRuleContext(ctx context.Context, request *CreateAdvRedirectRuleRequestType) (*CreateAdvRedirectRuleResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UpdateAdvRedirectRule(request *UpdateAdvRedirectRuleRequestType) (*UpdateAdvRedirectRuleResponseType, error) + + UpdateAdvRedirectRuleContext(ctx context.Context, request *UpdateAdvRedirectRuleRequestType) (*UpdateAdvRedirectRuleResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetOneAdvRedirectRule(request *GetOneAdvRedirectRuleRequestType) (*GetOneAdvRedirectRuleResponseType, error) + + GetOneAdvRedirectRuleContext(ctx context.Context, request *GetOneAdvRedirectRuleRequestType) (*GetOneAdvRedirectRuleResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetAdvRedirectRules(request *GetAdvRedirectRulesRequestType) (*GetAdvRedirectRulesResponseType, error) + + GetAdvRedirectRulesContext(ctx context.Context, request *GetAdvRedirectRulesRequestType) (*GetAdvRedirectRulesResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeleteOneAdvRedirectRule(request *DeleteOneAdvRedirectRuleRequestType) (*DeleteOneAdvRedirectRuleResponseType, error) + + DeleteOneAdvRedirectRuleContext(ctx context.Context, request *DeleteOneAdvRedirectRuleRequestType) (*DeleteOneAdvRedirectRuleResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new AdvRedirect */ + CreateAdvRedirect(request *CreateAdvRedirectRequestType) (*CreateAdvRedirectResponseType, error) + + CreateAdvRedirectContext(ctx context.Context, request *CreateAdvRedirectRequestType) (*CreateAdvRedirectResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single AdvRedirect */ + GetOneAdvRedirect(request *GetOneAdvRedirectRequestType) (*GetOneAdvRedirectResponseType, error) + + GetOneAdvRedirectContext(ctx context.Context, request *GetOneAdvRedirectRequestType) (*GetOneAdvRedirectResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every AdvRedirect */ + GetAdvRedirects(request *GetAdvRedirectsRequestType) (*GetAdvRedirectsResponseType, error) + + GetAdvRedirectsContext(ctx context.Context, request *GetAdvRedirectsRequestType) (*GetAdvRedirectsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single AdvRedirect */ + UpdateAdvRedirect(request *UpdateAdvRedirectRequestType) (*UpdateAdvRedirectResponseType, error) + + UpdateAdvRedirectContext(ctx context.Context, request *UpdateAdvRedirectRequestType) (*UpdateAdvRedirectResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeleteOneAdvRedirect(request *DeleteOneAdvRedirectRequestType) (*DeleteOneAdvRedirectResponseType, error) + + DeleteOneAdvRedirectContext(ctx context.Context, request *DeleteOneAdvRedirectRequestType) (*DeleteOneAdvRedirectResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetNodeList(request *GetNodeListRequestType) (*GetNodeListResponseType, error) + + GetNodeListContext(ctx context.Context, request *GetNodeListRequestType) (*GetNodeListResponseType, error) + + // Error can be either of the following types: + // + // - fault + + PublishZone(request *PublishZoneRequestType) (*PublishZoneResponseType, error) + + PublishZoneContext(ctx context.Context, request *PublishZoneRequestType) (*PublishZoneResponseType, error) + + // Error can be either of the following types: + // + // - fault + + PruneZone(request *PruneZoneRequestType) (*PruneZoneResponseType, error) + + PruneZoneContext(ctx context.Context, request *PruneZoneRequestType) (*PruneZoneResponseType, error) + + // Error can be either of the following types: + // + // - fault + + FreezeZone(request *FreezeZoneRequestType) (*FreezeZoneResponseType, error) + + FreezeZoneContext(ctx context.Context, request *FreezeZoneRequestType) (*FreezeZoneResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ThawZone(request *ThawZoneRequestType) (*ThawZoneResponseType, error) + + ThawZoneContext(ctx context.Context, request *ThawZoneRequestType) (*ThawZoneResponseType, error) + + // Error can be either of the following types: + // + // - fault + + RestoreZone(request *RestoreZoneRequestType) (*RestoreZoneResponseType, error) + + RestoreZoneContext(ctx context.Context, request *RestoreZoneRequestType) (*RestoreZoneResponseType, error) + + // Error can be either of the following types: + // + // - fault + + BlockZone(request *BlockZoneRequestType) (*BlockZoneResponseType, error) + + BlockZoneContext(ctx context.Context, request *BlockZoneRequestType) (*BlockZoneResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeleteZoneChangeset(request *DeleteZoneChangesetRequestType) (*DeleteZoneChangesetResponseType, error) + + DeleteZoneChangesetContext(ctx context.Context, request *DeleteZoneChangesetRequestType) (*DeleteZoneChangesetResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetZoneChangeset(request *GetZoneChangesetRequestType) (*GetZoneChangesetResponseType, error) + + GetZoneChangesetContext(ctx context.Context, request *GetZoneChangesetRequestType) (*GetZoneChangesetResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetZoneNotes(request *GetZoneNotesRequestType) (*GetZoneNotesResponseType, error) + + GetZoneNotesContext(ctx context.Context, request *GetZoneNotesRequestType) (*GetZoneNotesResponseType, error) + + // Error can be either of the following types: + // + // - fault + + UploadZoneFile(request *UploadZoneFileRequestType) (*UploadZoneFileResponseType, error) + + UploadZoneFileContext(ctx context.Context, request *UploadZoneFileRequestType) (*UploadZoneFileResponseType, error) + + // Error can be either of the following types: + // + // - fault + + TransferZoneIn(request *TransferZoneInRequestType) (*TransferZoneInResponseType, error) + + TransferZoneInContext(ctx context.Context, request *TransferZoneInRequestType) (*TransferZoneInResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetTransferStatus(request *GetTransferStatusRequestType) (*GetTransferStatusResponseType, error) + + GetTransferStatusContext(ctx context.Context, request *GetTransferStatusRequestType) (*GetTransferStatusResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetZoneConfigOptions(request *GetZoneConfigOptionsRequestType) (*GetZoneConfigOptionsResponseType, error) + + GetZoneConfigOptionsContext(ctx context.Context, request *GetZoneConfigOptionsRequestType) (*GetZoneConfigOptionsResponseType, error) + + // Error can be either of the following types: + // + // - fault + + SetZoneConfigOptions(request *SetZoneConfigOptionsRequestType) (*SetZoneConfigOptionsResponseType, error) + + SetZoneConfigOptionsContext(ctx context.Context, request *SetZoneConfigOptionsRequestType) (*SetZoneConfigOptionsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new IPTrack */ + CreateIPTrack(request *CreateIPTrackRequestType) (*CreateIPTrackResponseType, error) + + CreateIPTrackContext(ctx context.Context, request *CreateIPTrackRequestType) (*CreateIPTrackResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single IPTrack */ + GetOneIPTrack(request *GetOneIPTrackRequestType) (*GetOneIPTrackResponseType, error) + + GetOneIPTrackContext(ctx context.Context, request *GetOneIPTrackRequestType) (*GetOneIPTrackResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every IPTrack */ + GetIPTracks(request *GetIPTracksRequestType) (*GetIPTracksResponseType, error) + + GetIPTracksContext(ctx context.Context, request *GetIPTracksRequestType) (*GetIPTracksResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single IPTrack */ + UpdateIPTrack(request *UpdateIPTrackRequestType) (*UpdateIPTrackResponseType, error) + + UpdateIPTrackContext(ctx context.Context, request *UpdateIPTrackRequestType) (*UpdateIPTrackResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single IPTrack */ + DeleteOneIPTrack(request *DeleteOneIPTrackRequestType) (*DeleteOneIPTrackResponseType, error) + + DeleteOneIPTrackContext(ctx context.Context, request *DeleteOneIPTrackRequestType) (*DeleteOneIPTrackResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ActivateIPTrack(request *ActivateIPTrackRequestType) (*ActivateIPTrackResponseType, error) + + ActivateIPTrackContext(ctx context.Context, request *ActivateIPTrackRequestType) (*ActivateIPTrackResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeactivateIPTrack(request *DeactivateIPTrackRequestType) (*DeactivateIPTrackResponseType, error) + + DeactivateIPTrackContext(ctx context.Context, request *DeactivateIPTrackRequestType) (*DeactivateIPTrackResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new DNSSEC */ + CreateDNSSEC(request *CreateDNSSECRequestType) (*CreateDNSSECResponseType, error) + + CreateDNSSECContext(ctx context.Context, request *CreateDNSSECRequestType) (*CreateDNSSECResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single DNSSEC */ + GetOneDNSSEC(request *GetOneDNSSECRequestType) (*GetOneDNSSECResponseType, error) + + GetOneDNSSECContext(ctx context.Context, request *GetOneDNSSECRequestType) (*GetOneDNSSECResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every DNSSEC */ + GetDNSSECs(request *GetDNSSECsRequestType) (*GetDNSSECsResponseType, error) + + GetDNSSECsContext(ctx context.Context, request *GetDNSSECsRequestType) (*GetDNSSECsResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single DNSSEC */ + UpdateDNSSEC(request *UpdateDNSSECRequestType) (*UpdateDNSSECResponseType, error) + + UpdateDNSSECContext(ctx context.Context, request *UpdateDNSSECRequestType) (*UpdateDNSSECResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single DNSSEC */ + DeleteOneDNSSEC(request *DeleteOneDNSSECRequestType) (*DeleteOneDNSSECResponseType, error) + + DeleteOneDNSSECContext(ctx context.Context, request *DeleteOneDNSSECRequestType) (*DeleteOneDNSSECResponseType, error) + + // Error can be either of the following types: + // + // - fault + + ActivateDNSSEC(request *ActivateDNSSECRequestType) (*ActivateDNSSECResponseType, error) + + ActivateDNSSECContext(ctx context.Context, request *ActivateDNSSECRequestType) (*ActivateDNSSECResponseType, error) + + // Error can be either of the following types: + // + // - fault + + DeactivateDNSSEC(request *DeactivateDNSSECRequestType) (*DeactivateDNSSECResponseType, error) + + DeactivateDNSSECContext(ctx context.Context, request *DeactivateDNSSECRequestType) (*DeactivateDNSSECResponseType, error) + + // Error can be either of the following types: + // + // - fault + + GetDNSSECTimeline(request *GetDNSSECTimelineRequestType) (*GetDNSSECTimelineResponseType, error) + + GetDNSSECTimelineContext(ctx context.Context, request *GetDNSSECTimelineRequestType) (*GetDNSSECTimelineResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every Task */ + GetTasks(request *GetTasksRequestType) (*GetTasksResponseType, error) + + GetTasksContext(ctx context.Context, request *GetTasksRequestType) (*GetTasksResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single Task */ + GetOneTask(request *GetOneTaskRequestType) (*GetOneTaskResponseType, error) + + GetOneTaskContext(ctx context.Context, request *GetOneTaskRequestType) (*GetOneTaskResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Cancels a Task */ + CancelTask(request *CancelTaskRequestType) (*CancelTaskResponseType, error) + + CancelTaskContext(ctx context.Context, request *CancelTaskRequestType) (*CancelTaskResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Creates a new ExtNameserver */ + CreateExtNameserver(request *CreateExtNameserverRequestType) (*CreateExtNameserverResponseType, error) + + CreateExtNameserverContext(ctx context.Context, request *CreateExtNameserverRequestType) (*CreateExtNameserverResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds single ExtNameserver */ + GetOneExtNameserver(request *GetOneExtNameserverRequestType) (*GetOneExtNameserverResponseType, error) + + GetOneExtNameserverContext(ctx context.Context, request *GetOneExtNameserverRequestType) (*GetOneExtNameserverResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Finds every ExtNameserver */ + GetExtNameservers(request *GetExtNameserversRequestType) (*GetExtNameserversResponseType, error) + + GetExtNameserversContext(ctx context.Context, request *GetExtNameserversRequestType) (*GetExtNameserversResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Updates a single ExtNameserver */ + UpdateExtNameserver(request *UpdateExtNameserverRequestType) (*UpdateExtNameserverResponseType, error) + + UpdateExtNameserverContext(ctx context.Context, request *UpdateExtNameserverRequestType) (*UpdateExtNameserverResponseType, error) + + // Error can be either of the following types: + // + // - fault + /* Deletes a single ExtNameserver */ + DeleteOneExtNameserver(request *DeleteOneExtNameserverRequestType) (*DeleteOneExtNameserverResponseType, error) + + DeleteOneExtNameserverContext(ctx context.Context, request *DeleteOneExtNameserverRequestType) (*DeleteOneExtNameserverResponseType, error) +} + +type dynect struct { + client *soap.Client +} + +func NewDynect(client *soap.Client) Dynect { + return &dynect{ + client: client, + } +} + +func (service *dynect) GetJobContext(ctx context.Context, request *GetJobRequestType) (*GetJobResponseType, error) { + response := new(GetJobResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetJob(request *GetJobRequestType) (*GetJobResponseType, error) { + return service.GetJobContext( + context.Background(), + request, + ) +} + +func (service *dynect) SessionLoginContext(ctx context.Context, request *SessionLoginRequestType) (*SessionLoginResponseType, error) { + response := new(SessionLoginResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) SessionLogin(request *SessionLoginRequestType) (*SessionLoginResponseType, error) { + return service.SessionLoginContext( + context.Background(), + request, + ) +} + +func (service *dynect) SessionLogoutContext(ctx context.Context, request *SessionLogoutRequestType) (*SessionLogoutResponseType, error) { + response := new(SessionLogoutResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) SessionLogout(request *SessionLogoutRequestType) (*SessionLogoutResponseType, error) { + return service.SessionLogoutContext( + context.Background(), + request, + ) +} + +func (service *dynect) SessionIsAliveContext(ctx context.Context, request *SessionIsAliveRequestType) (*SessionIsAliveResponseType, error) { + response := new(SessionIsAliveResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) SessionIsAlive(request *SessionIsAliveRequestType) (*SessionIsAliveResponseType, error) { + return service.SessionIsAliveContext( + context.Background(), + request, + ) +} + +func (service *dynect) SessionKeepAliveContext(ctx context.Context, request *SessionKeepAliveRequestType) (*SessionKeepAliveResponseType, error) { + response := new(SessionKeepAliveResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) SessionKeepAlive(request *SessionKeepAliveRequestType) (*SessionKeepAliveResponseType, error) { + return service.SessionKeepAliveContext( + context.Background(), + request, + ) +} + +func (service *dynect) ScopeInContext(ctx context.Context, request *ScopeInRequestType) (*ScopeInResponseType, error) { + response := new(ScopeInResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ScopeIn(request *ScopeInRequestType) (*ScopeInResponseType, error) { + return service.ScopeInContext( + context.Background(), + request, + ) +} + +func (service *dynect) ScopeAsContext(ctx context.Context, request *ScopeAsRequestType) (*ScopeAsResponseType, error) { + response := new(ScopeAsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ScopeAs(request *ScopeAsRequestType) (*ScopeAsResponseType, error) { + return service.ScopeAsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UnscopeContext(ctx context.Context, request *UnscopeRequestType) (*UnscopeResponseType, error) { + response := new(UnscopeResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) Unscope(request *UnscopeRequestType) (*UnscopeResponseType, error) { + return service.UnscopeContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetQueryStatsContext(ctx context.Context, request *GetQueryStatsRequestType) (*GetQueryStatsResponseType, error) { + response := new(GetQueryStatsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetQueryStats(request *GetQueryStatsRequestType) (*GetQueryStatsResponseType, error) { + return service.GetQueryStatsContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateGeoContext(ctx context.Context, request *CreateGeoRequestType) (*CreateGeoResponseType, error) { + response := new(CreateGeoResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateGeo(request *CreateGeoRequestType) (*CreateGeoResponseType, error) { + return service.CreateGeoContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateGeoContext(ctx context.Context, request *UpdateGeoRequestType) (*UpdateGeoResponseType, error) { + response := new(UpdateGeoResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateGeo(request *UpdateGeoRequestType) (*UpdateGeoResponseType, error) { + return service.UpdateGeoContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetGeosContext(ctx context.Context, request *GetGeosRequestType) (*GetGeosResponseType, error) { + response := new(GetGeosResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetGeos(request *GetGeosRequestType) (*GetGeosResponseType, error) { + return service.GetGeosContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneGeoContext(ctx context.Context, request *GetOneGeoRequestType) (*GetOneGeoResponseType, error) { + response := new(GetOneGeoResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneGeo(request *GetOneGeoRequestType) (*GetOneGeoResponseType, error) { + return service.GetOneGeoContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneGeoContext(ctx context.Context, request *DeleteOneGeoRequestType) (*DeleteOneGeoResponseType, error) { + response := new(DeleteOneGeoResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneGeo(request *DeleteOneGeoRequestType) (*DeleteOneGeoResponseType, error) { + return service.DeleteOneGeoContext( + context.Background(), + request, + ) +} + +func (service *dynect) ActivateGeoContext(ctx context.Context, request *ActivateGeoRequestType) (*ActivateGeoResponseType, error) { + response := new(ActivateGeoResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ActivateGeo(request *ActivateGeoRequestType) (*ActivateGeoResponseType, error) { + return service.ActivateGeoContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeactivateGeoContext(ctx context.Context, request *DeactivateGeoRequestType) (*DeactivateGeoResponseType, error) { + response := new(DeactivateGeoResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeactivateGeo(request *DeactivateGeoRequestType) (*DeactivateGeoResponseType, error) { + return service.DeactivateGeoContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateGeoRegionGroupContext(ctx context.Context, request *CreateGeoRegionGroupRequestType) (*CreateGeoRegionGroupResponseType, error) { + response := new(CreateGeoRegionGroupResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateGeoRegionGroup(request *CreateGeoRegionGroupRequestType) (*CreateGeoRegionGroupResponseType, error) { + return service.CreateGeoRegionGroupContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateGeoRegionGroupContext(ctx context.Context, request *UpdateGeoRegionGroupRequestType) (*UpdateGeoRegionGroupResponseType, error) { + response := new(UpdateGeoRegionGroupResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateGeoRegionGroup(request *UpdateGeoRegionGroupRequestType) (*UpdateGeoRegionGroupResponseType, error) { + return service.UpdateGeoRegionGroupContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneGeoRegionGroupContext(ctx context.Context, request *DeleteOneGeoRegionGroupRequestType) (*DeleteOneGeoRegionGroupResponseType, error) { + response := new(DeleteOneGeoRegionGroupResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneGeoRegionGroup(request *DeleteOneGeoRegionGroupRequestType) (*DeleteOneGeoRegionGroupResponseType, error) { + return service.DeleteOneGeoRegionGroupContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetGeoRegionGroupsContext(ctx context.Context, request *GetGeoRegionGroupsRequestType) (*GetGeoRegionGroupsResponseType, error) { + response := new(GetGeoRegionGroupsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetGeoRegionGroups(request *GetGeoRegionGroupsRequestType) (*GetGeoRegionGroupsResponseType, error) { + return service.GetGeoRegionGroupsContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneGeoRegionGroupContext(ctx context.Context, request *GetOneGeoRegionGroupRequestType) (*GetOneGeoRegionGroupResponseType, error) { + response := new(GetOneGeoRegionGroupResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneGeoRegionGroup(request *GetOneGeoRegionGroupRequestType) (*GetOneGeoRegionGroupResponseType, error) { + return service.GetOneGeoRegionGroupContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateGeoNodeContext(ctx context.Context, request *CreateGeoNodeRequestType) (*CreateGeoNodeResponseType, error) { + response := new(CreateGeoNodeResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateGeoNode(request *CreateGeoNodeRequestType) (*CreateGeoNodeResponseType, error) { + return service.CreateGeoNodeContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneGeoNodeContext(ctx context.Context, request *DeleteOneGeoNodeRequestType) (*DeleteOneGeoNodeResponseType, error) { + response := new(DeleteOneGeoNodeResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneGeoNode(request *DeleteOneGeoNodeRequestType) (*DeleteOneGeoNodeResponseType, error) { + return service.DeleteOneGeoNodeContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetGeoNodesContext(ctx context.Context, request *GetGeoNodesRequestType) (*GetGeoNodesResponseType, error) { + response := new(GetGeoNodesResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetGeoNodes(request *GetGeoNodesRequestType) (*GetGeoNodesResponseType, error) { + return service.GetGeoNodesContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateDSFContext(ctx context.Context, request *CreateDSFRequestType) (*CreateDSFResponseType, error) { + response := new(CreateDSFResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateDSF(request *CreateDSFRequestType) (*CreateDSFResponseType, error) { + return service.CreateDSFContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateDSFContext(ctx context.Context, request *UpdateDSFRequestType) (*UpdateDSFResponseType, error) { + response := new(UpdateDSFResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateDSF(request *UpdateDSFRequestType) (*UpdateDSFResponseType, error) { + return service.UpdateDSFContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetDSFsContext(ctx context.Context, request *GetDSFsRequestType) (*GetDSFsResponseType, error) { + response := new(GetDSFsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetDSFs(request *GetDSFsRequestType) (*GetDSFsResponseType, error) { + return service.GetDSFsContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetDSFNotifiersContext(ctx context.Context, request *GetDSFNotifiersRequestType) (*GetDSFNotifiersResponseType, error) { + response := new(GetDSFNotifiersResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetDSFNotifiers(request *GetDSFNotifiersRequestType) (*GetDSFNotifiersResponseType, error) { + return service.GetDSFNotifiersContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneDSFContext(ctx context.Context, request *DeleteOneDSFRequestType) (*DeleteOneDSFResponseType, error) { + response := new(DeleteOneDSFResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneDSF(request *DeleteOneDSFRequestType) (*DeleteOneDSFResponseType, error) { + return service.DeleteOneDSFContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneDSFContext(ctx context.Context, request *GetOneDSFRequestType) (*GetOneDSFResponseType, error) { + response := new(GetOneDSFResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneDSF(request *GetOneDSFRequestType) (*GetOneDSFResponseType, error) { + return service.GetOneDSFContext( + context.Background(), + request, + ) +} + +func (service *dynect) RevertDSFContext(ctx context.Context, request *RevertDSFRequestType) (*RevertDSFResponseType, error) { + response := new(RevertDSFResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) RevertDSF(request *RevertDSFRequestType) (*RevertDSFResponseType, error) { + return service.RevertDSFContext( + context.Background(), + request, + ) +} + +func (service *dynect) PublishDSFContext(ctx context.Context, request *PublishDSFRequestType) (*PublishDSFResponseType, error) { + response := new(PublishDSFResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) PublishDSF(request *PublishDSFRequestType) (*PublishDSFResponseType, error) { + return service.PublishDSFContext( + context.Background(), + request, + ) +} + +func (service *dynect) AddDSFNotifierContext(ctx context.Context, request *AddDSFNotifierRequestType) (*AddDSFNotifierResponseType, error) { + response := new(AddDSFNotifierResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) AddDSFNotifier(request *AddDSFNotifierRequestType) (*AddDSFNotifierResponseType, error) { + return service.AddDSFNotifierContext( + context.Background(), + request, + ) +} + +func (service *dynect) RemoveDSFNotifierContext(ctx context.Context, request *RemoveDSFNotifierRequestType) (*RemoveDSFNotifierResponseType, error) { + response := new(RemoveDSFNotifierResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) RemoveDSFNotifier(request *RemoveDSFNotifierRequestType) (*RemoveDSFNotifierResponseType, error) { + return service.RemoveDSFNotifierContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateDSFRulesetContext(ctx context.Context, request *CreateDSFRulesetRequestType) (*CreateDSFRulesetResponseType, error) { + response := new(CreateDSFRulesetResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateDSFRuleset(request *CreateDSFRulesetRequestType) (*CreateDSFRulesetResponseType, error) { + return service.CreateDSFRulesetContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateDSFRulesetContext(ctx context.Context, request *UpdateDSFRulesetRequestType) (*UpdateDSFRulesetResponseType, error) { + response := new(UpdateDSFRulesetResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateDSFRuleset(request *UpdateDSFRulesetRequestType) (*UpdateDSFRulesetResponseType, error) { + return service.UpdateDSFRulesetContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetDSFRulesetsContext(ctx context.Context, request *GetDSFRulesetsRequestType) (*GetDSFRulesetsResponseType, error) { + response := new(GetDSFRulesetsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetDSFRulesets(request *GetDSFRulesetsRequestType) (*GetDSFRulesetsResponseType, error) { + return service.GetDSFRulesetsContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneDSFRulesetContext(ctx context.Context, request *GetOneDSFRulesetRequestType) (*GetOneDSFRulesetResponseType, error) { + response := new(GetOneDSFRulesetResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneDSFRuleset(request *GetOneDSFRulesetRequestType) (*GetOneDSFRulesetResponseType, error) { + return service.GetOneDSFRulesetContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneDSFRulesetContext(ctx context.Context, request *DeleteOneDSFRulesetRequestType) (*DeleteOneDSFRulesetResponseType, error) { + response := new(DeleteOneDSFRulesetResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneDSFRuleset(request *DeleteOneDSFRulesetRequestType) (*DeleteOneDSFRulesetResponseType, error) { + return service.DeleteOneDSFRulesetContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateDSFResponsePoolContext(ctx context.Context, request *CreateDSFResponsePoolRequestType) (*CreateDSFResponsePoolResponseType, error) { + response := new(CreateDSFResponsePoolResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateDSFResponsePool(request *CreateDSFResponsePoolRequestType) (*CreateDSFResponsePoolResponseType, error) { + return service.CreateDSFResponsePoolContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateDSFResponsePoolContext(ctx context.Context, request *UpdateDSFResponsePoolRequestType) (*UpdateDSFResponsePoolResponseType, error) { + response := new(UpdateDSFResponsePoolResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateDSFResponsePool(request *UpdateDSFResponsePoolRequestType) (*UpdateDSFResponsePoolResponseType, error) { + return service.UpdateDSFResponsePoolContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetDSFResponsePoolsContext(ctx context.Context, request *GetDSFResponsePoolsRequestType) (*GetDSFResponsePoolsResponseType, error) { + response := new(GetDSFResponsePoolsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetDSFResponsePools(request *GetDSFResponsePoolsRequestType) (*GetDSFResponsePoolsResponseType, error) { + return service.GetDSFResponsePoolsContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneDSFResponsePoolContext(ctx context.Context, request *GetOneDSFResponsePoolRequestType) (*GetOneDSFResponsePoolResponseType, error) { + response := new(GetOneDSFResponsePoolResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneDSFResponsePool(request *GetOneDSFResponsePoolRequestType) (*GetOneDSFResponsePoolResponseType, error) { + return service.GetOneDSFResponsePoolContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneDSFResponsePoolContext(ctx context.Context, request *DeleteOneDSFResponsePoolRequestType) (*DeleteOneDSFResponsePoolResponseType, error) { + response := new(DeleteOneDSFResponsePoolResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneDSFResponsePool(request *DeleteOneDSFResponsePoolRequestType) (*DeleteOneDSFResponsePoolResponseType, error) { + return service.DeleteOneDSFResponsePoolContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateDSFRecordSetFailoverChainContext(ctx context.Context, request *CreateDSFRecordSetFailoverChainRequestType) (*CreateDSFRecordSetFailoverChainResponseType, error) { + response := new(CreateDSFRecordSetFailoverChainResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateDSFRecordSetFailoverChain(request *CreateDSFRecordSetFailoverChainRequestType) (*CreateDSFRecordSetFailoverChainResponseType, error) { + return service.CreateDSFRecordSetFailoverChainContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateDSFRecordSetFailoverChainContext(ctx context.Context, request *UpdateDSFRecordSetFailoverChainRequestType) (*UpdateDSFRecordSetFailoverChainResponseType, error) { + response := new(UpdateDSFRecordSetFailoverChainResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateDSFRecordSetFailoverChain(request *UpdateDSFRecordSetFailoverChainRequestType) (*UpdateDSFRecordSetFailoverChainResponseType, error) { + return service.UpdateDSFRecordSetFailoverChainContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetDSFRecordSetFailoverChainsContext(ctx context.Context, request *GetDSFRecordSetFailoverChainsRequestType) (*GetDSFRecordSetFailoverChainsResponseType, error) { + response := new(GetDSFRecordSetFailoverChainsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetDSFRecordSetFailoverChains(request *GetDSFRecordSetFailoverChainsRequestType) (*GetDSFRecordSetFailoverChainsResponseType, error) { + return service.GetDSFRecordSetFailoverChainsContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneDSFRecordSetFailoverChainContext(ctx context.Context, request *GetOneDSFRecordSetFailoverChainRequestType) (*GetOneDSFRecordSetFailoverChainResponseType, error) { + response := new(GetOneDSFRecordSetFailoverChainResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneDSFRecordSetFailoverChain(request *GetOneDSFRecordSetFailoverChainRequestType) (*GetOneDSFRecordSetFailoverChainResponseType, error) { + return service.GetOneDSFRecordSetFailoverChainContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneDSFRecordSetFailoverChainContext(ctx context.Context, request *DeleteOneDSFRecordSetFailoverChainRequestType) (*DeleteOneDSFRecordSetFailoverChainResponseType, error) { + response := new(DeleteOneDSFRecordSetFailoverChainResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneDSFRecordSetFailoverChain(request *DeleteOneDSFRecordSetFailoverChainRequestType) (*DeleteOneDSFRecordSetFailoverChainResponseType, error) { + return service.DeleteOneDSFRecordSetFailoverChainContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateDSFRecordSetContext(ctx context.Context, request *CreateDSFRecordSetRequestType) (*CreateDSFRecordSetResponseType, error) { + response := new(CreateDSFRecordSetResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateDSFRecordSet(request *CreateDSFRecordSetRequestType) (*CreateDSFRecordSetResponseType, error) { + return service.CreateDSFRecordSetContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateDSFRecordSetContext(ctx context.Context, request *UpdateDSFRecordSetRequestType) (*UpdateDSFRecordSetResponseType, error) { + response := new(UpdateDSFRecordSetResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateDSFRecordSet(request *UpdateDSFRecordSetRequestType) (*UpdateDSFRecordSetResponseType, error) { + return service.UpdateDSFRecordSetContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneDSFRecordSetContext(ctx context.Context, request *GetOneDSFRecordSetRequestType) (*GetOneDSFRecordSetResponseType, error) { + response := new(GetOneDSFRecordSetResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneDSFRecordSet(request *GetOneDSFRecordSetRequestType) (*GetOneDSFRecordSetResponseType, error) { + return service.GetOneDSFRecordSetContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetDSFRecordSetsContext(ctx context.Context, request *GetDSFRecordSetsRequestType) (*GetDSFRecordSetsResponseType, error) { + response := new(GetDSFRecordSetsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetDSFRecordSets(request *GetDSFRecordSetsRequestType) (*GetDSFRecordSetsResponseType, error) { + return service.GetDSFRecordSetsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneDSFRecordSetContext(ctx context.Context, request *DeleteOneDSFRecordSetRequestType) (*DeleteOneDSFRecordSetResponseType, error) { + response := new(DeleteOneDSFRecordSetResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneDSFRecordSet(request *DeleteOneDSFRecordSetRequestType) (*DeleteOneDSFRecordSetResponseType, error) { + return service.DeleteOneDSFRecordSetContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateDSFRecordContext(ctx context.Context, request *CreateDSFRecordRequestType) (*CreateDSFRecordResponseType, error) { + response := new(CreateDSFRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateDSFRecord(request *CreateDSFRecordRequestType) (*CreateDSFRecordResponseType, error) { + return service.CreateDSFRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateDSFRecordContext(ctx context.Context, request *UpdateDSFRecordRequestType) (*UpdateDSFRecordResponseType, error) { + response := new(UpdateDSFRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateDSFRecord(request *UpdateDSFRecordRequestType) (*UpdateDSFRecordResponseType, error) { + return service.UpdateDSFRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneDSFRecordContext(ctx context.Context, request *GetOneDSFRecordRequestType) (*GetOneDSFRecordResponseType, error) { + response := new(GetOneDSFRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneDSFRecord(request *GetOneDSFRecordRequestType) (*GetOneDSFRecordResponseType, error) { + return service.GetOneDSFRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetDSFRecordsContext(ctx context.Context, request *GetDSFRecordsRequestType) (*GetDSFRecordsResponseType, error) { + response := new(GetDSFRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetDSFRecords(request *GetDSFRecordsRequestType) (*GetDSFRecordsResponseType, error) { + return service.GetDSFRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneDSFRecordContext(ctx context.Context, request *DeleteOneDSFRecordRequestType) (*DeleteOneDSFRecordResponseType, error) { + response := new(DeleteOneDSFRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneDSFRecord(request *DeleteOneDSFRecordRequestType) (*DeleteOneDSFRecordResponseType, error) { + return service.DeleteOneDSFRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) AddDSFNodeContext(ctx context.Context, request *AddDSFNodeRequestType) (*AddDSFNodeResponseType, error) { + response := new(AddDSFNodeResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) AddDSFNode(request *AddDSFNodeRequestType) (*AddDSFNodeResponseType, error) { + return service.AddDSFNodeContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateDSFNodesContext(ctx context.Context, request *UpdateDSFNodesRequestType) (*UpdateDSFNodesResponseType, error) { + response := new(UpdateDSFNodesResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateDSFNodes(request *UpdateDSFNodesRequestType) (*UpdateDSFNodesResponseType, error) { + return service.UpdateDSFNodesContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetDSFNodesContext(ctx context.Context, request *GetDSFNodesRequestType) (*GetDSFNodesResponseType, error) { + response := new(GetDSFNodesResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetDSFNodes(request *GetDSFNodesRequestType) (*GetDSFNodesResponseType, error) { + return service.GetDSFNodesContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneDSFNodeContext(ctx context.Context, request *DeleteOneDSFNodeRequestType) (*DeleteOneDSFNodeResponseType, error) { + response := new(DeleteOneDSFNodeResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneDSFNode(request *DeleteOneDSFNodeRequestType) (*DeleteOneDSFNodeResponseType, error) { + return service.DeleteOneDSFNodeContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateDSFMonitorContext(ctx context.Context, request *CreateDSFMonitorRequestType) (*CreateDSFMonitorResponseType, error) { + response := new(CreateDSFMonitorResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateDSFMonitor(request *CreateDSFMonitorRequestType) (*CreateDSFMonitorResponseType, error) { + return service.CreateDSFMonitorContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateDSFMonitorContext(ctx context.Context, request *UpdateDSFMonitorRequestType) (*UpdateDSFMonitorResponseType, error) { + response := new(UpdateDSFMonitorResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateDSFMonitor(request *UpdateDSFMonitorRequestType) (*UpdateDSFMonitorResponseType, error) { + return service.UpdateDSFMonitorContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneDSFMonitorContext(ctx context.Context, request *GetOneDSFMonitorRequestType) (*GetOneDSFMonitorResponseType, error) { + response := new(GetOneDSFMonitorResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneDSFMonitor(request *GetOneDSFMonitorRequestType) (*GetOneDSFMonitorResponseType, error) { + return service.GetOneDSFMonitorContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetDSFMonitorsContext(ctx context.Context, request *GetDSFMonitorsRequestType) (*GetDSFMonitorsResponseType, error) { + response := new(GetDSFMonitorsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetDSFMonitors(request *GetDSFMonitorsRequestType) (*GetDSFMonitorsResponseType, error) { + return service.GetDSFMonitorsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneDSFMonitorContext(ctx context.Context, request *DeleteOneDSFMonitorRequestType) (*DeleteOneDSFMonitorResponseType, error) { + response := new(DeleteOneDSFMonitorResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneDSFMonitor(request *DeleteOneDSFMonitorRequestType) (*DeleteOneDSFMonitorResponseType, error) { + return service.DeleteOneDSFMonitorContext( + context.Background(), + request, + ) +} + +func (service *dynect) AddDSFMonitorNotifierContext(ctx context.Context, request *AddDSFMonitorNotifierRequestType) (*AddDSFMonitorNotifierResponseType, error) { + response := new(AddDSFMonitorNotifierResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) AddDSFMonitorNotifier(request *AddDSFMonitorNotifierRequestType) (*AddDSFMonitorNotifierResponseType, error) { + return service.AddDSFMonitorNotifierContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetDSFMonitorSitesContext(ctx context.Context, request *GetDSFMonitorSitesRequestType) (*GetDSFMonitorSitesResponseType, error) { + response := new(GetDSFMonitorSitesResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetDSFMonitorSites(request *GetDSFMonitorSitesRequestType) (*GetDSFMonitorSitesResponseType, error) { + return service.GetDSFMonitorSitesContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateNotifierContext(ctx context.Context, request *CreateNotifierRequestType) (*CreateNotifierResponseType, error) { + response := new(CreateNotifierResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateNotifier(request *CreateNotifierRequestType) (*CreateNotifierResponseType, error) { + return service.CreateNotifierContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateNotifierContext(ctx context.Context, request *UpdateNotifierRequestType) (*UpdateNotifierResponseType, error) { + response := new(UpdateNotifierResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateNotifier(request *UpdateNotifierRequestType) (*UpdateNotifierResponseType, error) { + return service.UpdateNotifierContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneNotifierContext(ctx context.Context, request *GetOneNotifierRequestType) (*GetOneNotifierResponseType, error) { + response := new(GetOneNotifierResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneNotifier(request *GetOneNotifierRequestType) (*GetOneNotifierResponseType, error) { + return service.GetOneNotifierContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetNotifiersContext(ctx context.Context, request *GetNotifiersRequestType) (*GetNotifiersResponseType, error) { + response := new(GetNotifiersResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetNotifiers(request *GetNotifiersRequestType) (*GetNotifiersResponseType, error) { + return service.GetNotifiersContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneNotifierContext(ctx context.Context, request *DeleteOneNotifierRequestType) (*DeleteOneNotifierResponseType, error) { + response := new(DeleteOneNotifierResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneNotifier(request *DeleteOneNotifierRequestType) (*DeleteOneNotifierResponseType, error) { + return service.DeleteOneNotifierContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateConfigLimitContext(ctx context.Context, request *CreateConfigLimitRequestType) (*CreateConfigLimitResponseType, error) { + response := new(CreateConfigLimitResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateConfigLimit(request *CreateConfigLimitRequestType) (*CreateConfigLimitResponseType, error) { + return service.CreateConfigLimitContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneConfigLimitContext(ctx context.Context, request *GetOneConfigLimitRequestType) (*GetOneConfigLimitResponseType, error) { + response := new(GetOneConfigLimitResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneConfigLimit(request *GetOneConfigLimitRequestType) (*GetOneConfigLimitResponseType, error) { + return service.GetOneConfigLimitContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetConfigLimitsContext(ctx context.Context, request *GetConfigLimitsRequestType) (*GetConfigLimitsResponseType, error) { + response := new(GetConfigLimitsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetConfigLimits(request *GetConfigLimitsRequestType) (*GetConfigLimitsResponseType, error) { + return service.GetConfigLimitsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateConfigLimitContext(ctx context.Context, request *UpdateConfigLimitRequestType) (*UpdateConfigLimitResponseType, error) { + response := new(UpdateConfigLimitResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateConfigLimit(request *UpdateConfigLimitRequestType) (*UpdateConfigLimitResponseType, error) { + return service.UpdateConfigLimitContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneConfigLimitContext(ctx context.Context, request *DeleteOneConfigLimitRequestType) (*DeleteOneConfigLimitResponseType, error) { + response := new(DeleteOneConfigLimitResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneConfigLimit(request *DeleteOneConfigLimitRequestType) (*DeleteOneConfigLimitResponseType, error) { + return service.DeleteOneConfigLimitContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreatePermissionGroupContext(ctx context.Context, request *CreatePermissionGroupRequestType) (*CreatePermissionGroupResponseType, error) { + response := new(CreatePermissionGroupResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreatePermissionGroup(request *CreatePermissionGroupRequestType) (*CreatePermissionGroupResponseType, error) { + return service.CreatePermissionGroupContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOnePermissionGroupContext(ctx context.Context, request *GetOnePermissionGroupRequestType) (*GetOnePermissionGroupResponseType, error) { + response := new(GetOnePermissionGroupResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOnePermissionGroup(request *GetOnePermissionGroupRequestType) (*GetOnePermissionGroupResponseType, error) { + return service.GetOnePermissionGroupContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetPermissionGroupsContext(ctx context.Context, request *GetPermissionGroupsRequestType) (*GetPermissionGroupsResponseType, error) { + response := new(GetPermissionGroupsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetPermissionGroups(request *GetPermissionGroupsRequestType) (*GetPermissionGroupsResponseType, error) { + return service.GetPermissionGroupsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOnePermissionGroupContext(ctx context.Context, request *DeleteOnePermissionGroupRequestType) (*DeleteOnePermissionGroupResponseType, error) { + response := new(DeleteOnePermissionGroupResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOnePermissionGroup(request *DeleteOnePermissionGroupRequestType) (*DeleteOnePermissionGroupResponseType, error) { + return service.DeleteOnePermissionGroupContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdatePermissionGroupContext(ctx context.Context, request *UpdatePermissionGroupRequestType) (*UpdatePermissionGroupResponseType, error) { + response := new(UpdatePermissionGroupResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdatePermissionGroup(request *UpdatePermissionGroupRequestType) (*UpdatePermissionGroupResponseType, error) { + return service.UpdatePermissionGroupContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetCustomerPermissionsContext(ctx context.Context, request *GetCustomerPermissionsRequestType) (*GetCustomerPermissionsResponseType, error) { + response := new(GetCustomerPermissionsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetCustomerPermissions(request *GetCustomerPermissionsRequestType) (*GetCustomerPermissionsResponseType, error) { + return service.GetCustomerPermissionsContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetUserPermissionsContext(ctx context.Context, request *GetUserPermissionsRequestType) (*GetUserPermissionsResponseType, error) { + response := new(GetUserPermissionsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetUserPermissions(request *GetUserPermissionsRequestType) (*GetUserPermissionsResponseType, error) { + return service.GetUserPermissionsContext( + context.Background(), + request, + ) +} + +func (service *dynect) CheckPermissionsContext(ctx context.Context, request *CheckPermissionsRequestType) (*CheckPermissionsResponseType, error) { + response := new(CheckPermissionsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CheckPermissions(request *CheckPermissionsRequestType) (*CheckPermissionsResponseType, error) { + return service.CheckPermissionsContext( + context.Background(), + request, + ) +} + +func (service *dynect) AddPermissionGroupUsersContext(ctx context.Context, request *AddPermissionGroupUsersRequestType) (*AddPermissionGroupUsersResponseType, error) { + response := new(AddPermissionGroupUsersResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) AddPermissionGroupUsers(request *AddPermissionGroupUsersRequestType) (*AddPermissionGroupUsersResponseType, error) { + return service.AddPermissionGroupUsersContext( + context.Background(), + request, + ) +} + +func (service *dynect) SetPermissionGroupUsersContext(ctx context.Context, request *SetPermissionGroupUsersRequestType) (*SetPermissionGroupUsersResponseType, error) { + response := new(SetPermissionGroupUsersResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) SetPermissionGroupUsers(request *SetPermissionGroupUsersRequestType) (*SetPermissionGroupUsersResponseType, error) { + return service.SetPermissionGroupUsersContext( + context.Background(), + request, + ) +} + +func (service *dynect) RemovePermissionGroupUsersContext(ctx context.Context, request *RemovePermissionGroupUsersRequestType) (*RemovePermissionGroupUsersResponseType, error) { + response := new(RemovePermissionGroupUsersResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) RemovePermissionGroupUsers(request *RemovePermissionGroupUsersRequestType) (*RemovePermissionGroupUsersResponseType, error) { + return service.RemovePermissionGroupUsersContext( + context.Background(), + request, + ) +} + +func (service *dynect) AddPermissionGroupSubgroupsContext(ctx context.Context, request *AddPermissionGroupSubgroupsRequestType) (*AddPermissionGroupSubgroupsResponseType, error) { + response := new(AddPermissionGroupSubgroupsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) AddPermissionGroupSubgroups(request *AddPermissionGroupSubgroupsRequestType) (*AddPermissionGroupSubgroupsResponseType, error) { + return service.AddPermissionGroupSubgroupsContext( + context.Background(), + request, + ) +} + +func (service *dynect) SetPermissionGroupSubgroupsContext(ctx context.Context, request *SetPermissionGroupSubgroupsRequestType) (*SetPermissionGroupSubgroupsResponseType, error) { + response := new(SetPermissionGroupSubgroupsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) SetPermissionGroupSubgroups(request *SetPermissionGroupSubgroupsRequestType) (*SetPermissionGroupSubgroupsResponseType, error) { + return service.SetPermissionGroupSubgroupsContext( + context.Background(), + request, + ) +} + +func (service *dynect) RemovePermissionGroupSubgroupsContext(ctx context.Context, request *RemovePermissionGroupSubgroupsRequestType) (*RemovePermissionGroupSubgroupsResponseType, error) { + response := new(RemovePermissionGroupSubgroupsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) RemovePermissionGroupSubgroups(request *RemovePermissionGroupSubgroupsRequestType) (*RemovePermissionGroupSubgroupsResponseType, error) { + return service.RemovePermissionGroupSubgroupsContext( + context.Background(), + request, + ) +} + +func (service *dynect) AddPermissionGroupPermissionsContext(ctx context.Context, request *AddPermissionGroupPermissionsRequestType) (*AddPermissionGroupPermissionsResponseType, error) { + response := new(AddPermissionGroupPermissionsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) AddPermissionGroupPermissions(request *AddPermissionGroupPermissionsRequestType) (*AddPermissionGroupPermissionsResponseType, error) { + return service.AddPermissionGroupPermissionsContext( + context.Background(), + request, + ) +} + +func (service *dynect) SetPermissionGroupPermissionsContext(ctx context.Context, request *SetPermissionGroupPermissionsRequestType) (*SetPermissionGroupPermissionsResponseType, error) { + response := new(SetPermissionGroupPermissionsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) SetPermissionGroupPermissions(request *SetPermissionGroupPermissionsRequestType) (*SetPermissionGroupPermissionsResponseType, error) { + return service.SetPermissionGroupPermissionsContext( + context.Background(), + request, + ) +} + +func (service *dynect) RemovePermissionGroupPermissionsContext(ctx context.Context, request *RemovePermissionGroupPermissionsRequestType) (*RemovePermissionGroupPermissionsResponseType, error) { + response := new(RemovePermissionGroupPermissionsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) RemovePermissionGroupPermissions(request *RemovePermissionGroupPermissionsRequestType) (*RemovePermissionGroupPermissionsResponseType, error) { + return service.RemovePermissionGroupPermissionsContext( + context.Background(), + request, + ) +} + +func (service *dynect) AddPermissionGroupZonesContext(ctx context.Context, request *AddPermissionGroupZonesRequestType) (*AddPermissionGroupZonesResponseType, error) { + response := new(AddPermissionGroupZonesResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) AddPermissionGroupZones(request *AddPermissionGroupZonesRequestType) (*AddPermissionGroupZonesResponseType, error) { + return service.AddPermissionGroupZonesContext( + context.Background(), + request, + ) +} + +func (service *dynect) SetPermissionGroupZonesContext(ctx context.Context, request *SetPermissionGroupZonesRequestType) (*SetPermissionGroupZonesResponseType, error) { + response := new(SetPermissionGroupZonesResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) SetPermissionGroupZones(request *SetPermissionGroupZonesRequestType) (*SetPermissionGroupZonesResponseType, error) { + return service.SetPermissionGroupZonesContext( + context.Background(), + request, + ) +} + +func (service *dynect) RemovePermissionGroupZonesContext(ctx context.Context, request *RemovePermissionGroupZonesRequestType) (*RemovePermissionGroupZonesResponseType, error) { + response := new(RemovePermissionGroupZonesResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) RemovePermissionGroupZones(request *RemovePermissionGroupZonesRequestType) (*RemovePermissionGroupZonesResponseType, error) { + return service.RemovePermissionGroupZonesContext( + context.Background(), + request, + ) +} + +func (service *dynect) AddUserGroupsContext(ctx context.Context, request *AddUserGroupsRequestType) (*AddUserGroupsResponseType, error) { + response := new(AddUserGroupsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) AddUserGroups(request *AddUserGroupsRequestType) (*AddUserGroupsResponseType, error) { + return service.AddUserGroupsContext( + context.Background(), + request, + ) +} + +func (service *dynect) SetUserGroupsContext(ctx context.Context, request *SetUserGroupsRequestType) (*SetUserGroupsResponseType, error) { + response := new(SetUserGroupsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) SetUserGroups(request *SetUserGroupsRequestType) (*SetUserGroupsResponseType, error) { + return service.SetUserGroupsContext( + context.Background(), + request, + ) +} + +func (service *dynect) RemoveUserGroupsContext(ctx context.Context, request *RemoveUserGroupsRequestType) (*RemoveUserGroupsResponseType, error) { + response := new(RemoveUserGroupsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) RemoveUserGroups(request *RemoveUserGroupsRequestType) (*RemoveUserGroupsResponseType, error) { + return service.RemoveUserGroupsContext( + context.Background(), + request, + ) +} + +func (service *dynect) AddUserZonesContext(ctx context.Context, request *AddUserZonesRequestType) (*AddUserZonesResponseType, error) { + response := new(AddUserZonesResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) AddUserZones(request *AddUserZonesRequestType) (*AddUserZonesResponseType, error) { + return service.AddUserZonesContext( + context.Background(), + request, + ) +} + +func (service *dynect) SetUserZonesContext(ctx context.Context, request *SetUserZonesRequestType) (*SetUserZonesResponseType, error) { + response := new(SetUserZonesResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) SetUserZones(request *SetUserZonesRequestType) (*SetUserZonesResponseType, error) { + return service.SetUserZonesContext( + context.Background(), + request, + ) +} + +func (service *dynect) RemoveUserZonesContext(ctx context.Context, request *RemoveUserZonesRequestType) (*RemoveUserZonesResponseType, error) { + response := new(RemoveUserZonesResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) RemoveUserZones(request *RemoveUserZonesRequestType) (*RemoveUserZonesResponseType, error) { + return service.RemoveUserZonesContext( + context.Background(), + request, + ) +} + +func (service *dynect) AddUserPermissionsContext(ctx context.Context, request *AddUserPermissionsRequestType) (*AddUserPermissionsResponseType, error) { + response := new(AddUserPermissionsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) AddUserPermissions(request *AddUserPermissionsRequestType) (*AddUserPermissionsResponseType, error) { + return service.AddUserPermissionsContext( + context.Background(), + request, + ) +} + +func (service *dynect) SetUserPermissionsContext(ctx context.Context, request *SetUserPermissionsRequestType) (*SetUserPermissionsResponseType, error) { + response := new(SetUserPermissionsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) SetUserPermissions(request *SetUserPermissionsRequestType) (*SetUserPermissionsResponseType, error) { + return service.SetUserPermissionsContext( + context.Background(), + request, + ) +} + +func (service *dynect) RemoveUserPermissionsContext(ctx context.Context, request *RemoveUserPermissionsRequestType) (*RemoveUserPermissionsResponseType, error) { + response := new(RemoveUserPermissionsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) RemoveUserPermissions(request *RemoveUserPermissionsRequestType) (*RemoveUserPermissionsResponseType, error) { + return service.RemoveUserPermissionsContext( + context.Background(), + request, + ) +} + +func (service *dynect) AddUserForbidsContext(ctx context.Context, request *AddUserForbidsRequestType) (*AddUserForbidsResponseType, error) { + response := new(AddUserForbidsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) AddUserForbids(request *AddUserForbidsRequestType) (*AddUserForbidsResponseType, error) { + return service.AddUserForbidsContext( + context.Background(), + request, + ) +} + +func (service *dynect) SetUserForbidsContext(ctx context.Context, request *SetUserForbidsRequestType) (*SetUserForbidsResponseType, error) { + response := new(SetUserForbidsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) SetUserForbids(request *SetUserForbidsRequestType) (*SetUserForbidsResponseType, error) { + return service.SetUserForbidsContext( + context.Background(), + request, + ) +} + +func (service *dynect) RemoveUserForbidsContext(ctx context.Context, request *RemoveUserForbidsRequestType) (*RemoveUserForbidsResponseType, error) { + response := new(RemoveUserForbidsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) RemoveUserForbids(request *RemoveUserForbidsRequestType) (*RemoveUserForbidsResponseType, error) { + return service.RemoveUserForbidsContext( + context.Background(), + request, + ) +} + +func (service *dynect) AddCustomerPermissionsContext(ctx context.Context, request *AddCustomerPermissionsRequestType) (*AddCustomerPermissionsResponseType, error) { + response := new(AddCustomerPermissionsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) AddCustomerPermissions(request *AddCustomerPermissionsRequestType) (*AddCustomerPermissionsResponseType, error) { + return service.AddCustomerPermissionsContext( + context.Background(), + request, + ) +} + +func (service *dynect) SetCustomerPermissionsContext(ctx context.Context, request *SetCustomerPermissionsRequestType) (*SetCustomerPermissionsResponseType, error) { + response := new(SetCustomerPermissionsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) SetCustomerPermissions(request *SetCustomerPermissionsRequestType) (*SetCustomerPermissionsResponseType, error) { + return service.SetCustomerPermissionsContext( + context.Background(), + request, + ) +} + +func (service *dynect) RemoveCustomerPermissionsContext(ctx context.Context, request *RemoveCustomerPermissionsRequestType) (*RemoveCustomerPermissionsResponseType, error) { + response := new(RemoveCustomerPermissionsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) RemoveCustomerPermissions(request *RemoveCustomerPermissionsRequestType) (*RemoveCustomerPermissionsResponseType, error) { + return service.RemoveCustomerPermissionsContext( + context.Background(), + request, + ) +} + +func (service *dynect) AddCustomerForbidsContext(ctx context.Context, request *AddCustomerForbidsRequestType) (*AddCustomerForbidsResponseType, error) { + response := new(AddCustomerForbidsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) AddCustomerForbids(request *AddCustomerForbidsRequestType) (*AddCustomerForbidsResponseType, error) { + return service.AddCustomerForbidsContext( + context.Background(), + request, + ) +} + +func (service *dynect) SetCustomerForbidsContext(ctx context.Context, request *SetCustomerForbidsRequestType) (*SetCustomerForbidsResponseType, error) { + response := new(SetCustomerForbidsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) SetCustomerForbids(request *SetCustomerForbidsRequestType) (*SetCustomerForbidsResponseType, error) { + return service.SetCustomerForbidsContext( + context.Background(), + request, + ) +} + +func (service *dynect) RemoveCustomerForbidsContext(ctx context.Context, request *RemoveCustomerForbidsRequestType) (*RemoveCustomerForbidsResponseType, error) { + response := new(RemoveCustomerForbidsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) RemoveCustomerForbids(request *RemoveCustomerForbidsRequestType) (*RemoveCustomerForbidsResponseType, error) { + return service.RemoveCustomerForbidsContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetHostStatsFlagsContext(ctx context.Context, request *GetHostStatsFlagsRequestType) (*GetHostStatsFlagsResponseType, error) { + response := new(GetHostStatsFlagsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetHostStatsFlags(request *GetHostStatsFlagsRequestType) (*GetHostStatsFlagsResponseType, error) { + return service.GetHostStatsFlagsContext( + context.Background(), + request, + ) +} + +func (service *dynect) SetHostStatsFlagsContext(ctx context.Context, request *SetHostStatsFlagsRequestType) (*SetHostStatsFlagsResponseType, error) { + response := new(SetHostStatsFlagsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) SetHostStatsFlags(request *SetHostStatsFlagsRequestType) (*SetHostStatsFlagsResponseType, error) { + return service.SetHostStatsFlagsContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateTSIGKeyContext(ctx context.Context, request *CreateTSIGKeyRequestType) (*CreateTSIGKeyResponseType, error) { + response := new(CreateTSIGKeyResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateTSIGKey(request *CreateTSIGKeyRequestType) (*CreateTSIGKeyResponseType, error) { + return service.CreateTSIGKeyContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneTSIGKeyContext(ctx context.Context, request *GetOneTSIGKeyRequestType) (*GetOneTSIGKeyResponseType, error) { + response := new(GetOneTSIGKeyResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneTSIGKey(request *GetOneTSIGKeyRequestType) (*GetOneTSIGKeyResponseType, error) { + return service.GetOneTSIGKeyContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetTSIGKeysContext(ctx context.Context, request *GetTSIGKeysRequestType) (*GetTSIGKeysResponseType, error) { + response := new(GetTSIGKeysResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetTSIGKeys(request *GetTSIGKeysRequestType) (*GetTSIGKeysResponseType, error) { + return service.GetTSIGKeysContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateTSIGKeyContext(ctx context.Context, request *UpdateTSIGKeyRequestType) (*UpdateTSIGKeyResponseType, error) { + response := new(UpdateTSIGKeyResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateTSIGKey(request *UpdateTSIGKeyRequestType) (*UpdateTSIGKeyResponseType, error) { + return service.UpdateTSIGKeyContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneTSIGKeyContext(ctx context.Context, request *DeleteOneTSIGKeyRequestType) (*DeleteOneTSIGKeyResponseType, error) { + response := new(DeleteOneTSIGKeyResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneTSIGKey(request *DeleteOneTSIGKeyRequestType) (*DeleteOneTSIGKeyResponseType, error) { + return service.DeleteOneTSIGKeyContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateZoneContext(ctx context.Context, request *CreateZoneRequestType) (*CreateZoneResponseType, error) { + response := new(CreateZoneResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateZone(request *CreateZoneRequestType) (*CreateZoneResponseType, error) { + return service.CreateZoneContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneZoneContext(ctx context.Context, request *GetOneZoneRequestType) (*GetOneZoneResponseType, error) { + response := new(GetOneZoneResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneZone(request *GetOneZoneRequestType) (*GetOneZoneResponseType, error) { + return service.GetOneZoneContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetZonesContext(ctx context.Context, request *GetZonesRequestType) (*GetZonesResponseType, error) { + response := new(GetZonesResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetZones(request *GetZonesRequestType) (*GetZonesResponseType, error) { + return service.GetZonesContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneZoneContext(ctx context.Context, request *DeleteOneZoneRequestType) (*DeleteOneZoneResponseType, error) { + response := new(DeleteOneZoneResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneZone(request *DeleteOneZoneRequestType) (*DeleteOneZoneResponseType, error) { + return service.DeleteOneZoneContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateSecondaryZoneContext(ctx context.Context, request *CreateSecondaryZoneRequestType) (*CreateSecondaryZoneResponseType, error) { + response := new(CreateSecondaryZoneResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateSecondaryZone(request *CreateSecondaryZoneRequestType) (*CreateSecondaryZoneResponseType, error) { + return service.CreateSecondaryZoneContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateSecondaryContext(ctx context.Context, request *UpdateSecondaryRequestType) (*UpdateSecondaryResponseType, error) { + response := new(UpdateSecondaryResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateSecondary(request *UpdateSecondaryRequestType) (*UpdateSecondaryResponseType, error) { + return service.UpdateSecondaryContext( + context.Background(), + request, + ) +} + +func (service *dynect) ActivateSecondaryContext(ctx context.Context, request *ActivateSecondaryRequestType) (*ActivateSecondaryResponseType, error) { + response := new(ActivateSecondaryResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ActivateSecondary(request *ActivateSecondaryRequestType) (*ActivateSecondaryResponseType, error) { + return service.ActivateSecondaryContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeactivateSecondaryContext(ctx context.Context, request *DeactivateSecondaryRequestType) (*DeactivateSecondaryResponseType, error) { + response := new(DeactivateSecondaryResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeactivateSecondary(request *DeactivateSecondaryRequestType) (*DeactivateSecondaryResponseType, error) { + return service.DeactivateSecondaryContext( + context.Background(), + request, + ) +} + +func (service *dynect) RetransferSecondaryContext(ctx context.Context, request *RetransferSecondaryRequestType) (*RetransferSecondaryResponseType, error) { + response := new(RetransferSecondaryResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) RetransferSecondary(request *RetransferSecondaryRequestType) (*RetransferSecondaryResponseType, error) { + return service.RetransferSecondaryContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneSecondaryContext(ctx context.Context, request *GetOneSecondaryRequestType) (*GetOneSecondaryResponseType, error) { + response := new(GetOneSecondaryResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneSecondary(request *GetOneSecondaryRequestType) (*GetOneSecondaryResponseType, error) { + return service.GetOneSecondaryContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetSecondariesContext(ctx context.Context, request *GetSecondariesRequestType) (*GetSecondariesResponseType, error) { + response := new(GetSecondariesResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetSecondaries(request *GetSecondariesRequestType) (*GetSecondariesResponseType, error) { + return service.GetSecondariesContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetZoneApexContext(ctx context.Context, request *GetZoneApexRequestType) (*GetZoneApexResponseType, error) { + response := new(GetZoneApexResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetZoneApex(request *GetZoneApexRequestType) (*GetZoneApexResponseType, error) { + return service.GetZoneApexContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateARecordContext(ctx context.Context, request *CreateARecordRequestType) (*CreateARecordResponseType, error) { + response := new(CreateARecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateARecord(request *CreateARecordRequestType) (*CreateARecordResponseType, error) { + return service.CreateARecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneARecordContext(ctx context.Context, request *GetOneARecordRequestType) (*GetOneARecordResponseType, error) { + response := new(GetOneARecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneARecord(request *GetOneARecordRequestType) (*GetOneARecordResponseType, error) { + return service.GetOneARecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetARecordsContext(ctx context.Context, request *GetARecordsRequestType) (*GetARecordsResponseType, error) { + response := new(GetARecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetARecords(request *GetARecordsRequestType) (*GetARecordsResponseType, error) { + return service.GetARecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateARecordContext(ctx context.Context, request *UpdateARecordRequestType) (*UpdateARecordResponseType, error) { + response := new(UpdateARecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateARecord(request *UpdateARecordRequestType) (*UpdateARecordResponseType, error) { + return service.UpdateARecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteARecordsContext(ctx context.Context, request *DeleteARecordsRequestType) (*DeleteARecordsResponseType, error) { + response := new(DeleteARecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteARecords(request *DeleteARecordsRequestType) (*DeleteARecordsResponseType, error) { + return service.DeleteARecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneARecordContext(ctx context.Context, request *DeleteOneARecordRequestType) (*DeleteOneARecordResponseType, error) { + response := new(DeleteOneARecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneARecord(request *DeleteOneARecordRequestType) (*DeleteOneARecordResponseType, error) { + return service.DeleteOneARecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateAAAARecordContext(ctx context.Context, request *CreateAAAARecordRequestType) (*CreateAAAARecordResponseType, error) { + response := new(CreateAAAARecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateAAAARecord(request *CreateAAAARecordRequestType) (*CreateAAAARecordResponseType, error) { + return service.CreateAAAARecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneAAAARecordContext(ctx context.Context, request *GetOneAAAARecordRequestType) (*GetOneAAAARecordResponseType, error) { + response := new(GetOneAAAARecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneAAAARecord(request *GetOneAAAARecordRequestType) (*GetOneAAAARecordResponseType, error) { + return service.GetOneAAAARecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetAAAARecordsContext(ctx context.Context, request *GetAAAARecordsRequestType) (*GetAAAARecordsResponseType, error) { + response := new(GetAAAARecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetAAAARecords(request *GetAAAARecordsRequestType) (*GetAAAARecordsResponseType, error) { + return service.GetAAAARecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateAAAARecordContext(ctx context.Context, request *UpdateAAAARecordRequestType) (*UpdateAAAARecordResponseType, error) { + response := new(UpdateAAAARecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateAAAARecord(request *UpdateAAAARecordRequestType) (*UpdateAAAARecordResponseType, error) { + return service.UpdateAAAARecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteAAAARecordsContext(ctx context.Context, request *DeleteAAAARecordsRequestType) (*DeleteAAAARecordsResponseType, error) { + response := new(DeleteAAAARecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteAAAARecords(request *DeleteAAAARecordsRequestType) (*DeleteAAAARecordsResponseType, error) { + return service.DeleteAAAARecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneAAAARecordContext(ctx context.Context, request *DeleteOneAAAARecordRequestType) (*DeleteOneAAAARecordResponseType, error) { + response := new(DeleteOneAAAARecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneAAAARecord(request *DeleteOneAAAARecordRequestType) (*DeleteOneAAAARecordResponseType, error) { + return service.DeleteOneAAAARecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateALIASRecordContext(ctx context.Context, request *CreateALIASRecordRequestType) (*CreateALIASRecordResponseType, error) { + response := new(CreateALIASRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateALIASRecord(request *CreateALIASRecordRequestType) (*CreateALIASRecordResponseType, error) { + return service.CreateALIASRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneALIASRecordContext(ctx context.Context, request *GetOneALIASRecordRequestType) (*GetOneALIASRecordResponseType, error) { + response := new(GetOneALIASRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneALIASRecord(request *GetOneALIASRecordRequestType) (*GetOneALIASRecordResponseType, error) { + return service.GetOneALIASRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetALIASRecordsContext(ctx context.Context, request *GetALIASRecordsRequestType) (*GetALIASRecordsResponseType, error) { + response := new(GetALIASRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetALIASRecords(request *GetALIASRecordsRequestType) (*GetALIASRecordsResponseType, error) { + return service.GetALIASRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateALIASRecordContext(ctx context.Context, request *UpdateALIASRecordRequestType) (*UpdateALIASRecordResponseType, error) { + response := new(UpdateALIASRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateALIASRecord(request *UpdateALIASRecordRequestType) (*UpdateALIASRecordResponseType, error) { + return service.UpdateALIASRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteALIASRecordsContext(ctx context.Context, request *DeleteALIASRecordsRequestType) (*DeleteALIASRecordsResponseType, error) { + response := new(DeleteALIASRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteALIASRecords(request *DeleteALIASRecordsRequestType) (*DeleteALIASRecordsResponseType, error) { + return service.DeleteALIASRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneALIASRecordContext(ctx context.Context, request *DeleteOneALIASRecordRequestType) (*DeleteOneALIASRecordResponseType, error) { + response := new(DeleteOneALIASRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneALIASRecord(request *DeleteOneALIASRecordRequestType) (*DeleteOneALIASRecordResponseType, error) { + return service.DeleteOneALIASRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateCAARecordContext(ctx context.Context, request *CreateCAARecordRequestType) (*CreateCAARecordResponseType, error) { + response := new(CreateCAARecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateCAARecord(request *CreateCAARecordRequestType) (*CreateCAARecordResponseType, error) { + return service.CreateCAARecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneCAARecordContext(ctx context.Context, request *GetOneCAARecordRequestType) (*GetOneCAARecordResponseType, error) { + response := new(GetOneCAARecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneCAARecord(request *GetOneCAARecordRequestType) (*GetOneCAARecordResponseType, error) { + return service.GetOneCAARecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetCAARecordsContext(ctx context.Context, request *GetCAARecordsRequestType) (*GetCAARecordsResponseType, error) { + response := new(GetCAARecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetCAARecords(request *GetCAARecordsRequestType) (*GetCAARecordsResponseType, error) { + return service.GetCAARecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateCAARecordContext(ctx context.Context, request *UpdateCAARecordRequestType) (*UpdateCAARecordResponseType, error) { + response := new(UpdateCAARecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateCAARecord(request *UpdateCAARecordRequestType) (*UpdateCAARecordResponseType, error) { + return service.UpdateCAARecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteCAARecordsContext(ctx context.Context, request *DeleteCAARecordsRequestType) (*DeleteCAARecordsResponseType, error) { + response := new(DeleteCAARecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteCAARecords(request *DeleteCAARecordsRequestType) (*DeleteCAARecordsResponseType, error) { + return service.DeleteCAARecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneCAARecordContext(ctx context.Context, request *DeleteOneCAARecordRequestType) (*DeleteOneCAARecordResponseType, error) { + response := new(DeleteOneCAARecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneCAARecord(request *DeleteOneCAARecordRequestType) (*DeleteOneCAARecordResponseType, error) { + return service.DeleteOneCAARecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateCDNSKEYRecordContext(ctx context.Context, request *CreateCDNSKEYRecordRequestType) (*CreateCDNSKEYRecordResponseType, error) { + response := new(CreateCDNSKEYRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateCDNSKEYRecord(request *CreateCDNSKEYRecordRequestType) (*CreateCDNSKEYRecordResponseType, error) { + return service.CreateCDNSKEYRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneCDNSKEYRecordContext(ctx context.Context, request *GetOneCDNSKEYRecordRequestType) (*GetOneCDNSKEYRecordResponseType, error) { + response := new(GetOneCDNSKEYRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneCDNSKEYRecord(request *GetOneCDNSKEYRecordRequestType) (*GetOneCDNSKEYRecordResponseType, error) { + return service.GetOneCDNSKEYRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetCDNSKEYRecordsContext(ctx context.Context, request *GetCDNSKEYRecordsRequestType) (*GetCDNSKEYRecordsResponseType, error) { + response := new(GetCDNSKEYRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetCDNSKEYRecords(request *GetCDNSKEYRecordsRequestType) (*GetCDNSKEYRecordsResponseType, error) { + return service.GetCDNSKEYRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateCDNSKEYRecordContext(ctx context.Context, request *UpdateCDNSKEYRecordRequestType) (*UpdateCDNSKEYRecordResponseType, error) { + response := new(UpdateCDNSKEYRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateCDNSKEYRecord(request *UpdateCDNSKEYRecordRequestType) (*UpdateCDNSKEYRecordResponseType, error) { + return service.UpdateCDNSKEYRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteCDNSKEYRecordsContext(ctx context.Context, request *DeleteCDNSKEYRecordsRequestType) (*DeleteCDNSKEYRecordsResponseType, error) { + response := new(DeleteCDNSKEYRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteCDNSKEYRecords(request *DeleteCDNSKEYRecordsRequestType) (*DeleteCDNSKEYRecordsResponseType, error) { + return service.DeleteCDNSKEYRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneCDNSKEYRecordContext(ctx context.Context, request *DeleteOneCDNSKEYRecordRequestType) (*DeleteOneCDNSKEYRecordResponseType, error) { + response := new(DeleteOneCDNSKEYRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneCDNSKEYRecord(request *DeleteOneCDNSKEYRecordRequestType) (*DeleteOneCDNSKEYRecordResponseType, error) { + return service.DeleteOneCDNSKEYRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateCDSRecordContext(ctx context.Context, request *CreateCDSRecordRequestType) (*CreateCDSRecordResponseType, error) { + response := new(CreateCDSRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateCDSRecord(request *CreateCDSRecordRequestType) (*CreateCDSRecordResponseType, error) { + return service.CreateCDSRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneCDSRecordContext(ctx context.Context, request *GetOneCDSRecordRequestType) (*GetOneCDSRecordResponseType, error) { + response := new(GetOneCDSRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneCDSRecord(request *GetOneCDSRecordRequestType) (*GetOneCDSRecordResponseType, error) { + return service.GetOneCDSRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetCDSRecordsContext(ctx context.Context, request *GetCDSRecordsRequestType) (*GetCDSRecordsResponseType, error) { + response := new(GetCDSRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetCDSRecords(request *GetCDSRecordsRequestType) (*GetCDSRecordsResponseType, error) { + return service.GetCDSRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateCDSRecordContext(ctx context.Context, request *UpdateCDSRecordRequestType) (*UpdateCDSRecordResponseType, error) { + response := new(UpdateCDSRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateCDSRecord(request *UpdateCDSRecordRequestType) (*UpdateCDSRecordResponseType, error) { + return service.UpdateCDSRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteCDSRecordsContext(ctx context.Context, request *DeleteCDSRecordsRequestType) (*DeleteCDSRecordsResponseType, error) { + response := new(DeleteCDSRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteCDSRecords(request *DeleteCDSRecordsRequestType) (*DeleteCDSRecordsResponseType, error) { + return service.DeleteCDSRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneCDSRecordContext(ctx context.Context, request *DeleteOneCDSRecordRequestType) (*DeleteOneCDSRecordResponseType, error) { + response := new(DeleteOneCDSRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneCDSRecord(request *DeleteOneCDSRecordRequestType) (*DeleteOneCDSRecordResponseType, error) { + return service.DeleteOneCDSRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateCERTRecordContext(ctx context.Context, request *CreateCERTRecordRequestType) (*CreateCERTRecordResponseType, error) { + response := new(CreateCERTRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateCERTRecord(request *CreateCERTRecordRequestType) (*CreateCERTRecordResponseType, error) { + return service.CreateCERTRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneCERTRecordContext(ctx context.Context, request *GetOneCERTRecordRequestType) (*GetOneCERTRecordResponseType, error) { + response := new(GetOneCERTRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneCERTRecord(request *GetOneCERTRecordRequestType) (*GetOneCERTRecordResponseType, error) { + return service.GetOneCERTRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetCERTRecordsContext(ctx context.Context, request *GetCERTRecordsRequestType) (*GetCERTRecordsResponseType, error) { + response := new(GetCERTRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetCERTRecords(request *GetCERTRecordsRequestType) (*GetCERTRecordsResponseType, error) { + return service.GetCERTRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateCERTRecordContext(ctx context.Context, request *UpdateCERTRecordRequestType) (*UpdateCERTRecordResponseType, error) { + response := new(UpdateCERTRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateCERTRecord(request *UpdateCERTRecordRequestType) (*UpdateCERTRecordResponseType, error) { + return service.UpdateCERTRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteCERTRecordsContext(ctx context.Context, request *DeleteCERTRecordsRequestType) (*DeleteCERTRecordsResponseType, error) { + response := new(DeleteCERTRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteCERTRecords(request *DeleteCERTRecordsRequestType) (*DeleteCERTRecordsResponseType, error) { + return service.DeleteCERTRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneCERTRecordContext(ctx context.Context, request *DeleteOneCERTRecordRequestType) (*DeleteOneCERTRecordResponseType, error) { + response := new(DeleteOneCERTRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneCERTRecord(request *DeleteOneCERTRecordRequestType) (*DeleteOneCERTRecordResponseType, error) { + return service.DeleteOneCERTRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateCNAMERecordContext(ctx context.Context, request *CreateCNAMERecordRequestType) (*CreateCNAMERecordResponseType, error) { + response := new(CreateCNAMERecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateCNAMERecord(request *CreateCNAMERecordRequestType) (*CreateCNAMERecordResponseType, error) { + return service.CreateCNAMERecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneCNAMERecordContext(ctx context.Context, request *GetOneCNAMERecordRequestType) (*GetOneCNAMERecordResponseType, error) { + response := new(GetOneCNAMERecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneCNAMERecord(request *GetOneCNAMERecordRequestType) (*GetOneCNAMERecordResponseType, error) { + return service.GetOneCNAMERecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetCNAMERecordsContext(ctx context.Context, request *GetCNAMERecordsRequestType) (*GetCNAMERecordsResponseType, error) { + response := new(GetCNAMERecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetCNAMERecords(request *GetCNAMERecordsRequestType) (*GetCNAMERecordsResponseType, error) { + return service.GetCNAMERecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateCNAMERecordContext(ctx context.Context, request *UpdateCNAMERecordRequestType) (*UpdateCNAMERecordResponseType, error) { + response := new(UpdateCNAMERecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateCNAMERecord(request *UpdateCNAMERecordRequestType) (*UpdateCNAMERecordResponseType, error) { + return service.UpdateCNAMERecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteCNAMERecordsContext(ctx context.Context, request *DeleteCNAMERecordsRequestType) (*DeleteCNAMERecordsResponseType, error) { + response := new(DeleteCNAMERecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteCNAMERecords(request *DeleteCNAMERecordsRequestType) (*DeleteCNAMERecordsResponseType, error) { + return service.DeleteCNAMERecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneCNAMERecordContext(ctx context.Context, request *DeleteOneCNAMERecordRequestType) (*DeleteOneCNAMERecordResponseType, error) { + response := new(DeleteOneCNAMERecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneCNAMERecord(request *DeleteOneCNAMERecordRequestType) (*DeleteOneCNAMERecordResponseType, error) { + return service.DeleteOneCNAMERecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateCSYNCRecordContext(ctx context.Context, request *CreateCSYNCRecordRequestType) (*CreateCSYNCRecordResponseType, error) { + response := new(CreateCSYNCRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateCSYNCRecord(request *CreateCSYNCRecordRequestType) (*CreateCSYNCRecordResponseType, error) { + return service.CreateCSYNCRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneCSYNCRecordContext(ctx context.Context, request *GetOneCSYNCRecordRequestType) (*GetOneCSYNCRecordResponseType, error) { + response := new(GetOneCSYNCRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneCSYNCRecord(request *GetOneCSYNCRecordRequestType) (*GetOneCSYNCRecordResponseType, error) { + return service.GetOneCSYNCRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetCSYNCRecordsContext(ctx context.Context, request *GetCSYNCRecordsRequestType) (*GetCSYNCRecordsResponseType, error) { + response := new(GetCSYNCRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetCSYNCRecords(request *GetCSYNCRecordsRequestType) (*GetCSYNCRecordsResponseType, error) { + return service.GetCSYNCRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateCSYNCRecordContext(ctx context.Context, request *UpdateCSYNCRecordRequestType) (*UpdateCSYNCRecordResponseType, error) { + response := new(UpdateCSYNCRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateCSYNCRecord(request *UpdateCSYNCRecordRequestType) (*UpdateCSYNCRecordResponseType, error) { + return service.UpdateCSYNCRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteCSYNCRecordsContext(ctx context.Context, request *DeleteCSYNCRecordsRequestType) (*DeleteCSYNCRecordsResponseType, error) { + response := new(DeleteCSYNCRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteCSYNCRecords(request *DeleteCSYNCRecordsRequestType) (*DeleteCSYNCRecordsResponseType, error) { + return service.DeleteCSYNCRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneCSYNCRecordContext(ctx context.Context, request *DeleteOneCSYNCRecordRequestType) (*DeleteOneCSYNCRecordResponseType, error) { + response := new(DeleteOneCSYNCRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneCSYNCRecord(request *DeleteOneCSYNCRecordRequestType) (*DeleteOneCSYNCRecordResponseType, error) { + return service.DeleteOneCSYNCRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateDHCIDRecordContext(ctx context.Context, request *CreateDHCIDRecordRequestType) (*CreateDHCIDRecordResponseType, error) { + response := new(CreateDHCIDRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateDHCIDRecord(request *CreateDHCIDRecordRequestType) (*CreateDHCIDRecordResponseType, error) { + return service.CreateDHCIDRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneDHCIDRecordContext(ctx context.Context, request *GetOneDHCIDRecordRequestType) (*GetOneDHCIDRecordResponseType, error) { + response := new(GetOneDHCIDRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneDHCIDRecord(request *GetOneDHCIDRecordRequestType) (*GetOneDHCIDRecordResponseType, error) { + return service.GetOneDHCIDRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetDHCIDRecordsContext(ctx context.Context, request *GetDHCIDRecordsRequestType) (*GetDHCIDRecordsResponseType, error) { + response := new(GetDHCIDRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetDHCIDRecords(request *GetDHCIDRecordsRequestType) (*GetDHCIDRecordsResponseType, error) { + return service.GetDHCIDRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateDHCIDRecordContext(ctx context.Context, request *UpdateDHCIDRecordRequestType) (*UpdateDHCIDRecordResponseType, error) { + response := new(UpdateDHCIDRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateDHCIDRecord(request *UpdateDHCIDRecordRequestType) (*UpdateDHCIDRecordResponseType, error) { + return service.UpdateDHCIDRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteDHCIDRecordsContext(ctx context.Context, request *DeleteDHCIDRecordsRequestType) (*DeleteDHCIDRecordsResponseType, error) { + response := new(DeleteDHCIDRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteDHCIDRecords(request *DeleteDHCIDRecordsRequestType) (*DeleteDHCIDRecordsResponseType, error) { + return service.DeleteDHCIDRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneDHCIDRecordContext(ctx context.Context, request *DeleteOneDHCIDRecordRequestType) (*DeleteOneDHCIDRecordResponseType, error) { + response := new(DeleteOneDHCIDRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneDHCIDRecord(request *DeleteOneDHCIDRecordRequestType) (*DeleteOneDHCIDRecordResponseType, error) { + return service.DeleteOneDHCIDRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateDNAMERecordContext(ctx context.Context, request *CreateDNAMERecordRequestType) (*CreateDNAMERecordResponseType, error) { + response := new(CreateDNAMERecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateDNAMERecord(request *CreateDNAMERecordRequestType) (*CreateDNAMERecordResponseType, error) { + return service.CreateDNAMERecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneDNAMERecordContext(ctx context.Context, request *GetOneDNAMERecordRequestType) (*GetOneDNAMERecordResponseType, error) { + response := new(GetOneDNAMERecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneDNAMERecord(request *GetOneDNAMERecordRequestType) (*GetOneDNAMERecordResponseType, error) { + return service.GetOneDNAMERecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetDNAMERecordsContext(ctx context.Context, request *GetDNAMERecordsRequestType) (*GetDNAMERecordsResponseType, error) { + response := new(GetDNAMERecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetDNAMERecords(request *GetDNAMERecordsRequestType) (*GetDNAMERecordsResponseType, error) { + return service.GetDNAMERecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateDNAMERecordContext(ctx context.Context, request *UpdateDNAMERecordRequestType) (*UpdateDNAMERecordResponseType, error) { + response := new(UpdateDNAMERecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateDNAMERecord(request *UpdateDNAMERecordRequestType) (*UpdateDNAMERecordResponseType, error) { + return service.UpdateDNAMERecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteDNAMERecordsContext(ctx context.Context, request *DeleteDNAMERecordsRequestType) (*DeleteDNAMERecordsResponseType, error) { + response := new(DeleteDNAMERecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteDNAMERecords(request *DeleteDNAMERecordsRequestType) (*DeleteDNAMERecordsResponseType, error) { + return service.DeleteDNAMERecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneDNAMERecordContext(ctx context.Context, request *DeleteOneDNAMERecordRequestType) (*DeleteOneDNAMERecordResponseType, error) { + response := new(DeleteOneDNAMERecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneDNAMERecord(request *DeleteOneDNAMERecordRequestType) (*DeleteOneDNAMERecordResponseType, error) { + return service.DeleteOneDNAMERecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateDNSKEYRecordContext(ctx context.Context, request *CreateDNSKEYRecordRequestType) (*CreateDNSKEYRecordResponseType, error) { + response := new(CreateDNSKEYRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateDNSKEYRecord(request *CreateDNSKEYRecordRequestType) (*CreateDNSKEYRecordResponseType, error) { + return service.CreateDNSKEYRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneDNSKEYRecordContext(ctx context.Context, request *GetOneDNSKEYRecordRequestType) (*GetOneDNSKEYRecordResponseType, error) { + response := new(GetOneDNSKEYRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneDNSKEYRecord(request *GetOneDNSKEYRecordRequestType) (*GetOneDNSKEYRecordResponseType, error) { + return service.GetOneDNSKEYRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetDNSKEYRecordsContext(ctx context.Context, request *GetDNSKEYRecordsRequestType) (*GetDNSKEYRecordsResponseType, error) { + response := new(GetDNSKEYRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetDNSKEYRecords(request *GetDNSKEYRecordsRequestType) (*GetDNSKEYRecordsResponseType, error) { + return service.GetDNSKEYRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateDNSKEYRecordContext(ctx context.Context, request *UpdateDNSKEYRecordRequestType) (*UpdateDNSKEYRecordResponseType, error) { + response := new(UpdateDNSKEYRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateDNSKEYRecord(request *UpdateDNSKEYRecordRequestType) (*UpdateDNSKEYRecordResponseType, error) { + return service.UpdateDNSKEYRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteDNSKEYRecordsContext(ctx context.Context, request *DeleteDNSKEYRecordsRequestType) (*DeleteDNSKEYRecordsResponseType, error) { + response := new(DeleteDNSKEYRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteDNSKEYRecords(request *DeleteDNSKEYRecordsRequestType) (*DeleteDNSKEYRecordsResponseType, error) { + return service.DeleteDNSKEYRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneDNSKEYRecordContext(ctx context.Context, request *DeleteOneDNSKEYRecordRequestType) (*DeleteOneDNSKEYRecordResponseType, error) { + response := new(DeleteOneDNSKEYRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneDNSKEYRecord(request *DeleteOneDNSKEYRecordRequestType) (*DeleteOneDNSKEYRecordResponseType, error) { + return service.DeleteOneDNSKEYRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateDSRecordContext(ctx context.Context, request *CreateDSRecordRequestType) (*CreateDSRecordResponseType, error) { + response := new(CreateDSRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateDSRecord(request *CreateDSRecordRequestType) (*CreateDSRecordResponseType, error) { + return service.CreateDSRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneDSRecordContext(ctx context.Context, request *GetOneDSRecordRequestType) (*GetOneDSRecordResponseType, error) { + response := new(GetOneDSRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneDSRecord(request *GetOneDSRecordRequestType) (*GetOneDSRecordResponseType, error) { + return service.GetOneDSRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetDSRecordsContext(ctx context.Context, request *GetDSRecordsRequestType) (*GetDSRecordsResponseType, error) { + response := new(GetDSRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetDSRecords(request *GetDSRecordsRequestType) (*GetDSRecordsResponseType, error) { + return service.GetDSRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateDSRecordContext(ctx context.Context, request *UpdateDSRecordRequestType) (*UpdateDSRecordResponseType, error) { + response := new(UpdateDSRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateDSRecord(request *UpdateDSRecordRequestType) (*UpdateDSRecordResponseType, error) { + return service.UpdateDSRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteDSRecordsContext(ctx context.Context, request *DeleteDSRecordsRequestType) (*DeleteDSRecordsResponseType, error) { + response := new(DeleteDSRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteDSRecords(request *DeleteDSRecordsRequestType) (*DeleteDSRecordsResponseType, error) { + return service.DeleteDSRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneDSRecordContext(ctx context.Context, request *DeleteOneDSRecordRequestType) (*DeleteOneDSRecordResponseType, error) { + response := new(DeleteOneDSRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneDSRecord(request *DeleteOneDSRecordRequestType) (*DeleteOneDSRecordResponseType, error) { + return service.DeleteOneDSRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateIPSECKEYRecordContext(ctx context.Context, request *CreateIPSECKEYRecordRequestType) (*CreateIPSECKEYRecordResponseType, error) { + response := new(CreateIPSECKEYRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateIPSECKEYRecord(request *CreateIPSECKEYRecordRequestType) (*CreateIPSECKEYRecordResponseType, error) { + return service.CreateIPSECKEYRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneIPSECKEYRecordContext(ctx context.Context, request *GetOneIPSECKEYRecordRequestType) (*GetOneIPSECKEYRecordResponseType, error) { + response := new(GetOneIPSECKEYRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneIPSECKEYRecord(request *GetOneIPSECKEYRecordRequestType) (*GetOneIPSECKEYRecordResponseType, error) { + return service.GetOneIPSECKEYRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetIPSECKEYRecordsContext(ctx context.Context, request *GetIPSECKEYRecordsRequestType) (*GetIPSECKEYRecordsResponseType, error) { + response := new(GetIPSECKEYRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetIPSECKEYRecords(request *GetIPSECKEYRecordsRequestType) (*GetIPSECKEYRecordsResponseType, error) { + return service.GetIPSECKEYRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateIPSECKEYRecordContext(ctx context.Context, request *UpdateIPSECKEYRecordRequestType) (*UpdateIPSECKEYRecordResponseType, error) { + response := new(UpdateIPSECKEYRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateIPSECKEYRecord(request *UpdateIPSECKEYRecordRequestType) (*UpdateIPSECKEYRecordResponseType, error) { + return service.UpdateIPSECKEYRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteIPSECKEYRecordsContext(ctx context.Context, request *DeleteIPSECKEYRecordsRequestType) (*DeleteIPSECKEYRecordsResponseType, error) { + response := new(DeleteIPSECKEYRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteIPSECKEYRecords(request *DeleteIPSECKEYRecordsRequestType) (*DeleteIPSECKEYRecordsResponseType, error) { + return service.DeleteIPSECKEYRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneIPSECKEYRecordContext(ctx context.Context, request *DeleteOneIPSECKEYRecordRequestType) (*DeleteOneIPSECKEYRecordResponseType, error) { + response := new(DeleteOneIPSECKEYRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneIPSECKEYRecord(request *DeleteOneIPSECKEYRecordRequestType) (*DeleteOneIPSECKEYRecordResponseType, error) { + return service.DeleteOneIPSECKEYRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateKEYRecordContext(ctx context.Context, request *CreateKEYRecordRequestType) (*CreateKEYRecordResponseType, error) { + response := new(CreateKEYRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateKEYRecord(request *CreateKEYRecordRequestType) (*CreateKEYRecordResponseType, error) { + return service.CreateKEYRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneKEYRecordContext(ctx context.Context, request *GetOneKEYRecordRequestType) (*GetOneKEYRecordResponseType, error) { + response := new(GetOneKEYRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneKEYRecord(request *GetOneKEYRecordRequestType) (*GetOneKEYRecordResponseType, error) { + return service.GetOneKEYRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetKEYRecordsContext(ctx context.Context, request *GetKEYRecordsRequestType) (*GetKEYRecordsResponseType, error) { + response := new(GetKEYRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetKEYRecords(request *GetKEYRecordsRequestType) (*GetKEYRecordsResponseType, error) { + return service.GetKEYRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateKEYRecordContext(ctx context.Context, request *UpdateKEYRecordRequestType) (*UpdateKEYRecordResponseType, error) { + response := new(UpdateKEYRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateKEYRecord(request *UpdateKEYRecordRequestType) (*UpdateKEYRecordResponseType, error) { + return service.UpdateKEYRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteKEYRecordsContext(ctx context.Context, request *DeleteKEYRecordsRequestType) (*DeleteKEYRecordsResponseType, error) { + response := new(DeleteKEYRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteKEYRecords(request *DeleteKEYRecordsRequestType) (*DeleteKEYRecordsResponseType, error) { + return service.DeleteKEYRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneKEYRecordContext(ctx context.Context, request *DeleteOneKEYRecordRequestType) (*DeleteOneKEYRecordResponseType, error) { + response := new(DeleteOneKEYRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneKEYRecord(request *DeleteOneKEYRecordRequestType) (*DeleteOneKEYRecordResponseType, error) { + return service.DeleteOneKEYRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateKXRecordContext(ctx context.Context, request *CreateKXRecordRequestType) (*CreateKXRecordResponseType, error) { + response := new(CreateKXRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateKXRecord(request *CreateKXRecordRequestType) (*CreateKXRecordResponseType, error) { + return service.CreateKXRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneKXRecordContext(ctx context.Context, request *GetOneKXRecordRequestType) (*GetOneKXRecordResponseType, error) { + response := new(GetOneKXRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneKXRecord(request *GetOneKXRecordRequestType) (*GetOneKXRecordResponseType, error) { + return service.GetOneKXRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetKXRecordsContext(ctx context.Context, request *GetKXRecordsRequestType) (*GetKXRecordsResponseType, error) { + response := new(GetKXRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetKXRecords(request *GetKXRecordsRequestType) (*GetKXRecordsResponseType, error) { + return service.GetKXRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateKXRecordContext(ctx context.Context, request *UpdateKXRecordRequestType) (*UpdateKXRecordResponseType, error) { + response := new(UpdateKXRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateKXRecord(request *UpdateKXRecordRequestType) (*UpdateKXRecordResponseType, error) { + return service.UpdateKXRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteKXRecordsContext(ctx context.Context, request *DeleteKXRecordsRequestType) (*DeleteKXRecordsResponseType, error) { + response := new(DeleteKXRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteKXRecords(request *DeleteKXRecordsRequestType) (*DeleteKXRecordsResponseType, error) { + return service.DeleteKXRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneKXRecordContext(ctx context.Context, request *DeleteOneKXRecordRequestType) (*DeleteOneKXRecordResponseType, error) { + response := new(DeleteOneKXRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneKXRecord(request *DeleteOneKXRecordRequestType) (*DeleteOneKXRecordResponseType, error) { + return service.DeleteOneKXRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateLOCRecordContext(ctx context.Context, request *CreateLOCRecordRequestType) (*CreateLOCRecordResponseType, error) { + response := new(CreateLOCRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateLOCRecord(request *CreateLOCRecordRequestType) (*CreateLOCRecordResponseType, error) { + return service.CreateLOCRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneLOCRecordContext(ctx context.Context, request *GetOneLOCRecordRequestType) (*GetOneLOCRecordResponseType, error) { + response := new(GetOneLOCRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneLOCRecord(request *GetOneLOCRecordRequestType) (*GetOneLOCRecordResponseType, error) { + return service.GetOneLOCRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetLOCRecordsContext(ctx context.Context, request *GetLOCRecordsRequestType) (*GetLOCRecordsResponseType, error) { + response := new(GetLOCRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetLOCRecords(request *GetLOCRecordsRequestType) (*GetLOCRecordsResponseType, error) { + return service.GetLOCRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateLOCRecordContext(ctx context.Context, request *UpdateLOCRecordRequestType) (*UpdateLOCRecordResponseType, error) { + response := new(UpdateLOCRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateLOCRecord(request *UpdateLOCRecordRequestType) (*UpdateLOCRecordResponseType, error) { + return service.UpdateLOCRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteLOCRecordsContext(ctx context.Context, request *DeleteLOCRecordsRequestType) (*DeleteLOCRecordsResponseType, error) { + response := new(DeleteLOCRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteLOCRecords(request *DeleteLOCRecordsRequestType) (*DeleteLOCRecordsResponseType, error) { + return service.DeleteLOCRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneLOCRecordContext(ctx context.Context, request *DeleteOneLOCRecordRequestType) (*DeleteOneLOCRecordResponseType, error) { + response := new(DeleteOneLOCRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneLOCRecord(request *DeleteOneLOCRecordRequestType) (*DeleteOneLOCRecordResponseType, error) { + return service.DeleteOneLOCRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateMXRecordContext(ctx context.Context, request *CreateMXRecordRequestType) (*CreateMXRecordResponseType, error) { + response := new(CreateMXRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateMXRecord(request *CreateMXRecordRequestType) (*CreateMXRecordResponseType, error) { + return service.CreateMXRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneMXRecordContext(ctx context.Context, request *GetOneMXRecordRequestType) (*GetOneMXRecordResponseType, error) { + response := new(GetOneMXRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneMXRecord(request *GetOneMXRecordRequestType) (*GetOneMXRecordResponseType, error) { + return service.GetOneMXRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetMXRecordsContext(ctx context.Context, request *GetMXRecordsRequestType) (*GetMXRecordsResponseType, error) { + response := new(GetMXRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetMXRecords(request *GetMXRecordsRequestType) (*GetMXRecordsResponseType, error) { + return service.GetMXRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateMXRecordContext(ctx context.Context, request *UpdateMXRecordRequestType) (*UpdateMXRecordResponseType, error) { + response := new(UpdateMXRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateMXRecord(request *UpdateMXRecordRequestType) (*UpdateMXRecordResponseType, error) { + return service.UpdateMXRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteMXRecordsContext(ctx context.Context, request *DeleteMXRecordsRequestType) (*DeleteMXRecordsResponseType, error) { + response := new(DeleteMXRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteMXRecords(request *DeleteMXRecordsRequestType) (*DeleteMXRecordsResponseType, error) { + return service.DeleteMXRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneMXRecordContext(ctx context.Context, request *DeleteOneMXRecordRequestType) (*DeleteOneMXRecordResponseType, error) { + response := new(DeleteOneMXRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneMXRecord(request *DeleteOneMXRecordRequestType) (*DeleteOneMXRecordResponseType, error) { + return service.DeleteOneMXRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateNAPTRRecordContext(ctx context.Context, request *CreateNAPTRRecordRequestType) (*CreateNAPTRRecordResponseType, error) { + response := new(CreateNAPTRRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateNAPTRRecord(request *CreateNAPTRRecordRequestType) (*CreateNAPTRRecordResponseType, error) { + return service.CreateNAPTRRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneNAPTRRecordContext(ctx context.Context, request *GetOneNAPTRRecordRequestType) (*GetOneNAPTRRecordResponseType, error) { + response := new(GetOneNAPTRRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneNAPTRRecord(request *GetOneNAPTRRecordRequestType) (*GetOneNAPTRRecordResponseType, error) { + return service.GetOneNAPTRRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetNAPTRRecordsContext(ctx context.Context, request *GetNAPTRRecordsRequestType) (*GetNAPTRRecordsResponseType, error) { + response := new(GetNAPTRRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetNAPTRRecords(request *GetNAPTRRecordsRequestType) (*GetNAPTRRecordsResponseType, error) { + return service.GetNAPTRRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateNAPTRRecordContext(ctx context.Context, request *UpdateNAPTRRecordRequestType) (*UpdateNAPTRRecordResponseType, error) { + response := new(UpdateNAPTRRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateNAPTRRecord(request *UpdateNAPTRRecordRequestType) (*UpdateNAPTRRecordResponseType, error) { + return service.UpdateNAPTRRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteNAPTRRecordsContext(ctx context.Context, request *DeleteNAPTRRecordsRequestType) (*DeleteNAPTRRecordsResponseType, error) { + response := new(DeleteNAPTRRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteNAPTRRecords(request *DeleteNAPTRRecordsRequestType) (*DeleteNAPTRRecordsResponseType, error) { + return service.DeleteNAPTRRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneNAPTRRecordContext(ctx context.Context, request *DeleteOneNAPTRRecordRequestType) (*DeleteOneNAPTRRecordResponseType, error) { + response := new(DeleteOneNAPTRRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneNAPTRRecord(request *DeleteOneNAPTRRecordRequestType) (*DeleteOneNAPTRRecordResponseType, error) { + return service.DeleteOneNAPTRRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateNSAPRecordContext(ctx context.Context, request *CreateNSAPRecordRequestType) (*CreateNSAPRecordResponseType, error) { + response := new(CreateNSAPRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateNSAPRecord(request *CreateNSAPRecordRequestType) (*CreateNSAPRecordResponseType, error) { + return service.CreateNSAPRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneNSAPRecordContext(ctx context.Context, request *GetOneNSAPRecordRequestType) (*GetOneNSAPRecordResponseType, error) { + response := new(GetOneNSAPRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneNSAPRecord(request *GetOneNSAPRecordRequestType) (*GetOneNSAPRecordResponseType, error) { + return service.GetOneNSAPRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetNSAPRecordsContext(ctx context.Context, request *GetNSAPRecordsRequestType) (*GetNSAPRecordsResponseType, error) { + response := new(GetNSAPRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetNSAPRecords(request *GetNSAPRecordsRequestType) (*GetNSAPRecordsResponseType, error) { + return service.GetNSAPRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateNSAPRecordContext(ctx context.Context, request *UpdateNSAPRecordRequestType) (*UpdateNSAPRecordResponseType, error) { + response := new(UpdateNSAPRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateNSAPRecord(request *UpdateNSAPRecordRequestType) (*UpdateNSAPRecordResponseType, error) { + return service.UpdateNSAPRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteNSAPRecordsContext(ctx context.Context, request *DeleteNSAPRecordsRequestType) (*DeleteNSAPRecordsResponseType, error) { + response := new(DeleteNSAPRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteNSAPRecords(request *DeleteNSAPRecordsRequestType) (*DeleteNSAPRecordsResponseType, error) { + return service.DeleteNSAPRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneNSAPRecordContext(ctx context.Context, request *DeleteOneNSAPRecordRequestType) (*DeleteOneNSAPRecordResponseType, error) { + response := new(DeleteOneNSAPRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneNSAPRecord(request *DeleteOneNSAPRecordRequestType) (*DeleteOneNSAPRecordResponseType, error) { + return service.DeleteOneNSAPRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreatePOLICYRecordContext(ctx context.Context, request *CreatePOLICYRecordRequestType) (*CreatePOLICYRecordResponseType, error) { + response := new(CreatePOLICYRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreatePOLICYRecord(request *CreatePOLICYRecordRequestType) (*CreatePOLICYRecordResponseType, error) { + return service.CreatePOLICYRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOnePOLICYRecordContext(ctx context.Context, request *GetOnePOLICYRecordRequestType) (*GetOnePOLICYRecordResponseType, error) { + response := new(GetOnePOLICYRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOnePOLICYRecord(request *GetOnePOLICYRecordRequestType) (*GetOnePOLICYRecordResponseType, error) { + return service.GetOnePOLICYRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetPOLICYRecordsContext(ctx context.Context, request *GetPOLICYRecordsRequestType) (*GetPOLICYRecordsResponseType, error) { + response := new(GetPOLICYRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetPOLICYRecords(request *GetPOLICYRecordsRequestType) (*GetPOLICYRecordsResponseType, error) { + return service.GetPOLICYRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdatePOLICYRecordContext(ctx context.Context, request *UpdatePOLICYRecordRequestType) (*UpdatePOLICYRecordResponseType, error) { + response := new(UpdatePOLICYRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdatePOLICYRecord(request *UpdatePOLICYRecordRequestType) (*UpdatePOLICYRecordResponseType, error) { + return service.UpdatePOLICYRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeletePOLICYRecordsContext(ctx context.Context, request *DeletePOLICYRecordsRequestType) (*DeletePOLICYRecordsResponseType, error) { + response := new(DeletePOLICYRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeletePOLICYRecords(request *DeletePOLICYRecordsRequestType) (*DeletePOLICYRecordsResponseType, error) { + return service.DeletePOLICYRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOnePOLICYRecordContext(ctx context.Context, request *DeleteOnePOLICYRecordRequestType) (*DeleteOnePOLICYRecordResponseType, error) { + response := new(DeleteOnePOLICYRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOnePOLICYRecord(request *DeleteOnePOLICYRecordRequestType) (*DeleteOnePOLICYRecordResponseType, error) { + return service.DeleteOnePOLICYRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreatePTRRecordContext(ctx context.Context, request *CreatePTRRecordRequestType) (*CreatePTRRecordResponseType, error) { + response := new(CreatePTRRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreatePTRRecord(request *CreatePTRRecordRequestType) (*CreatePTRRecordResponseType, error) { + return service.CreatePTRRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOnePTRRecordContext(ctx context.Context, request *GetOnePTRRecordRequestType) (*GetOnePTRRecordResponseType, error) { + response := new(GetOnePTRRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOnePTRRecord(request *GetOnePTRRecordRequestType) (*GetOnePTRRecordResponseType, error) { + return service.GetOnePTRRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetPTRRecordsContext(ctx context.Context, request *GetPTRRecordsRequestType) (*GetPTRRecordsResponseType, error) { + response := new(GetPTRRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetPTRRecords(request *GetPTRRecordsRequestType) (*GetPTRRecordsResponseType, error) { + return service.GetPTRRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdatePTRRecordContext(ctx context.Context, request *UpdatePTRRecordRequestType) (*UpdatePTRRecordResponseType, error) { + response := new(UpdatePTRRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdatePTRRecord(request *UpdatePTRRecordRequestType) (*UpdatePTRRecordResponseType, error) { + return service.UpdatePTRRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeletePTRRecordsContext(ctx context.Context, request *DeletePTRRecordsRequestType) (*DeletePTRRecordsResponseType, error) { + response := new(DeletePTRRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeletePTRRecords(request *DeletePTRRecordsRequestType) (*DeletePTRRecordsResponseType, error) { + return service.DeletePTRRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOnePTRRecordContext(ctx context.Context, request *DeleteOnePTRRecordRequestType) (*DeleteOnePTRRecordResponseType, error) { + response := new(DeleteOnePTRRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOnePTRRecord(request *DeleteOnePTRRecordRequestType) (*DeleteOnePTRRecordResponseType, error) { + return service.DeleteOnePTRRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreatePXRecordContext(ctx context.Context, request *CreatePXRecordRequestType) (*CreatePXRecordResponseType, error) { + response := new(CreatePXRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreatePXRecord(request *CreatePXRecordRequestType) (*CreatePXRecordResponseType, error) { + return service.CreatePXRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOnePXRecordContext(ctx context.Context, request *GetOnePXRecordRequestType) (*GetOnePXRecordResponseType, error) { + response := new(GetOnePXRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOnePXRecord(request *GetOnePXRecordRequestType) (*GetOnePXRecordResponseType, error) { + return service.GetOnePXRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetPXRecordsContext(ctx context.Context, request *GetPXRecordsRequestType) (*GetPXRecordsResponseType, error) { + response := new(GetPXRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetPXRecords(request *GetPXRecordsRequestType) (*GetPXRecordsResponseType, error) { + return service.GetPXRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdatePXRecordContext(ctx context.Context, request *UpdatePXRecordRequestType) (*UpdatePXRecordResponseType, error) { + response := new(UpdatePXRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdatePXRecord(request *UpdatePXRecordRequestType) (*UpdatePXRecordResponseType, error) { + return service.UpdatePXRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeletePXRecordsContext(ctx context.Context, request *DeletePXRecordsRequestType) (*DeletePXRecordsResponseType, error) { + response := new(DeletePXRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeletePXRecords(request *DeletePXRecordsRequestType) (*DeletePXRecordsResponseType, error) { + return service.DeletePXRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOnePXRecordContext(ctx context.Context, request *DeleteOnePXRecordRequestType) (*DeleteOnePXRecordResponseType, error) { + response := new(DeleteOnePXRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOnePXRecord(request *DeleteOnePXRecordRequestType) (*DeleteOnePXRecordResponseType, error) { + return service.DeleteOnePXRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateRPRecordContext(ctx context.Context, request *CreateRPRecordRequestType) (*CreateRPRecordResponseType, error) { + response := new(CreateRPRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateRPRecord(request *CreateRPRecordRequestType) (*CreateRPRecordResponseType, error) { + return service.CreateRPRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneRPRecordContext(ctx context.Context, request *GetOneRPRecordRequestType) (*GetOneRPRecordResponseType, error) { + response := new(GetOneRPRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneRPRecord(request *GetOneRPRecordRequestType) (*GetOneRPRecordResponseType, error) { + return service.GetOneRPRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetRPRecordsContext(ctx context.Context, request *GetRPRecordsRequestType) (*GetRPRecordsResponseType, error) { + response := new(GetRPRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetRPRecords(request *GetRPRecordsRequestType) (*GetRPRecordsResponseType, error) { + return service.GetRPRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateRPRecordContext(ctx context.Context, request *UpdateRPRecordRequestType) (*UpdateRPRecordResponseType, error) { + response := new(UpdateRPRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateRPRecord(request *UpdateRPRecordRequestType) (*UpdateRPRecordResponseType, error) { + return service.UpdateRPRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteRPRecordsContext(ctx context.Context, request *DeleteRPRecordsRequestType) (*DeleteRPRecordsResponseType, error) { + response := new(DeleteRPRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteRPRecords(request *DeleteRPRecordsRequestType) (*DeleteRPRecordsResponseType, error) { + return service.DeleteRPRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneRPRecordContext(ctx context.Context, request *DeleteOneRPRecordRequestType) (*DeleteOneRPRecordResponseType, error) { + response := new(DeleteOneRPRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneRPRecord(request *DeleteOneRPRecordRequestType) (*DeleteOneRPRecordResponseType, error) { + return service.DeleteOneRPRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateSPFRecordContext(ctx context.Context, request *CreateSPFRecordRequestType) (*CreateSPFRecordResponseType, error) { + response := new(CreateSPFRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateSPFRecord(request *CreateSPFRecordRequestType) (*CreateSPFRecordResponseType, error) { + return service.CreateSPFRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneSPFRecordContext(ctx context.Context, request *GetOneSPFRecordRequestType) (*GetOneSPFRecordResponseType, error) { + response := new(GetOneSPFRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneSPFRecord(request *GetOneSPFRecordRequestType) (*GetOneSPFRecordResponseType, error) { + return service.GetOneSPFRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetSPFRecordsContext(ctx context.Context, request *GetSPFRecordsRequestType) (*GetSPFRecordsResponseType, error) { + response := new(GetSPFRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetSPFRecords(request *GetSPFRecordsRequestType) (*GetSPFRecordsResponseType, error) { + return service.GetSPFRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateSPFRecordContext(ctx context.Context, request *UpdateSPFRecordRequestType) (*UpdateSPFRecordResponseType, error) { + response := new(UpdateSPFRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateSPFRecord(request *UpdateSPFRecordRequestType) (*UpdateSPFRecordResponseType, error) { + return service.UpdateSPFRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteSPFRecordsContext(ctx context.Context, request *DeleteSPFRecordsRequestType) (*DeleteSPFRecordsResponseType, error) { + response := new(DeleteSPFRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteSPFRecords(request *DeleteSPFRecordsRequestType) (*DeleteSPFRecordsResponseType, error) { + return service.DeleteSPFRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneSPFRecordContext(ctx context.Context, request *DeleteOneSPFRecordRequestType) (*DeleteOneSPFRecordResponseType, error) { + response := new(DeleteOneSPFRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneSPFRecord(request *DeleteOneSPFRecordRequestType) (*DeleteOneSPFRecordResponseType, error) { + return service.DeleteOneSPFRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateSRVRecordContext(ctx context.Context, request *CreateSRVRecordRequestType) (*CreateSRVRecordResponseType, error) { + response := new(CreateSRVRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateSRVRecord(request *CreateSRVRecordRequestType) (*CreateSRVRecordResponseType, error) { + return service.CreateSRVRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneSRVRecordContext(ctx context.Context, request *GetOneSRVRecordRequestType) (*GetOneSRVRecordResponseType, error) { + response := new(GetOneSRVRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneSRVRecord(request *GetOneSRVRecordRequestType) (*GetOneSRVRecordResponseType, error) { + return service.GetOneSRVRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetSRVRecordsContext(ctx context.Context, request *GetSRVRecordsRequestType) (*GetSRVRecordsResponseType, error) { + response := new(GetSRVRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetSRVRecords(request *GetSRVRecordsRequestType) (*GetSRVRecordsResponseType, error) { + return service.GetSRVRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateSRVRecordContext(ctx context.Context, request *UpdateSRVRecordRequestType) (*UpdateSRVRecordResponseType, error) { + response := new(UpdateSRVRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateSRVRecord(request *UpdateSRVRecordRequestType) (*UpdateSRVRecordResponseType, error) { + return service.UpdateSRVRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteSRVRecordsContext(ctx context.Context, request *DeleteSRVRecordsRequestType) (*DeleteSRVRecordsResponseType, error) { + response := new(DeleteSRVRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteSRVRecords(request *DeleteSRVRecordsRequestType) (*DeleteSRVRecordsResponseType, error) { + return service.DeleteSRVRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneSRVRecordContext(ctx context.Context, request *DeleteOneSRVRecordRequestType) (*DeleteOneSRVRecordResponseType, error) { + response := new(DeleteOneSRVRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneSRVRecord(request *DeleteOneSRVRecordRequestType) (*DeleteOneSRVRecordResponseType, error) { + return service.DeleteOneSRVRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateSSHFPRecordContext(ctx context.Context, request *CreateSSHFPRecordRequestType) (*CreateSSHFPRecordResponseType, error) { + response := new(CreateSSHFPRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateSSHFPRecord(request *CreateSSHFPRecordRequestType) (*CreateSSHFPRecordResponseType, error) { + return service.CreateSSHFPRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneSSHFPRecordContext(ctx context.Context, request *GetOneSSHFPRecordRequestType) (*GetOneSSHFPRecordResponseType, error) { + response := new(GetOneSSHFPRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneSSHFPRecord(request *GetOneSSHFPRecordRequestType) (*GetOneSSHFPRecordResponseType, error) { + return service.GetOneSSHFPRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetSSHFPRecordsContext(ctx context.Context, request *GetSSHFPRecordsRequestType) (*GetSSHFPRecordsResponseType, error) { + response := new(GetSSHFPRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetSSHFPRecords(request *GetSSHFPRecordsRequestType) (*GetSSHFPRecordsResponseType, error) { + return service.GetSSHFPRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateSSHFPRecordContext(ctx context.Context, request *UpdateSSHFPRecordRequestType) (*UpdateSSHFPRecordResponseType, error) { + response := new(UpdateSSHFPRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateSSHFPRecord(request *UpdateSSHFPRecordRequestType) (*UpdateSSHFPRecordResponseType, error) { + return service.UpdateSSHFPRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteSSHFPRecordsContext(ctx context.Context, request *DeleteSSHFPRecordsRequestType) (*DeleteSSHFPRecordsResponseType, error) { + response := new(DeleteSSHFPRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteSSHFPRecords(request *DeleteSSHFPRecordsRequestType) (*DeleteSSHFPRecordsResponseType, error) { + return service.DeleteSSHFPRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneSSHFPRecordContext(ctx context.Context, request *DeleteOneSSHFPRecordRequestType) (*DeleteOneSSHFPRecordResponseType, error) { + response := new(DeleteOneSSHFPRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneSSHFPRecord(request *DeleteOneSSHFPRecordRequestType) (*DeleteOneSSHFPRecordResponseType, error) { + return service.DeleteOneSSHFPRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateTLSARecordContext(ctx context.Context, request *CreateTLSARecordRequestType) (*CreateTLSARecordResponseType, error) { + response := new(CreateTLSARecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateTLSARecord(request *CreateTLSARecordRequestType) (*CreateTLSARecordResponseType, error) { + return service.CreateTLSARecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneTLSARecordContext(ctx context.Context, request *GetOneTLSARecordRequestType) (*GetOneTLSARecordResponseType, error) { + response := new(GetOneTLSARecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneTLSARecord(request *GetOneTLSARecordRequestType) (*GetOneTLSARecordResponseType, error) { + return service.GetOneTLSARecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetTLSARecordsContext(ctx context.Context, request *GetTLSARecordsRequestType) (*GetTLSARecordsResponseType, error) { + response := new(GetTLSARecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetTLSARecords(request *GetTLSARecordsRequestType) (*GetTLSARecordsResponseType, error) { + return service.GetTLSARecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateTLSARecordContext(ctx context.Context, request *UpdateTLSARecordRequestType) (*UpdateTLSARecordResponseType, error) { + response := new(UpdateTLSARecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateTLSARecord(request *UpdateTLSARecordRequestType) (*UpdateTLSARecordResponseType, error) { + return service.UpdateTLSARecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteTLSARecordsContext(ctx context.Context, request *DeleteTLSARecordsRequestType) (*DeleteTLSARecordsResponseType, error) { + response := new(DeleteTLSARecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteTLSARecords(request *DeleteTLSARecordsRequestType) (*DeleteTLSARecordsResponseType, error) { + return service.DeleteTLSARecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneTLSARecordContext(ctx context.Context, request *DeleteOneTLSARecordRequestType) (*DeleteOneTLSARecordResponseType, error) { + response := new(DeleteOneTLSARecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneTLSARecord(request *DeleteOneTLSARecordRequestType) (*DeleteOneTLSARecordResponseType, error) { + return service.DeleteOneTLSARecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateTXTRecordContext(ctx context.Context, request *CreateTXTRecordRequestType) (*CreateTXTRecordResponseType, error) { + response := new(CreateTXTRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateTXTRecord(request *CreateTXTRecordRequestType) (*CreateTXTRecordResponseType, error) { + return service.CreateTXTRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneTXTRecordContext(ctx context.Context, request *GetOneTXTRecordRequestType) (*GetOneTXTRecordResponseType, error) { + response := new(GetOneTXTRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneTXTRecord(request *GetOneTXTRecordRequestType) (*GetOneTXTRecordResponseType, error) { + return service.GetOneTXTRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetTXTRecordsContext(ctx context.Context, request *GetTXTRecordsRequestType) (*GetTXTRecordsResponseType, error) { + response := new(GetTXTRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetTXTRecords(request *GetTXTRecordsRequestType) (*GetTXTRecordsResponseType, error) { + return service.GetTXTRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateTXTRecordContext(ctx context.Context, request *UpdateTXTRecordRequestType) (*UpdateTXTRecordResponseType, error) { + response := new(UpdateTXTRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateTXTRecord(request *UpdateTXTRecordRequestType) (*UpdateTXTRecordResponseType, error) { + return service.UpdateTXTRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteTXTRecordsContext(ctx context.Context, request *DeleteTXTRecordsRequestType) (*DeleteTXTRecordsResponseType, error) { + response := new(DeleteTXTRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteTXTRecords(request *DeleteTXTRecordsRequestType) (*DeleteTXTRecordsResponseType, error) { + return service.DeleteTXTRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneTXTRecordContext(ctx context.Context, request *DeleteOneTXTRecordRequestType) (*DeleteOneTXTRecordResponseType, error) { + response := new(DeleteOneTXTRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneTXTRecord(request *DeleteOneTXTRecordRequestType) (*DeleteOneTXTRecordResponseType, error) { + return service.DeleteOneTXTRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneSOARecordContext(ctx context.Context, request *GetOneSOARecordRequestType) (*GetOneSOARecordResponseType, error) { + response := new(GetOneSOARecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneSOARecord(request *GetOneSOARecordRequestType) (*GetOneSOARecordResponseType, error) { + return service.GetOneSOARecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetSOARecordsContext(ctx context.Context, request *GetSOARecordsRequestType) (*GetSOARecordsResponseType, error) { + response := new(GetSOARecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetSOARecords(request *GetSOARecordsRequestType) (*GetSOARecordsResponseType, error) { + return service.GetSOARecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateSOARecordContext(ctx context.Context, request *UpdateSOARecordRequestType) (*UpdateSOARecordResponseType, error) { + response := new(UpdateSOARecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateSOARecord(request *UpdateSOARecordRequestType) (*UpdateSOARecordResponseType, error) { + return service.UpdateSOARecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateNSRecordContext(ctx context.Context, request *CreateNSRecordRequestType) (*CreateNSRecordResponseType, error) { + response := new(CreateNSRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateNSRecord(request *CreateNSRecordRequestType) (*CreateNSRecordResponseType, error) { + return service.CreateNSRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneNSRecordContext(ctx context.Context, request *GetOneNSRecordRequestType) (*GetOneNSRecordResponseType, error) { + response := new(GetOneNSRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneNSRecord(request *GetOneNSRecordRequestType) (*GetOneNSRecordResponseType, error) { + return service.GetOneNSRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetNSRecordsContext(ctx context.Context, request *GetNSRecordsRequestType) (*GetNSRecordsResponseType, error) { + response := new(GetNSRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetNSRecords(request *GetNSRecordsRequestType) (*GetNSRecordsResponseType, error) { + return service.GetNSRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateNSRecordContext(ctx context.Context, request *UpdateNSRecordRequestType) (*UpdateNSRecordResponseType, error) { + response := new(UpdateNSRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateNSRecord(request *UpdateNSRecordRequestType) (*UpdateNSRecordResponseType, error) { + return service.UpdateNSRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteNSRecordsContext(ctx context.Context, request *DeleteNSRecordsRequestType) (*DeleteNSRecordsResponseType, error) { + response := new(DeleteNSRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteNSRecords(request *DeleteNSRecordsRequestType) (*DeleteNSRecordsResponseType, error) { + return service.DeleteNSRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneNSRecordContext(ctx context.Context, request *DeleteOneNSRecordRequestType) (*DeleteOneNSRecordResponseType, error) { + response := new(DeleteOneNSRecordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneNSRecord(request *DeleteOneNSRecordRequestType) (*DeleteOneNSRecordResponseType, error) { + return service.DeleteOneNSRecordContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceARecordsContext(ctx context.Context, request *ReplaceARecordsRequestType) (*ReplaceARecordsResponseType, error) { + response := new(ReplaceARecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceARecords(request *ReplaceARecordsRequestType) (*ReplaceARecordsResponseType, error) { + return service.ReplaceARecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceAAAARecordsContext(ctx context.Context, request *ReplaceAAAARecordsRequestType) (*ReplaceAAAARecordsResponseType, error) { + response := new(ReplaceAAAARecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceAAAARecords(request *ReplaceAAAARecordsRequestType) (*ReplaceAAAARecordsResponseType, error) { + return service.ReplaceAAAARecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceALIASRecordsContext(ctx context.Context, request *ReplaceALIASRecordsRequestType) (*ReplaceALIASRecordsResponseType, error) { + response := new(ReplaceALIASRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceALIASRecords(request *ReplaceALIASRecordsRequestType) (*ReplaceALIASRecordsResponseType, error) { + return service.ReplaceALIASRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceCAARecordsContext(ctx context.Context, request *ReplaceCAARecordsRequestType) (*ReplaceCAARecordsResponseType, error) { + response := new(ReplaceCAARecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceCAARecords(request *ReplaceCAARecordsRequestType) (*ReplaceCAARecordsResponseType, error) { + return service.ReplaceCAARecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceCDNSKEYRecordsContext(ctx context.Context, request *ReplaceCDNSKEYRecordsRequestType) (*ReplaceCDNSKEYRecordsResponseType, error) { + response := new(ReplaceCDNSKEYRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceCDNSKEYRecords(request *ReplaceCDNSKEYRecordsRequestType) (*ReplaceCDNSKEYRecordsResponseType, error) { + return service.ReplaceCDNSKEYRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceCDSRecordsContext(ctx context.Context, request *ReplaceCDSRecordsRequestType) (*ReplaceCDSRecordsResponseType, error) { + response := new(ReplaceCDSRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceCDSRecords(request *ReplaceCDSRecordsRequestType) (*ReplaceCDSRecordsResponseType, error) { + return service.ReplaceCDSRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceCERTRecordsContext(ctx context.Context, request *ReplaceCERTRecordsRequestType) (*ReplaceCERTRecordsResponseType, error) { + response := new(ReplaceCERTRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceCERTRecords(request *ReplaceCERTRecordsRequestType) (*ReplaceCERTRecordsResponseType, error) { + return service.ReplaceCERTRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceCNAMERecordsContext(ctx context.Context, request *ReplaceCNAMERecordsRequestType) (*ReplaceCNAMERecordsResponseType, error) { + response := new(ReplaceCNAMERecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceCNAMERecords(request *ReplaceCNAMERecordsRequestType) (*ReplaceCNAMERecordsResponseType, error) { + return service.ReplaceCNAMERecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceCSYNCRecordsContext(ctx context.Context, request *ReplaceCSYNCRecordsRequestType) (*ReplaceCSYNCRecordsResponseType, error) { + response := new(ReplaceCSYNCRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceCSYNCRecords(request *ReplaceCSYNCRecordsRequestType) (*ReplaceCSYNCRecordsResponseType, error) { + return service.ReplaceCSYNCRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceDHCIDRecordsContext(ctx context.Context, request *ReplaceDHCIDRecordsRequestType) (*ReplaceDHCIDRecordsResponseType, error) { + response := new(ReplaceDHCIDRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceDHCIDRecords(request *ReplaceDHCIDRecordsRequestType) (*ReplaceDHCIDRecordsResponseType, error) { + return service.ReplaceDHCIDRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceDNAMERecordsContext(ctx context.Context, request *ReplaceDNAMERecordsRequestType) (*ReplaceDNAMERecordsResponseType, error) { + response := new(ReplaceDNAMERecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceDNAMERecords(request *ReplaceDNAMERecordsRequestType) (*ReplaceDNAMERecordsResponseType, error) { + return service.ReplaceDNAMERecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceDNSKEYRecordsContext(ctx context.Context, request *ReplaceDNSKEYRecordsRequestType) (*ReplaceDNSKEYRecordsResponseType, error) { + response := new(ReplaceDNSKEYRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceDNSKEYRecords(request *ReplaceDNSKEYRecordsRequestType) (*ReplaceDNSKEYRecordsResponseType, error) { + return service.ReplaceDNSKEYRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceDSRecordsContext(ctx context.Context, request *ReplaceDSRecordsRequestType) (*ReplaceDSRecordsResponseType, error) { + response := new(ReplaceDSRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceDSRecords(request *ReplaceDSRecordsRequestType) (*ReplaceDSRecordsResponseType, error) { + return service.ReplaceDSRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceIPSECKEYRecordsContext(ctx context.Context, request *ReplaceIPSECKEYRecordsRequestType) (*ReplaceIPSECKEYRecordsResponseType, error) { + response := new(ReplaceIPSECKEYRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceIPSECKEYRecords(request *ReplaceIPSECKEYRecordsRequestType) (*ReplaceIPSECKEYRecordsResponseType, error) { + return service.ReplaceIPSECKEYRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceKEYRecordsContext(ctx context.Context, request *ReplaceKEYRecordsRequestType) (*ReplaceKEYRecordsResponseType, error) { + response := new(ReplaceKEYRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceKEYRecords(request *ReplaceKEYRecordsRequestType) (*ReplaceKEYRecordsResponseType, error) { + return service.ReplaceKEYRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceKXRecordsContext(ctx context.Context, request *ReplaceKXRecordsRequestType) (*ReplaceKXRecordsResponseType, error) { + response := new(ReplaceKXRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceKXRecords(request *ReplaceKXRecordsRequestType) (*ReplaceKXRecordsResponseType, error) { + return service.ReplaceKXRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceLOCRecordsContext(ctx context.Context, request *ReplaceLOCRecordsRequestType) (*ReplaceLOCRecordsResponseType, error) { + response := new(ReplaceLOCRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceLOCRecords(request *ReplaceLOCRecordsRequestType) (*ReplaceLOCRecordsResponseType, error) { + return service.ReplaceLOCRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceMXRecordsContext(ctx context.Context, request *ReplaceMXRecordsRequestType) (*ReplaceMXRecordsResponseType, error) { + response := new(ReplaceMXRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceMXRecords(request *ReplaceMXRecordsRequestType) (*ReplaceMXRecordsResponseType, error) { + return service.ReplaceMXRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceNAPTRRecordsContext(ctx context.Context, request *ReplaceNAPTRRecordsRequestType) (*ReplaceNAPTRRecordsResponseType, error) { + response := new(ReplaceNAPTRRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceNAPTRRecords(request *ReplaceNAPTRRecordsRequestType) (*ReplaceNAPTRRecordsResponseType, error) { + return service.ReplaceNAPTRRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceNSAPRecordsContext(ctx context.Context, request *ReplaceNSAPRecordsRequestType) (*ReplaceNSAPRecordsResponseType, error) { + response := new(ReplaceNSAPRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceNSAPRecords(request *ReplaceNSAPRecordsRequestType) (*ReplaceNSAPRecordsResponseType, error) { + return service.ReplaceNSAPRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplacePOLICYRecordsContext(ctx context.Context, request *ReplacePOLICYRecordsRequestType) (*ReplacePOLICYRecordsResponseType, error) { + response := new(ReplacePOLICYRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplacePOLICYRecords(request *ReplacePOLICYRecordsRequestType) (*ReplacePOLICYRecordsResponseType, error) { + return service.ReplacePOLICYRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplacePTRRecordsContext(ctx context.Context, request *ReplacePTRRecordsRequestType) (*ReplacePTRRecordsResponseType, error) { + response := new(ReplacePTRRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplacePTRRecords(request *ReplacePTRRecordsRequestType) (*ReplacePTRRecordsResponseType, error) { + return service.ReplacePTRRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplacePXRecordsContext(ctx context.Context, request *ReplacePXRecordsRequestType) (*ReplacePXRecordsResponseType, error) { + response := new(ReplacePXRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplacePXRecords(request *ReplacePXRecordsRequestType) (*ReplacePXRecordsResponseType, error) { + return service.ReplacePXRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceRPRecordsContext(ctx context.Context, request *ReplaceRPRecordsRequestType) (*ReplaceRPRecordsResponseType, error) { + response := new(ReplaceRPRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceRPRecords(request *ReplaceRPRecordsRequestType) (*ReplaceRPRecordsResponseType, error) { + return service.ReplaceRPRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceSPFRecordsContext(ctx context.Context, request *ReplaceSPFRecordsRequestType) (*ReplaceSPFRecordsResponseType, error) { + response := new(ReplaceSPFRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceSPFRecords(request *ReplaceSPFRecordsRequestType) (*ReplaceSPFRecordsResponseType, error) { + return service.ReplaceSPFRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceSRVRecordsContext(ctx context.Context, request *ReplaceSRVRecordsRequestType) (*ReplaceSRVRecordsResponseType, error) { + response := new(ReplaceSRVRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceSRVRecords(request *ReplaceSRVRecordsRequestType) (*ReplaceSRVRecordsResponseType, error) { + return service.ReplaceSRVRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceSSHFPRecordsContext(ctx context.Context, request *ReplaceSSHFPRecordsRequestType) (*ReplaceSSHFPRecordsResponseType, error) { + response := new(ReplaceSSHFPRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceSSHFPRecords(request *ReplaceSSHFPRecordsRequestType) (*ReplaceSSHFPRecordsResponseType, error) { + return service.ReplaceSSHFPRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceTLSARecordsContext(ctx context.Context, request *ReplaceTLSARecordsRequestType) (*ReplaceTLSARecordsResponseType, error) { + response := new(ReplaceTLSARecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceTLSARecords(request *ReplaceTLSARecordsRequestType) (*ReplaceTLSARecordsResponseType, error) { + return service.ReplaceTLSARecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceTXTRecordsContext(ctx context.Context, request *ReplaceTXTRecordsRequestType) (*ReplaceTXTRecordsResponseType, error) { + response := new(ReplaceTXTRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceTXTRecords(request *ReplaceTXTRecordsRequestType) (*ReplaceTXTRecordsResponseType, error) { + return service.ReplaceTXTRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) ReplaceNSRecordsContext(ctx context.Context, request *ReplaceNSRecordsRequestType) (*ReplaceNSRecordsResponseType, error) { + response := new(ReplaceNSRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ReplaceNSRecords(request *ReplaceNSRecordsRequestType) (*ReplaceNSRecordsResponseType, error) { + return service.ReplaceNSRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetANYRecordsContext(ctx context.Context, request *GetANYRecordsRequestType) (*GetANYRecordsResponseType, error) { + response := new(GetANYRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetANYRecords(request *GetANYRecordsRequestType) (*GetANYRecordsResponseType, error) { + return service.GetANYRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetAllRecordsContext(ctx context.Context, request *GetAllRecordsRequestType) (*GetAllRecordsResponseType, error) { + response := new(GetAllRecordsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetAllRecords(request *GetAllRecordsRequestType) (*GetAllRecordsResponseType, error) { + return service.GetAllRecordsContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetAllAliasQNamesContext(ctx context.Context, request *GetAllAliasQNamesRequestType) (*GetAllAliasQNamesResponseType, error) { + response := new(GetAllAliasQNamesResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetAllAliasQNames(request *GetAllAliasQNamesRequestType) (*GetAllAliasQNamesResponseType, error) { + return service.GetAllAliasQNamesContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneUserContext(ctx context.Context, request *GetOneUserRequestType) (*GetOneUserResponseType, error) { + response := new(GetOneUserResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneUser(request *GetOneUserRequestType) (*GetOneUserResponseType, error) { + return service.GetOneUserContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneUserContext(ctx context.Context, request *DeleteOneUserRequestType) (*DeleteOneUserResponseType, error) { + response := new(DeleteOneUserResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneUser(request *DeleteOneUserRequestType) (*DeleteOneUserResponseType, error) { + return service.DeleteOneUserContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateUserContext(ctx context.Context, request *CreateUserRequestType) (*CreateUserResponseType, error) { + response := new(CreateUserResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateUser(request *CreateUserRequestType) (*CreateUserResponseType, error) { + return service.CreateUserContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateUserContext(ctx context.Context, request *UpdateUserRequestType) (*UpdateUserResponseType, error) { + response := new(UpdateUserResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateUser(request *UpdateUserRequestType) (*UpdateUserResponseType, error) { + return service.UpdateUserContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetUsersContext(ctx context.Context, request *GetUsersRequestType) (*GetUsersResponseType, error) { + response := new(GetUsersResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetUsers(request *GetUsersRequestType) (*GetUsersResponseType, error) { + return service.GetUsersContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetUpdateUsersContext(ctx context.Context, request *GetUpdateUsersRequestType) (*GetUpdateUsersResponseType, error) { + response := new(GetUpdateUsersResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetUpdateUsers(request *GetUpdateUsersRequestType) (*GetUpdateUsersResponseType, error) { + return service.GetUpdateUsersContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateUpdateUserContext(ctx context.Context, request *UpdateUpdateUserRequestType) (*UpdateUpdateUserResponseType, error) { + response := new(UpdateUpdateUserResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateUpdateUser(request *UpdateUpdateUserRequestType) (*UpdateUpdateUserResponseType, error) { + return service.UpdateUpdateUserContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneUpdateUserContext(ctx context.Context, request *DeleteOneUpdateUserRequestType) (*DeleteOneUpdateUserResponseType, error) { + response := new(DeleteOneUpdateUserResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneUpdateUser(request *DeleteOneUpdateUserRequestType) (*DeleteOneUpdateUserResponseType, error) { + return service.DeleteOneUpdateUserContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateUserPasswordContext(ctx context.Context, request *UpdateUserPasswordRequestType) (*UpdateUserPasswordResponseType, error) { + response := new(UpdateUserPasswordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateUserPassword(request *UpdateUserPasswordRequestType) (*UpdateUserPasswordResponseType, error) { + return service.UpdateUserPasswordContext( + context.Background(), + request, + ) +} + +func (service *dynect) BlockUserContext(ctx context.Context, request *BlockUserRequestType) (*BlockUserResponseType, error) { + response := new(BlockUserResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) BlockUser(request *BlockUserRequestType) (*BlockUserResponseType, error) { + return service.BlockUserContext( + context.Background(), + request, + ) +} + +func (service *dynect) UnblockUserContext(ctx context.Context, request *UnblockUserRequestType) (*UnblockUserResponseType, error) { + response := new(UnblockUserResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UnblockUser(request *UnblockUserRequestType) (*UnblockUserResponseType, error) { + return service.UnblockUserContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateContactContext(ctx context.Context, request *CreateContactRequestType) (*CreateContactResponseType, error) { + response := new(CreateContactResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateContact(request *CreateContactRequestType) (*CreateContactResponseType, error) { + return service.CreateContactContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneContactContext(ctx context.Context, request *GetOneContactRequestType) (*GetOneContactResponseType, error) { + response := new(GetOneContactResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneContact(request *GetOneContactRequestType) (*GetOneContactResponseType, error) { + return service.GetOneContactContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetContactsContext(ctx context.Context, request *GetContactsRequestType) (*GetContactsResponseType, error) { + response := new(GetContactsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetContacts(request *GetContactsRequestType) (*GetContactsResponseType, error) { + return service.GetContactsContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneContactContext(ctx context.Context, request *DeleteOneContactRequestType) (*DeleteOneContactResponseType, error) { + response := new(DeleteOneContactResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneContact(request *DeleteOneContactRequestType) (*DeleteOneContactResponseType, error) { + return service.DeleteOneContactContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateContactContext(ctx context.Context, request *UpdateContactRequestType) (*UpdateContactResponseType, error) { + response := new(UpdateContactResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateContact(request *UpdateContactRequestType) (*UpdateContactResponseType, error) { + return service.UpdateContactContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateCustomerContext(ctx context.Context, request *CreateCustomerRequestType) (*CreateCustomerResponseType, error) { + response := new(CreateCustomerResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateCustomer(request *CreateCustomerRequestType) (*CreateCustomerResponseType, error) { + return service.CreateCustomerContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateCustomerContext(ctx context.Context, request *UpdateCustomerRequestType) (*UpdateCustomerResponseType, error) { + response := new(UpdateCustomerResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateCustomer(request *UpdateCustomerRequestType) (*UpdateCustomerResponseType, error) { + return service.UpdateCustomerContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneCustomerContext(ctx context.Context, request *GetOneCustomerRequestType) (*GetOneCustomerResponseType, error) { + response := new(GetOneCustomerResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneCustomer(request *GetOneCustomerRequestType) (*GetOneCustomerResponseType, error) { + return service.GetOneCustomerContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetCustomersContext(ctx context.Context, request *GetCustomersRequestType) (*GetCustomersResponseType, error) { + response := new(GetCustomersResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetCustomers(request *GetCustomersRequestType) (*GetCustomersResponseType, error) { + return service.GetCustomersContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneCustomerContext(ctx context.Context, request *DeleteOneCustomerRequestType) (*DeleteOneCustomerResponseType, error) { + response := new(DeleteOneCustomerResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneCustomer(request *DeleteOneCustomerRequestType) (*DeleteOneCustomerResponseType, error) { + return service.DeleteOneCustomerContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetCustomerPrefsContext(ctx context.Context, request *GetCustomerPrefsRequestType) (*GetCustomerPrefsResponseType, error) { + response := new(GetCustomerPrefsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetCustomerPrefs(request *GetCustomerPrefsRequestType) (*GetCustomerPrefsResponseType, error) { + return service.GetCustomerPrefsContext( + context.Background(), + request, + ) +} + +func (service *dynect) SetCustomerPrefsContext(ctx context.Context, request *SetCustomerPrefsRequestType) (*SetCustomerPrefsResponseType, error) { + response := new(SetCustomerPrefsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) SetCustomerPrefs(request *SetCustomerPrefsRequestType) (*SetCustomerPrefsResponseType, error) { + return service.SetCustomerPrefsContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetCustomerIPACLContext(ctx context.Context, request *GetCustomerIPACLRequestType) (*GetCustomerIPACLResponseType, error) { + response := new(GetCustomerIPACLResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetCustomerIPACL(request *GetCustomerIPACLRequestType) (*GetCustomerIPACLResponseType, error) { + return service.GetCustomerIPACLContext( + context.Background(), + request, + ) +} + +func (service *dynect) SetCustomerIPACLContext(ctx context.Context, request *SetCustomerIPACLRequestType) (*SetCustomerIPACLResponseType, error) { + response := new(SetCustomerIPACLResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) SetCustomerIPACL(request *SetCustomerIPACLRequestType) (*SetCustomerIPACLResponseType, error) { + return service.SetCustomerIPACLContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateCustomerOracleMetadataContext(ctx context.Context, request *CreateCustomerOracleMetadataRequestType) (*CreateCustomerOracleMetadataResponseType, error) { + response := new(CreateCustomerOracleMetadataResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateCustomerOracleMetadata(request *CreateCustomerOracleMetadataRequestType) (*CreateCustomerOracleMetadataResponseType, error) { + return service.CreateCustomerOracleMetadataContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateCustomerOracleMetadataContext(ctx context.Context, request *UpdateCustomerOracleMetadataRequestType) (*UpdateCustomerOracleMetadataResponseType, error) { + response := new(UpdateCustomerOracleMetadataResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateCustomerOracleMetadata(request *UpdateCustomerOracleMetadataRequestType) (*UpdateCustomerOracleMetadataResponseType, error) { + return service.UpdateCustomerOracleMetadataContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetCustomerOracleMetadataContext(ctx context.Context, request *GetCustomerOracleMetadataRequestType) (*GetCustomerOracleMetadataResponseType, error) { + response := new(GetCustomerOracleMetadataResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetCustomerOracleMetadata(request *GetCustomerOracleMetadataRequestType) (*GetCustomerOracleMetadataResponseType, error) { + return service.GetCustomerOracleMetadataContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteCustomerOracleMetadataContext(ctx context.Context, request *DeleteCustomerOracleMetadataRequestType) (*DeleteCustomerOracleMetadataResponseType, error) { + response := new(DeleteCustomerOracleMetadataResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteCustomerOracleMetadata(request *DeleteCustomerOracleMetadataRequestType) (*DeleteCustomerOracleMetadataResponseType, error) { + return service.DeleteCustomerOracleMetadataContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateZoneOracleMetadataContext(ctx context.Context, request *CreateZoneOracleMetadataRequestType) (*CreateZoneOracleMetadataResponseType, error) { + response := new(CreateZoneOracleMetadataResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateZoneOracleMetadata(request *CreateZoneOracleMetadataRequestType) (*CreateZoneOracleMetadataResponseType, error) { + return service.CreateZoneOracleMetadataContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateZoneOracleMetadataContext(ctx context.Context, request *UpdateZoneOracleMetadataRequestType) (*UpdateZoneOracleMetadataResponseType, error) { + response := new(UpdateZoneOracleMetadataResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateZoneOracleMetadata(request *UpdateZoneOracleMetadataRequestType) (*UpdateZoneOracleMetadataResponseType, error) { + return service.UpdateZoneOracleMetadataContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetZoneOracleMetadataContext(ctx context.Context, request *GetZoneOracleMetadataRequestType) (*GetZoneOracleMetadataResponseType, error) { + response := new(GetZoneOracleMetadataResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetZoneOracleMetadata(request *GetZoneOracleMetadataRequestType) (*GetZoneOracleMetadataResponseType, error) { + return service.GetZoneOracleMetadataContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteZoneOracleMetadataContext(ctx context.Context, request *DeleteZoneOracleMetadataRequestType) (*DeleteZoneOracleMetadataResponseType, error) { + response := new(DeleteZoneOracleMetadataResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteZoneOracleMetadata(request *DeleteZoneOracleMetadataRequestType) (*DeleteZoneOracleMetadataResponseType, error) { + return service.DeleteZoneOracleMetadataContext( + context.Background(), + request, + ) +} + +func (service *dynect) OCIMigrateContext(ctx context.Context, request *OCIMigrateRequestType) (*OCIMigrateResponseType, error) { + response := new(OCIMigrateResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) OCIMigrate(request *OCIMigrateRequestType) (*OCIMigrateResponseType, error) { + return service.OCIMigrateContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateDDNSContext(ctx context.Context, request *CreateDDNSRequestType) (*CreateDDNSResponseType, error) { + response := new(CreateDDNSResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateDDNS(request *CreateDDNSRequestType) (*CreateDDNSResponseType, error) { + return service.CreateDDNSContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneDDNSContext(ctx context.Context, request *GetOneDDNSRequestType) (*GetOneDDNSResponseType, error) { + response := new(GetOneDDNSResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneDDNS(request *GetOneDDNSRequestType) (*GetOneDDNSResponseType, error) { + return service.GetOneDDNSContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetDDNSsContext(ctx context.Context, request *GetDDNSsRequestType) (*GetDDNSsResponseType, error) { + response := new(GetDDNSsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetDDNSs(request *GetDDNSsRequestType) (*GetDDNSsResponseType, error) { + return service.GetDDNSsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateDDNSContext(ctx context.Context, request *UpdateDDNSRequestType) (*UpdateDDNSResponseType, error) { + response := new(UpdateDDNSResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateDDNS(request *UpdateDDNSRequestType) (*UpdateDDNSResponseType, error) { + return service.UpdateDDNSContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneDDNSContext(ctx context.Context, request *DeleteOneDDNSRequestType) (*DeleteOneDDNSResponseType, error) { + response := new(DeleteOneDDNSResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneDDNS(request *DeleteOneDDNSRequestType) (*DeleteOneDDNSResponseType, error) { + return service.DeleteOneDDNSContext( + context.Background(), + request, + ) +} + +func (service *dynect) ActivateDDNSContext(ctx context.Context, request *ActivateDDNSRequestType) (*ActivateDDNSResponseType, error) { + response := new(ActivateDDNSResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ActivateDDNS(request *ActivateDDNSRequestType) (*ActivateDDNSResponseType, error) { + return service.ActivateDDNSContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeactivateDDNSContext(ctx context.Context, request *DeactivateDDNSRequestType) (*DeactivateDDNSResponseType, error) { + response := new(DeactivateDDNSResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeactivateDDNS(request *DeactivateDDNSRequestType) (*DeactivateDDNSResponseType, error) { + return service.DeactivateDDNSContext( + context.Background(), + request, + ) +} + +func (service *dynect) ResetDDNSContext(ctx context.Context, request *ResetDDNSRequestType) (*ResetDDNSResponseType, error) { + response := new(ResetDDNSResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ResetDDNS(request *ResetDDNSRequestType) (*ResetDDNSResponseType, error) { + return service.ResetDDNSContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetUpdateUserPasswordContext(ctx context.Context, request *GetUpdateUserPasswordRequestType) (*GetUpdateUserPasswordResponseType, error) { + response := new(GetUpdateUserPasswordResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetUpdateUserPassword(request *GetUpdateUserPasswordRequestType) (*GetUpdateUserPasswordResponseType, error) { + return service.GetUpdateUserPasswordContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateDDNSHostContext(ctx context.Context, request *CreateDDNSHostRequestType) (*CreateDDNSHostResponseType, error) { + response := new(CreateDDNSHostResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateDDNSHost(request *CreateDDNSHostRequestType) (*CreateDDNSHostResponseType, error) { + return service.CreateDDNSHostContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateUpdateUserContext(ctx context.Context, request *CreateUpdateUserRequestType) (*CreateUpdateUserResponseType, error) { + response := new(CreateUpdateUserResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateUpdateUser(request *CreateUpdateUserRequestType) (*CreateUpdateUserResponseType, error) { + return service.CreateUpdateUserContext( + context.Background(), + request, + ) +} + +func (service *dynect) AddDDNSContext(ctx context.Context, request *AddDDNSRequestType) (*AddDDNSResponseType, error) { + response := new(AddDDNSResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) AddDDNS(request *AddDDNSRequestType) (*AddDDNSResponseType, error) { + return service.AddDDNSContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateFailoverContext(ctx context.Context, request *CreateFailoverRequestType) (*CreateFailoverResponseType, error) { + response := new(CreateFailoverResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateFailover(request *CreateFailoverRequestType) (*CreateFailoverResponseType, error) { + return service.CreateFailoverContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneFailoverContext(ctx context.Context, request *GetOneFailoverRequestType) (*GetOneFailoverResponseType, error) { + response := new(GetOneFailoverResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneFailover(request *GetOneFailoverRequestType) (*GetOneFailoverResponseType, error) { + return service.GetOneFailoverContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetFailoversContext(ctx context.Context, request *GetFailoversRequestType) (*GetFailoversResponseType, error) { + response := new(GetFailoversResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetFailovers(request *GetFailoversRequestType) (*GetFailoversResponseType, error) { + return service.GetFailoversContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateFailoverContext(ctx context.Context, request *UpdateFailoverRequestType) (*UpdateFailoverResponseType, error) { + response := new(UpdateFailoverResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateFailover(request *UpdateFailoverRequestType) (*UpdateFailoverResponseType, error) { + return service.UpdateFailoverContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneFailoverContext(ctx context.Context, request *DeleteOneFailoverRequestType) (*DeleteOneFailoverResponseType, error) { + response := new(DeleteOneFailoverResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneFailover(request *DeleteOneFailoverRequestType) (*DeleteOneFailoverResponseType, error) { + return service.DeleteOneFailoverContext( + context.Background(), + request, + ) +} + +func (service *dynect) ActivateFailoverContext(ctx context.Context, request *ActivateFailoverRequestType) (*ActivateFailoverResponseType, error) { + response := new(ActivateFailoverResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ActivateFailover(request *ActivateFailoverRequestType) (*ActivateFailoverResponseType, error) { + return service.ActivateFailoverContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeactivateFailoverContext(ctx context.Context, request *DeactivateFailoverRequestType) (*DeactivateFailoverResponseType, error) { + response := new(DeactivateFailoverResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeactivateFailover(request *DeactivateFailoverRequestType) (*DeactivateFailoverResponseType, error) { + return service.DeactivateFailoverContext( + context.Background(), + request, + ) +} + +func (service *dynect) RecoverFailoverContext(ctx context.Context, request *RecoverFailoverRequestType) (*RecoverFailoverResponseType, error) { + response := new(RecoverFailoverResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) RecoverFailover(request *RecoverFailoverRequestType) (*RecoverFailoverResponseType, error) { + return service.RecoverFailoverContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateLoadBalanceContext(ctx context.Context, request *CreateLoadBalanceRequestType) (*CreateLoadBalanceResponseType, error) { + response := new(CreateLoadBalanceResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateLoadBalance(request *CreateLoadBalanceRequestType) (*CreateLoadBalanceResponseType, error) { + return service.CreateLoadBalanceContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneLoadBalanceContext(ctx context.Context, request *GetOneLoadBalanceRequestType) (*GetOneLoadBalanceResponseType, error) { + response := new(GetOneLoadBalanceResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneLoadBalance(request *GetOneLoadBalanceRequestType) (*GetOneLoadBalanceResponseType, error) { + return service.GetOneLoadBalanceContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetLoadBalancesContext(ctx context.Context, request *GetLoadBalancesRequestType) (*GetLoadBalancesResponseType, error) { + response := new(GetLoadBalancesResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetLoadBalances(request *GetLoadBalancesRequestType) (*GetLoadBalancesResponseType, error) { + return service.GetLoadBalancesContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateLoadBalanceContext(ctx context.Context, request *UpdateLoadBalanceRequestType) (*UpdateLoadBalanceResponseType, error) { + response := new(UpdateLoadBalanceResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateLoadBalance(request *UpdateLoadBalanceRequestType) (*UpdateLoadBalanceResponseType, error) { + return service.UpdateLoadBalanceContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneLoadBalanceContext(ctx context.Context, request *DeleteOneLoadBalanceRequestType) (*DeleteOneLoadBalanceResponseType, error) { + response := new(DeleteOneLoadBalanceResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneLoadBalance(request *DeleteOneLoadBalanceRequestType) (*DeleteOneLoadBalanceResponseType, error) { + return service.DeleteOneLoadBalanceContext( + context.Background(), + request, + ) +} + +func (service *dynect) ActivateLoadBalanceContext(ctx context.Context, request *ActivateLoadBalanceRequestType) (*ActivateLoadBalanceResponseType, error) { + response := new(ActivateLoadBalanceResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ActivateLoadBalance(request *ActivateLoadBalanceRequestType) (*ActivateLoadBalanceResponseType, error) { + return service.ActivateLoadBalanceContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeactivateLoadBalanceContext(ctx context.Context, request *DeactivateLoadBalanceRequestType) (*DeactivateLoadBalanceResponseType, error) { + response := new(DeactivateLoadBalanceResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeactivateLoadBalance(request *DeactivateLoadBalanceRequestType) (*DeactivateLoadBalanceResponseType, error) { + return service.DeactivateLoadBalanceContext( + context.Background(), + request, + ) +} + +func (service *dynect) RecoverLoadBalanceContext(ctx context.Context, request *RecoverLoadBalanceRequestType) (*RecoverLoadBalanceResponseType, error) { + response := new(RecoverLoadBalanceResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) RecoverLoadBalance(request *RecoverLoadBalanceRequestType) (*RecoverLoadBalanceResponseType, error) { + return service.RecoverLoadBalanceContext( + context.Background(), + request, + ) +} + +func (service *dynect) RecoverLoadBalanceIPContext(ctx context.Context, request *RecoverLoadBalanceIPRequestType) (*RecoverLoadBalanceIPResponseType, error) { + response := new(RecoverLoadBalanceIPResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) RecoverLoadBalanceIP(request *RecoverLoadBalanceIPRequestType) (*RecoverLoadBalanceIPResponseType, error) { + return service.RecoverLoadBalanceIPContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateLoadBalancePoolEntryContext(ctx context.Context, request *CreateLoadBalancePoolEntryRequestType) (*CreateLoadBalancePoolEntryResponseType, error) { + response := new(CreateLoadBalancePoolEntryResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateLoadBalancePoolEntry(request *CreateLoadBalancePoolEntryRequestType) (*CreateLoadBalancePoolEntryResponseType, error) { + return service.CreateLoadBalancePoolEntryContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateLoadBalancePoolEntryContext(ctx context.Context, request *UpdateLoadBalancePoolEntryRequestType) (*UpdateLoadBalancePoolEntryResponseType, error) { + response := new(UpdateLoadBalancePoolEntryResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateLoadBalancePoolEntry(request *UpdateLoadBalancePoolEntryRequestType) (*UpdateLoadBalancePoolEntryResponseType, error) { + return service.UpdateLoadBalancePoolEntryContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneLoadBalancePoolEntryContext(ctx context.Context, request *GetOneLoadBalancePoolEntryRequestType) (*GetOneLoadBalancePoolEntryResponseType, error) { + response := new(GetOneLoadBalancePoolEntryResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneLoadBalancePoolEntry(request *GetOneLoadBalancePoolEntryRequestType) (*GetOneLoadBalancePoolEntryResponseType, error) { + return service.GetOneLoadBalancePoolEntryContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetLoadBalancePoolEntriesContext(ctx context.Context, request *GetLoadBalancePoolEntriesRequestType) (*GetLoadBalancePoolEntriesResponseType, error) { + response := new(GetLoadBalancePoolEntriesResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetLoadBalancePoolEntries(request *GetLoadBalancePoolEntriesRequestType) (*GetLoadBalancePoolEntriesResponseType, error) { + return service.GetLoadBalancePoolEntriesContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneLoadBalancePoolEntryContext(ctx context.Context, request *DeleteOneLoadBalancePoolEntryRequestType) (*DeleteOneLoadBalancePoolEntryResponseType, error) { + response := new(DeleteOneLoadBalancePoolEntryResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneLoadBalancePoolEntry(request *DeleteOneLoadBalancePoolEntryRequestType) (*DeleteOneLoadBalancePoolEntryResponseType, error) { + return service.DeleteOneLoadBalancePoolEntryContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateGSLBContext(ctx context.Context, request *CreateGSLBRequestType) (*CreateGSLBResponseType, error) { + response := new(CreateGSLBResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateGSLB(request *CreateGSLBRequestType) (*CreateGSLBResponseType, error) { + return service.CreateGSLBContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneGSLBContext(ctx context.Context, request *GetOneGSLBRequestType) (*GetOneGSLBResponseType, error) { + response := new(GetOneGSLBResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneGSLB(request *GetOneGSLBRequestType) (*GetOneGSLBResponseType, error) { + return service.GetOneGSLBContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetGSLBsContext(ctx context.Context, request *GetGSLBsRequestType) (*GetGSLBsResponseType, error) { + response := new(GetGSLBsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetGSLBs(request *GetGSLBsRequestType) (*GetGSLBsResponseType, error) { + return service.GetGSLBsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateGSLBContext(ctx context.Context, request *UpdateGSLBRequestType) (*UpdateGSLBResponseType, error) { + response := new(UpdateGSLBResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateGSLB(request *UpdateGSLBRequestType) (*UpdateGSLBResponseType, error) { + return service.UpdateGSLBContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneGSLBContext(ctx context.Context, request *DeleteOneGSLBRequestType) (*DeleteOneGSLBResponseType, error) { + response := new(DeleteOneGSLBResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneGSLB(request *DeleteOneGSLBRequestType) (*DeleteOneGSLBResponseType, error) { + return service.DeleteOneGSLBContext( + context.Background(), + request, + ) +} + +func (service *dynect) ActivateGSLBContext(ctx context.Context, request *ActivateGSLBRequestType) (*ActivateGSLBResponseType, error) { + response := new(ActivateGSLBResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ActivateGSLB(request *ActivateGSLBRequestType) (*ActivateGSLBResponseType, error) { + return service.ActivateGSLBContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeactivateGSLBContext(ctx context.Context, request *DeactivateGSLBRequestType) (*DeactivateGSLBResponseType, error) { + response := new(DeactivateGSLBResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeactivateGSLB(request *DeactivateGSLBRequestType) (*DeactivateGSLBResponseType, error) { + return service.DeactivateGSLBContext( + context.Background(), + request, + ) +} + +func (service *dynect) RecoverGSLBContext(ctx context.Context, request *RecoverGSLBRequestType) (*RecoverGSLBResponseType, error) { + response := new(RecoverGSLBResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) RecoverGSLB(request *RecoverGSLBRequestType) (*RecoverGSLBResponseType, error) { + return service.RecoverGSLBContext( + context.Background(), + request, + ) +} + +func (service *dynect) RecoverGSLBIPContext(ctx context.Context, request *RecoverGSLBIPRequestType) (*RecoverGSLBIPResponseType, error) { + response := new(RecoverGSLBIPResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) RecoverGSLBIP(request *RecoverGSLBIPRequestType) (*RecoverGSLBIPResponseType, error) { + return service.RecoverGSLBIPContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateGSLBRegionContext(ctx context.Context, request *CreateGSLBRegionRequestType) (*CreateGSLBRegionResponseType, error) { + response := new(CreateGSLBRegionResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateGSLBRegion(request *CreateGSLBRegionRequestType) (*CreateGSLBRegionResponseType, error) { + return service.CreateGSLBRegionContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneGSLBRegionContext(ctx context.Context, request *GetOneGSLBRegionRequestType) (*GetOneGSLBRegionResponseType, error) { + response := new(GetOneGSLBRegionResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneGSLBRegion(request *GetOneGSLBRegionRequestType) (*GetOneGSLBRegionResponseType, error) { + return service.GetOneGSLBRegionContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetGSLBRegionsContext(ctx context.Context, request *GetGSLBRegionsRequestType) (*GetGSLBRegionsResponseType, error) { + response := new(GetGSLBRegionsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetGSLBRegions(request *GetGSLBRegionsRequestType) (*GetGSLBRegionsResponseType, error) { + return service.GetGSLBRegionsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateGSLBRegionContext(ctx context.Context, request *UpdateGSLBRegionRequestType) (*UpdateGSLBRegionResponseType, error) { + response := new(UpdateGSLBRegionResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateGSLBRegion(request *UpdateGSLBRegionRequestType) (*UpdateGSLBRegionResponseType, error) { + return service.UpdateGSLBRegionContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneGSLBRegionContext(ctx context.Context, request *DeleteOneGSLBRegionRequestType) (*DeleteOneGSLBRegionResponseType, error) { + response := new(DeleteOneGSLBRegionResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneGSLBRegion(request *DeleteOneGSLBRegionRequestType) (*DeleteOneGSLBRegionResponseType, error) { + return service.DeleteOneGSLBRegionContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateGSLBRegionPoolEntryContext(ctx context.Context, request *CreateGSLBRegionPoolEntryRequestType) (*CreateGSLBRegionPoolEntryResponseType, error) { + response := new(CreateGSLBRegionPoolEntryResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateGSLBRegionPoolEntry(request *CreateGSLBRegionPoolEntryRequestType) (*CreateGSLBRegionPoolEntryResponseType, error) { + return service.CreateGSLBRegionPoolEntryContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateGSLBRegionPoolEntryContext(ctx context.Context, request *UpdateGSLBRegionPoolEntryRequestType) (*UpdateGSLBRegionPoolEntryResponseType, error) { + response := new(UpdateGSLBRegionPoolEntryResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateGSLBRegionPoolEntry(request *UpdateGSLBRegionPoolEntryRequestType) (*UpdateGSLBRegionPoolEntryResponseType, error) { + return service.UpdateGSLBRegionPoolEntryContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneGSLBRegionPoolEntryContext(ctx context.Context, request *GetOneGSLBRegionPoolEntryRequestType) (*GetOneGSLBRegionPoolEntryResponseType, error) { + response := new(GetOneGSLBRegionPoolEntryResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneGSLBRegionPoolEntry(request *GetOneGSLBRegionPoolEntryRequestType) (*GetOneGSLBRegionPoolEntryResponseType, error) { + return service.GetOneGSLBRegionPoolEntryContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetGSLBRegionPoolEntriesContext(ctx context.Context, request *GetGSLBRegionPoolEntriesRequestType) (*GetGSLBRegionPoolEntriesResponseType, error) { + response := new(GetGSLBRegionPoolEntriesResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetGSLBRegionPoolEntries(request *GetGSLBRegionPoolEntriesRequestType) (*GetGSLBRegionPoolEntriesResponseType, error) { + return service.GetGSLBRegionPoolEntriesContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneGSLBRegionPoolEntryContext(ctx context.Context, request *DeleteOneGSLBRegionPoolEntryRequestType) (*DeleteOneGSLBRegionPoolEntryResponseType, error) { + response := new(DeleteOneGSLBRegionPoolEntryResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneGSLBRegionPoolEntry(request *DeleteOneGSLBRegionPoolEntryRequestType) (*DeleteOneGSLBRegionPoolEntryResponseType, error) { + return service.DeleteOneGSLBRegionPoolEntryContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateRTTMContext(ctx context.Context, request *CreateRTTMRequestType) (*CreateRTTMResponseType, error) { + response := new(CreateRTTMResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateRTTM(request *CreateRTTMRequestType) (*CreateRTTMResponseType, error) { + return service.CreateRTTMContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneRTTMContext(ctx context.Context, request *GetOneRTTMRequestType) (*GetOneRTTMResponseType, error) { + response := new(GetOneRTTMResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneRTTM(request *GetOneRTTMRequestType) (*GetOneRTTMResponseType, error) { + return service.GetOneRTTMContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetRTTMsContext(ctx context.Context, request *GetRTTMsRequestType) (*GetRTTMsResponseType, error) { + response := new(GetRTTMsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetRTTMs(request *GetRTTMsRequestType) (*GetRTTMsResponseType, error) { + return service.GetRTTMsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateRTTMContext(ctx context.Context, request *UpdateRTTMRequestType) (*UpdateRTTMResponseType, error) { + response := new(UpdateRTTMResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateRTTM(request *UpdateRTTMRequestType) (*UpdateRTTMResponseType, error) { + return service.UpdateRTTMContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneRTTMContext(ctx context.Context, request *DeleteOneRTTMRequestType) (*DeleteOneRTTMResponseType, error) { + response := new(DeleteOneRTTMResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneRTTM(request *DeleteOneRTTMRequestType) (*DeleteOneRTTMResponseType, error) { + return service.DeleteOneRTTMContext( + context.Background(), + request, + ) +} + +func (service *dynect) ActivateRTTMContext(ctx context.Context, request *ActivateRTTMRequestType) (*ActivateRTTMResponseType, error) { + response := new(ActivateRTTMResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ActivateRTTM(request *ActivateRTTMRequestType) (*ActivateRTTMResponseType, error) { + return service.ActivateRTTMContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeactivateRTTMContext(ctx context.Context, request *DeactivateRTTMRequestType) (*DeactivateRTTMResponseType, error) { + response := new(DeactivateRTTMResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeactivateRTTM(request *DeactivateRTTMRequestType) (*DeactivateRTTMResponseType, error) { + return service.DeactivateRTTMContext( + context.Background(), + request, + ) +} + +func (service *dynect) RecoverRTTMContext(ctx context.Context, request *RecoverRTTMRequestType) (*RecoverRTTMResponseType, error) { + response := new(RecoverRTTMResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) RecoverRTTM(request *RecoverRTTMRequestType) (*RecoverRTTMResponseType, error) { + return service.RecoverRTTMContext( + context.Background(), + request, + ) +} + +func (service *dynect) RecoverRTTMIPContext(ctx context.Context, request *RecoverRTTMIPRequestType) (*RecoverRTTMIPResponseType, error) { + response := new(RecoverRTTMIPResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) RecoverRTTMIP(request *RecoverRTTMIPRequestType) (*RecoverRTTMIPResponseType, error) { + return service.RecoverRTTMIPContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetRTTMLogsContext(ctx context.Context, request *GetRTTMLogsRequestType) (*GetRTTMLogsResponseType, error) { + response := new(GetRTTMLogsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetRTTMLogs(request *GetRTTMLogsRequestType) (*GetRTTMLogsResponseType, error) { + return service.GetRTTMLogsContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetRTTMRRSetsContext(ctx context.Context, request *GetRTTMRRSetsRequestType) (*GetRTTMRRSetsResponseType, error) { + response := new(GetRTTMRRSetsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetRTTMRRSets(request *GetRTTMRRSetsRequestType) (*GetRTTMRRSetsResponseType, error) { + return service.GetRTTMRRSetsContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateRTTMRegionContext(ctx context.Context, request *CreateRTTMRegionRequestType) (*CreateRTTMRegionResponseType, error) { + response := new(CreateRTTMRegionResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateRTTMRegion(request *CreateRTTMRegionRequestType) (*CreateRTTMRegionResponseType, error) { + return service.CreateRTTMRegionContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneRTTMRegionContext(ctx context.Context, request *GetOneRTTMRegionRequestType) (*GetOneRTTMRegionResponseType, error) { + response := new(GetOneRTTMRegionResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneRTTMRegion(request *GetOneRTTMRegionRequestType) (*GetOneRTTMRegionResponseType, error) { + return service.GetOneRTTMRegionContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetRTTMRegionsContext(ctx context.Context, request *GetRTTMRegionsRequestType) (*GetRTTMRegionsResponseType, error) { + response := new(GetRTTMRegionsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetRTTMRegions(request *GetRTTMRegionsRequestType) (*GetRTTMRegionsResponseType, error) { + return service.GetRTTMRegionsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateRTTMRegionContext(ctx context.Context, request *UpdateRTTMRegionRequestType) (*UpdateRTTMRegionResponseType, error) { + response := new(UpdateRTTMRegionResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateRTTMRegion(request *UpdateRTTMRegionRequestType) (*UpdateRTTMRegionResponseType, error) { + return service.UpdateRTTMRegionContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneRTTMRegionContext(ctx context.Context, request *DeleteOneRTTMRegionRequestType) (*DeleteOneRTTMRegionResponseType, error) { + response := new(DeleteOneRTTMRegionResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneRTTMRegion(request *DeleteOneRTTMRegionRequestType) (*DeleteOneRTTMRegionResponseType, error) { + return service.DeleteOneRTTMRegionContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateRTTMRegionPoolEntryContext(ctx context.Context, request *CreateRTTMRegionPoolEntryRequestType) (*CreateRTTMRegionPoolEntryResponseType, error) { + response := new(CreateRTTMRegionPoolEntryResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateRTTMRegionPoolEntry(request *CreateRTTMRegionPoolEntryRequestType) (*CreateRTTMRegionPoolEntryResponseType, error) { + return service.CreateRTTMRegionPoolEntryContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateRTTMRegionPoolEntryContext(ctx context.Context, request *UpdateRTTMRegionPoolEntryRequestType) (*UpdateRTTMRegionPoolEntryResponseType, error) { + response := new(UpdateRTTMRegionPoolEntryResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateRTTMRegionPoolEntry(request *UpdateRTTMRegionPoolEntryRequestType) (*UpdateRTTMRegionPoolEntryResponseType, error) { + return service.UpdateRTTMRegionPoolEntryContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneRTTMRegionPoolEntryContext(ctx context.Context, request *GetOneRTTMRegionPoolEntryRequestType) (*GetOneRTTMRegionPoolEntryResponseType, error) { + response := new(GetOneRTTMRegionPoolEntryResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneRTTMRegionPoolEntry(request *GetOneRTTMRegionPoolEntryRequestType) (*GetOneRTTMRegionPoolEntryResponseType, error) { + return service.GetOneRTTMRegionPoolEntryContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetRTTMRegionPoolEntriesContext(ctx context.Context, request *GetRTTMRegionPoolEntriesRequestType) (*GetRTTMRegionPoolEntriesResponseType, error) { + response := new(GetRTTMRegionPoolEntriesResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetRTTMRegionPoolEntries(request *GetRTTMRegionPoolEntriesRequestType) (*GetRTTMRegionPoolEntriesResponseType, error) { + return service.GetRTTMRegionPoolEntriesContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneRTTMRegionPoolEntryContext(ctx context.Context, request *DeleteOneRTTMRegionPoolEntryRequestType) (*DeleteOneRTTMRegionPoolEntryResponseType, error) { + response := new(DeleteOneRTTMRegionPoolEntryResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneRTTMRegionPoolEntry(request *DeleteOneRTTMRegionPoolEntryRequestType) (*DeleteOneRTTMRegionPoolEntryResponseType, error) { + return service.DeleteOneRTTMRegionPoolEntryContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateHTTPRedirectContext(ctx context.Context, request *CreateHTTPRedirectRequestType) (*CreateHTTPRedirectResponseType, error) { + response := new(CreateHTTPRedirectResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateHTTPRedirect(request *CreateHTTPRedirectRequestType) (*CreateHTTPRedirectResponseType, error) { + return service.CreateHTTPRedirectContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneHTTPRedirectContext(ctx context.Context, request *GetOneHTTPRedirectRequestType) (*GetOneHTTPRedirectResponseType, error) { + response := new(GetOneHTTPRedirectResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneHTTPRedirect(request *GetOneHTTPRedirectRequestType) (*GetOneHTTPRedirectResponseType, error) { + return service.GetOneHTTPRedirectContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetHTTPRedirectsContext(ctx context.Context, request *GetHTTPRedirectsRequestType) (*GetHTTPRedirectsResponseType, error) { + response := new(GetHTTPRedirectsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetHTTPRedirects(request *GetHTTPRedirectsRequestType) (*GetHTTPRedirectsResponseType, error) { + return service.GetHTTPRedirectsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateHTTPRedirectContext(ctx context.Context, request *UpdateHTTPRedirectRequestType) (*UpdateHTTPRedirectResponseType, error) { + response := new(UpdateHTTPRedirectResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateHTTPRedirect(request *UpdateHTTPRedirectRequestType) (*UpdateHTTPRedirectResponseType, error) { + return service.UpdateHTTPRedirectContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneHTTPRedirectContext(ctx context.Context, request *DeleteOneHTTPRedirectRequestType) (*DeleteOneHTTPRedirectResponseType, error) { + response := new(DeleteOneHTTPRedirectResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneHTTPRedirect(request *DeleteOneHTTPRedirectRequestType) (*DeleteOneHTTPRedirectResponseType, error) { + return service.DeleteOneHTTPRedirectContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateAdvRedirectRuleContext(ctx context.Context, request *CreateAdvRedirectRuleRequestType) (*CreateAdvRedirectRuleResponseType, error) { + response := new(CreateAdvRedirectRuleResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateAdvRedirectRule(request *CreateAdvRedirectRuleRequestType) (*CreateAdvRedirectRuleResponseType, error) { + return service.CreateAdvRedirectRuleContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateAdvRedirectRuleContext(ctx context.Context, request *UpdateAdvRedirectRuleRequestType) (*UpdateAdvRedirectRuleResponseType, error) { + response := new(UpdateAdvRedirectRuleResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateAdvRedirectRule(request *UpdateAdvRedirectRuleRequestType) (*UpdateAdvRedirectRuleResponseType, error) { + return service.UpdateAdvRedirectRuleContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneAdvRedirectRuleContext(ctx context.Context, request *GetOneAdvRedirectRuleRequestType) (*GetOneAdvRedirectRuleResponseType, error) { + response := new(GetOneAdvRedirectRuleResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneAdvRedirectRule(request *GetOneAdvRedirectRuleRequestType) (*GetOneAdvRedirectRuleResponseType, error) { + return service.GetOneAdvRedirectRuleContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetAdvRedirectRulesContext(ctx context.Context, request *GetAdvRedirectRulesRequestType) (*GetAdvRedirectRulesResponseType, error) { + response := new(GetAdvRedirectRulesResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetAdvRedirectRules(request *GetAdvRedirectRulesRequestType) (*GetAdvRedirectRulesResponseType, error) { + return service.GetAdvRedirectRulesContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneAdvRedirectRuleContext(ctx context.Context, request *DeleteOneAdvRedirectRuleRequestType) (*DeleteOneAdvRedirectRuleResponseType, error) { + response := new(DeleteOneAdvRedirectRuleResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneAdvRedirectRule(request *DeleteOneAdvRedirectRuleRequestType) (*DeleteOneAdvRedirectRuleResponseType, error) { + return service.DeleteOneAdvRedirectRuleContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateAdvRedirectContext(ctx context.Context, request *CreateAdvRedirectRequestType) (*CreateAdvRedirectResponseType, error) { + response := new(CreateAdvRedirectResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateAdvRedirect(request *CreateAdvRedirectRequestType) (*CreateAdvRedirectResponseType, error) { + return service.CreateAdvRedirectContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneAdvRedirectContext(ctx context.Context, request *GetOneAdvRedirectRequestType) (*GetOneAdvRedirectResponseType, error) { + response := new(GetOneAdvRedirectResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneAdvRedirect(request *GetOneAdvRedirectRequestType) (*GetOneAdvRedirectResponseType, error) { + return service.GetOneAdvRedirectContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetAdvRedirectsContext(ctx context.Context, request *GetAdvRedirectsRequestType) (*GetAdvRedirectsResponseType, error) { + response := new(GetAdvRedirectsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetAdvRedirects(request *GetAdvRedirectsRequestType) (*GetAdvRedirectsResponseType, error) { + return service.GetAdvRedirectsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateAdvRedirectContext(ctx context.Context, request *UpdateAdvRedirectRequestType) (*UpdateAdvRedirectResponseType, error) { + response := new(UpdateAdvRedirectResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateAdvRedirect(request *UpdateAdvRedirectRequestType) (*UpdateAdvRedirectResponseType, error) { + return service.UpdateAdvRedirectContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneAdvRedirectContext(ctx context.Context, request *DeleteOneAdvRedirectRequestType) (*DeleteOneAdvRedirectResponseType, error) { + response := new(DeleteOneAdvRedirectResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneAdvRedirect(request *DeleteOneAdvRedirectRequestType) (*DeleteOneAdvRedirectResponseType, error) { + return service.DeleteOneAdvRedirectContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetNodeListContext(ctx context.Context, request *GetNodeListRequestType) (*GetNodeListResponseType, error) { + response := new(GetNodeListResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetNodeList(request *GetNodeListRequestType) (*GetNodeListResponseType, error) { + return service.GetNodeListContext( + context.Background(), + request, + ) +} + +func (service *dynect) PublishZoneContext(ctx context.Context, request *PublishZoneRequestType) (*PublishZoneResponseType, error) { + response := new(PublishZoneResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) PublishZone(request *PublishZoneRequestType) (*PublishZoneResponseType, error) { + return service.PublishZoneContext( + context.Background(), + request, + ) +} + +func (service *dynect) PruneZoneContext(ctx context.Context, request *PruneZoneRequestType) (*PruneZoneResponseType, error) { + response := new(PruneZoneResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) PruneZone(request *PruneZoneRequestType) (*PruneZoneResponseType, error) { + return service.PruneZoneContext( + context.Background(), + request, + ) +} + +func (service *dynect) FreezeZoneContext(ctx context.Context, request *FreezeZoneRequestType) (*FreezeZoneResponseType, error) { + response := new(FreezeZoneResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) FreezeZone(request *FreezeZoneRequestType) (*FreezeZoneResponseType, error) { + return service.FreezeZoneContext( + context.Background(), + request, + ) +} + +func (service *dynect) ThawZoneContext(ctx context.Context, request *ThawZoneRequestType) (*ThawZoneResponseType, error) { + response := new(ThawZoneResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ThawZone(request *ThawZoneRequestType) (*ThawZoneResponseType, error) { + return service.ThawZoneContext( + context.Background(), + request, + ) +} + +func (service *dynect) RestoreZoneContext(ctx context.Context, request *RestoreZoneRequestType) (*RestoreZoneResponseType, error) { + response := new(RestoreZoneResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) RestoreZone(request *RestoreZoneRequestType) (*RestoreZoneResponseType, error) { + return service.RestoreZoneContext( + context.Background(), + request, + ) +} + +func (service *dynect) BlockZoneContext(ctx context.Context, request *BlockZoneRequestType) (*BlockZoneResponseType, error) { + response := new(BlockZoneResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) BlockZone(request *BlockZoneRequestType) (*BlockZoneResponseType, error) { + return service.BlockZoneContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteZoneChangesetContext(ctx context.Context, request *DeleteZoneChangesetRequestType) (*DeleteZoneChangesetResponseType, error) { + response := new(DeleteZoneChangesetResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteZoneChangeset(request *DeleteZoneChangesetRequestType) (*DeleteZoneChangesetResponseType, error) { + return service.DeleteZoneChangesetContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetZoneChangesetContext(ctx context.Context, request *GetZoneChangesetRequestType) (*GetZoneChangesetResponseType, error) { + response := new(GetZoneChangesetResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetZoneChangeset(request *GetZoneChangesetRequestType) (*GetZoneChangesetResponseType, error) { + return service.GetZoneChangesetContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetZoneNotesContext(ctx context.Context, request *GetZoneNotesRequestType) (*GetZoneNotesResponseType, error) { + response := new(GetZoneNotesResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetZoneNotes(request *GetZoneNotesRequestType) (*GetZoneNotesResponseType, error) { + return service.GetZoneNotesContext( + context.Background(), + request, + ) +} + +func (service *dynect) UploadZoneFileContext(ctx context.Context, request *UploadZoneFileRequestType) (*UploadZoneFileResponseType, error) { + response := new(UploadZoneFileResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UploadZoneFile(request *UploadZoneFileRequestType) (*UploadZoneFileResponseType, error) { + return service.UploadZoneFileContext( + context.Background(), + request, + ) +} + +func (service *dynect) TransferZoneInContext(ctx context.Context, request *TransferZoneInRequestType) (*TransferZoneInResponseType, error) { + response := new(TransferZoneInResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) TransferZoneIn(request *TransferZoneInRequestType) (*TransferZoneInResponseType, error) { + return service.TransferZoneInContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetTransferStatusContext(ctx context.Context, request *GetTransferStatusRequestType) (*GetTransferStatusResponseType, error) { + response := new(GetTransferStatusResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetTransferStatus(request *GetTransferStatusRequestType) (*GetTransferStatusResponseType, error) { + return service.GetTransferStatusContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetZoneConfigOptionsContext(ctx context.Context, request *GetZoneConfigOptionsRequestType) (*GetZoneConfigOptionsResponseType, error) { + response := new(GetZoneConfigOptionsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetZoneConfigOptions(request *GetZoneConfigOptionsRequestType) (*GetZoneConfigOptionsResponseType, error) { + return service.GetZoneConfigOptionsContext( + context.Background(), + request, + ) +} + +func (service *dynect) SetZoneConfigOptionsContext(ctx context.Context, request *SetZoneConfigOptionsRequestType) (*SetZoneConfigOptionsResponseType, error) { + response := new(SetZoneConfigOptionsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) SetZoneConfigOptions(request *SetZoneConfigOptionsRequestType) (*SetZoneConfigOptionsResponseType, error) { + return service.SetZoneConfigOptionsContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateIPTrackContext(ctx context.Context, request *CreateIPTrackRequestType) (*CreateIPTrackResponseType, error) { + response := new(CreateIPTrackResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateIPTrack(request *CreateIPTrackRequestType) (*CreateIPTrackResponseType, error) { + return service.CreateIPTrackContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneIPTrackContext(ctx context.Context, request *GetOneIPTrackRequestType) (*GetOneIPTrackResponseType, error) { + response := new(GetOneIPTrackResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneIPTrack(request *GetOneIPTrackRequestType) (*GetOneIPTrackResponseType, error) { + return service.GetOneIPTrackContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetIPTracksContext(ctx context.Context, request *GetIPTracksRequestType) (*GetIPTracksResponseType, error) { + response := new(GetIPTracksResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetIPTracks(request *GetIPTracksRequestType) (*GetIPTracksResponseType, error) { + return service.GetIPTracksContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateIPTrackContext(ctx context.Context, request *UpdateIPTrackRequestType) (*UpdateIPTrackResponseType, error) { + response := new(UpdateIPTrackResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateIPTrack(request *UpdateIPTrackRequestType) (*UpdateIPTrackResponseType, error) { + return service.UpdateIPTrackContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneIPTrackContext(ctx context.Context, request *DeleteOneIPTrackRequestType) (*DeleteOneIPTrackResponseType, error) { + response := new(DeleteOneIPTrackResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneIPTrack(request *DeleteOneIPTrackRequestType) (*DeleteOneIPTrackResponseType, error) { + return service.DeleteOneIPTrackContext( + context.Background(), + request, + ) +} + +func (service *dynect) ActivateIPTrackContext(ctx context.Context, request *ActivateIPTrackRequestType) (*ActivateIPTrackResponseType, error) { + response := new(ActivateIPTrackResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ActivateIPTrack(request *ActivateIPTrackRequestType) (*ActivateIPTrackResponseType, error) { + return service.ActivateIPTrackContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeactivateIPTrackContext(ctx context.Context, request *DeactivateIPTrackRequestType) (*DeactivateIPTrackResponseType, error) { + response := new(DeactivateIPTrackResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeactivateIPTrack(request *DeactivateIPTrackRequestType) (*DeactivateIPTrackResponseType, error) { + return service.DeactivateIPTrackContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateDNSSECContext(ctx context.Context, request *CreateDNSSECRequestType) (*CreateDNSSECResponseType, error) { + response := new(CreateDNSSECResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateDNSSEC(request *CreateDNSSECRequestType) (*CreateDNSSECResponseType, error) { + return service.CreateDNSSECContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneDNSSECContext(ctx context.Context, request *GetOneDNSSECRequestType) (*GetOneDNSSECResponseType, error) { + response := new(GetOneDNSSECResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneDNSSEC(request *GetOneDNSSECRequestType) (*GetOneDNSSECResponseType, error) { + return service.GetOneDNSSECContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetDNSSECsContext(ctx context.Context, request *GetDNSSECsRequestType) (*GetDNSSECsResponseType, error) { + response := new(GetDNSSECsResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetDNSSECs(request *GetDNSSECsRequestType) (*GetDNSSECsResponseType, error) { + return service.GetDNSSECsContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateDNSSECContext(ctx context.Context, request *UpdateDNSSECRequestType) (*UpdateDNSSECResponseType, error) { + response := new(UpdateDNSSECResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateDNSSEC(request *UpdateDNSSECRequestType) (*UpdateDNSSECResponseType, error) { + return service.UpdateDNSSECContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneDNSSECContext(ctx context.Context, request *DeleteOneDNSSECRequestType) (*DeleteOneDNSSECResponseType, error) { + response := new(DeleteOneDNSSECResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneDNSSEC(request *DeleteOneDNSSECRequestType) (*DeleteOneDNSSECResponseType, error) { + return service.DeleteOneDNSSECContext( + context.Background(), + request, + ) +} + +func (service *dynect) ActivateDNSSECContext(ctx context.Context, request *ActivateDNSSECRequestType) (*ActivateDNSSECResponseType, error) { + response := new(ActivateDNSSECResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) ActivateDNSSEC(request *ActivateDNSSECRequestType) (*ActivateDNSSECResponseType, error) { + return service.ActivateDNSSECContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeactivateDNSSECContext(ctx context.Context, request *DeactivateDNSSECRequestType) (*DeactivateDNSSECResponseType, error) { + response := new(DeactivateDNSSECResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeactivateDNSSEC(request *DeactivateDNSSECRequestType) (*DeactivateDNSSECResponseType, error) { + return service.DeactivateDNSSECContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetDNSSECTimelineContext(ctx context.Context, request *GetDNSSECTimelineRequestType) (*GetDNSSECTimelineResponseType, error) { + response := new(GetDNSSECTimelineResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetDNSSECTimeline(request *GetDNSSECTimelineRequestType) (*GetDNSSECTimelineResponseType, error) { + return service.GetDNSSECTimelineContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetTasksContext(ctx context.Context, request *GetTasksRequestType) (*GetTasksResponseType, error) { + response := new(GetTasksResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetTasks(request *GetTasksRequestType) (*GetTasksResponseType, error) { + return service.GetTasksContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneTaskContext(ctx context.Context, request *GetOneTaskRequestType) (*GetOneTaskResponseType, error) { + response := new(GetOneTaskResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneTask(request *GetOneTaskRequestType) (*GetOneTaskResponseType, error) { + return service.GetOneTaskContext( + context.Background(), + request, + ) +} + +func (service *dynect) CancelTaskContext(ctx context.Context, request *CancelTaskRequestType) (*CancelTaskResponseType, error) { + response := new(CancelTaskResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CancelTask(request *CancelTaskRequestType) (*CancelTaskResponseType, error) { + return service.CancelTaskContext( + context.Background(), + request, + ) +} + +func (service *dynect) CreateExtNameserverContext(ctx context.Context, request *CreateExtNameserverRequestType) (*CreateExtNameserverResponseType, error) { + response := new(CreateExtNameserverResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) CreateExtNameserver(request *CreateExtNameserverRequestType) (*CreateExtNameserverResponseType, error) { + return service.CreateExtNameserverContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetOneExtNameserverContext(ctx context.Context, request *GetOneExtNameserverRequestType) (*GetOneExtNameserverResponseType, error) { + response := new(GetOneExtNameserverResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetOneExtNameserver(request *GetOneExtNameserverRequestType) (*GetOneExtNameserverResponseType, error) { + return service.GetOneExtNameserverContext( + context.Background(), + request, + ) +} + +func (service *dynect) GetExtNameserversContext(ctx context.Context, request *GetExtNameserversRequestType) (*GetExtNameserversResponseType, error) { + response := new(GetExtNameserversResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) GetExtNameservers(request *GetExtNameserversRequestType) (*GetExtNameserversResponseType, error) { + return service.GetExtNameserversContext( + context.Background(), + request, + ) +} + +func (service *dynect) UpdateExtNameserverContext(ctx context.Context, request *UpdateExtNameserverRequestType) (*UpdateExtNameserverResponseType, error) { + response := new(UpdateExtNameserverResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) UpdateExtNameserver(request *UpdateExtNameserverRequestType) (*UpdateExtNameserverResponseType, error) { + return service.UpdateExtNameserverContext( + context.Background(), + request, + ) +} + +func (service *dynect) DeleteOneExtNameserverContext(ctx context.Context, request *DeleteOneExtNameserverRequestType) (*DeleteOneExtNameserverResponseType, error) { + response := new(DeleteOneExtNameserverResponseType) + err := service.client.CallContext(ctx, "https://api2.dynect.net/SOAP/", request, response) + if err != nil { + return nil, err + } + + return response, nil +} + +func (service *dynect) DeleteOneExtNameserver(request *DeleteOneExtNameserverRequestType) (*DeleteOneExtNameserverResponseType, error) { + return service.DeleteOneExtNameserverContext( + context.Background(), + request, + ) +} From 6b8035e0adb29c39ea22c69927d2bbc0e4588f88 Mon Sep 17 00:00:00 2001 From: Thibault Jamet Date: Fri, 12 Mar 2021 09:35:11 +0100 Subject: [PATCH 073/175] Increase AWS pagination size From measurements, AWS by default has pagination of 100 items per page when listing hosted zone resources. This increases the number of requests required to list all our zones, and pushes a hard constraint on the rate limits. From the experiments, it seems that on the server-side, there is a hard limit of 300 elements per page, as per AWS documentation: https://docs.aws.amazon.com/Route53/latest/APIReference/API_ListResourceRecordSets.html > ListResourceRecordSets returns up to 300 resource record sets at a time in ASCII order, > beginning at a position specified by the name and type elements Hence raising the page size from 100 to 300 items would decrease by 3 the number of requests posted to Route53 We even set a higher limit so we can benefit from a lower number of requests if ever AWS increases the hard limit of 300. --- provider/aws/aws.go | 7 +++++++ provider/aws/aws_test.go | 9 +++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/provider/aws/aws.go b/provider/aws/aws.go index 2581af2a1..425bd654c 100644 --- a/provider/aws/aws.go +++ b/provider/aws/aws.go @@ -376,6 +376,13 @@ func (p *AWSProvider) records(ctx context.Context, zones map[string]*route53.Hos for _, z := range zones { params := &route53.ListResourceRecordSetsInput{ HostedZoneId: z.Id, + // From the experiments, it seems that the default MaxItems applied is 100, + // and that, on the server side, there is a hard limit of 300 elements per page. + // After a discussion with AWS representants, clients should accept + // when less items are returned, and still paginate accordingly. + // As we are using the standard AWS client, this should already be compliant. + // Hence, ifever AWS decides to raise this limit, we will automatically reduce the pressure on rate limits + MaxItems: aws.String("1000"), } if err := p.client.ListResourceRecordSetsPagesWithContext(ctx, params, f); err != nil { diff --git a/provider/aws/aws_test.go b/provider/aws/aws_test.go index 40e522a49..09259c3de 100644 --- a/provider/aws/aws_test.go +++ b/provider/aws/aws_test.go @@ -56,6 +56,7 @@ type Route53APIStub struct { recordSets map[string]map[string][]*route53.ResourceRecordSet zoneTags map[string][]*route53.Tag m dynamicMock + t *testing.T } // MockMethod starts a description of an expectation of the specified method @@ -67,16 +68,19 @@ func (r *Route53APIStub) MockMethod(method string, args ...interface{}) *mock.Ca } // NewRoute53APIStub returns an initialized Route53APIStub -func NewRoute53APIStub() *Route53APIStub { +func NewRoute53APIStub(t *testing.T) *Route53APIStub { return &Route53APIStub{ zones: make(map[string]*route53.HostedZone), recordSets: make(map[string]map[string][]*route53.ResourceRecordSet), zoneTags: make(map[string][]*route53.Tag), + t: t, } } func (r *Route53APIStub) ListResourceRecordSetsPagesWithContext(ctx context.Context, input *route53.ListResourceRecordSetsInput, fn func(p *route53.ListResourceRecordSetsOutput, lastPage bool) (shouldContinue bool), opts ...request.Option) error { output := route53.ListResourceRecordSetsOutput{} // TODO: Support optional input args. + require.NotNil(r.t, input.MaxItems) + assert.EqualValues(r.t, "1000", *input.MaxItems) if len(r.recordSets) == 0 { output.ResourceRecordSets = []*route53.ResourceRecordSet{} } else if _, ok := r.recordSets[aws.StringValue(input.HostedZoneId)]; !ok { @@ -1198,6 +1202,7 @@ func listAWSRecords(t *testing.T, client Route53API, zone string) []*route53.Res recordSets := []*route53.ResourceRecordSet{} require.NoError(t, client.ListResourceRecordSetsPagesWithContext(context.Background(), &route53.ListResourceRecordSetsInput{ HostedZoneId: aws.String(zone), + MaxItems: aws.String("1000"), }, func(resp *route53.ListResourceRecordSetsOutput, _ bool) bool { recordSets = append(recordSets, resp.ResourceRecordSets...) return true @@ -1255,7 +1260,7 @@ func newAWSProvider(t *testing.T, domainFilter endpoint.DomainFilter, zoneIDFilt } func newAWSProviderWithTagFilter(t *testing.T, domainFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, zoneTypeFilter provider.ZoneTypeFilter, zoneTagFilter provider.ZoneTagFilter, evaluateTargetHealth, dryRun bool, records []*endpoint.Endpoint) (*AWSProvider, *Route53APIStub) { - client := NewRoute53APIStub() + client := NewRoute53APIStub(t) provider := &AWSProvider{ client: client, From ac01d16c89d0a1ba119131a9c746dbd96fe6fbed Mon Sep 17 00:00:00 2001 From: Thomas Stig Jacobsen Date: Fri, 12 Mar 2021 15:44:05 +0100 Subject: [PATCH 074/175] Another bump to 1.16.2 --- .github/workflows/ci.yml | 2 +- Dockerfile | 2 +- Dockerfile.mini | 2 +- docs/contributing/getting-started.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f7d8114c6..9a1ce1a31 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: - name: Set up Go 1.x uses: actions/setup-go@v2 with: - go-version: ^1.16.1 + go-version: ^1.16.2 id: go - name: Check out code into the Go module directory diff --git a/Dockerfile b/Dockerfile index 31611d8d6..a4b0932de 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,7 @@ # builder image ARG ARCH -FROM golang:1.16.1 as builder +FROM golang:1.16.2 as builder ARG ARCH WORKDIR /sigs.k8s.io/external-dns diff --git a/Dockerfile.mini b/Dockerfile.mini index c7122fcaf..6c5f41933 100644 --- a/Dockerfile.mini +++ b/Dockerfile.mini @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM golang:1.16.1 as builder +FROM golang:1.16.2 as builder WORKDIR /sigs.k8s.io/external-dns diff --git a/docs/contributing/getting-started.md b/docs/contributing/getting-started.md index 2fd7222c1..be4a89f97 100644 --- a/docs/contributing/getting-started.md +++ b/docs/contributing/getting-started.md @@ -1,7 +1,7 @@ # Quick Start - [Git](https://git-scm.com/downloads) -- [Go 1.16.1+](https://golang.org/dl/) +- [Go 1.16.2+](https://golang.org/dl/) - [Go modules](https://github.com/golang/go/wiki/Modules) - [golangci-lint](https://github.com/golangci/golangci-lint) - [Docker](https://docs.docker.com/install/) From 2476b3bbe10c27a5661381f094c6fbc58e7fa5bf Mon Sep 17 00:00:00 2001 From: Morre Date: Sat, 13 Mar 2021 00:41:23 +0100 Subject: [PATCH 075/175] remove outdated provider list from FAQ, link to list in README --- docs/faq.md | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/docs/faq.md b/docs/faq.md index b53c24995..db309b385 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -28,24 +28,7 @@ ExternalDNS can solve this for you as well. ### Which DNS providers are supported? -Currently, the following providers are supported: - -- Google Cloud DNS -- AWS Route 53 -- AzureDNS -- CloudFlare -- DigitalOcean -- DNSimple -- Infoblox -- Dyn -- OpenStack Designate -- PowerDNS -- CoreDNS -- Exoscale -- Oracle Cloud Infrastructure DNS -- Linode DNS -- RFC2136 -- TransIP +Please check the [provider status table](https://github.com/kubernetes-sigs/external-dns#status-of-providers) for the list of supported providers and their status. As stated in the README, we are currently looking for stable maintainers for those providers, to ensure that bugfixes and new features will be available for all of those. @@ -279,11 +262,11 @@ If you need to filter only one specific source you have to run a separated exter ### How do I specify that I want the DNS record to point to either the Node's public or private IP when it has both? -If your Nodes have both public and private IP addresses, you might want to write DNS records with one or the other. +If your Nodes have both public and private IP addresses, you might want to write DNS records with one or the other. For example, you may want to write a DNS record in a private zone that resolves to your Nodes' private IPs so that traffic never leaves your private network. -To accomplish this, set this annotation on your service: `external-dns.alpha.kubernetes.io/access=private` -Conversely, to force the public IP: `external-dns.alpha.kubernetes.io/access=public` +To accomplish this, set this annotation on your service: `external-dns.alpha.kubernetes.io/access=private` +Conversely, to force the public IP: `external-dns.alpha.kubernetes.io/access=public` If this annotation is not set, and the node has both public and private IP addresses, then the public IP will be used by default. From e1cf5f88a79bda93ca6416f4d876b7d3c04d9d87 Mon Sep 17 00:00:00 2001 From: Kundan Kumar Date: Tue, 16 Mar 2021 12:42:30 +0530 Subject: [PATCH 076/175] updated ingress apiVersion --- docs/tutorials/alibabacloud.md | 2 +- docs/tutorials/aws.md | 2 +- docs/tutorials/azure-private-dns.md | 2 +- docs/tutorials/azure.md | 2 +- docs/tutorials/coredns.md | 2 +- docs/tutorials/dyn.md | 2 +- docs/tutorials/exoscale.md | 2 +- docs/tutorials/gke.md | 4 ++-- docs/tutorials/kube-ingress-aws.md | 8 ++++---- docs/tutorials/nginx-ingress.md | 4 ++-- docs/tutorials/public-private-route53.md | 8 ++++---- docs/tutorials/rdns.md | 2 +- docs/tutorials/rfc2136.md | 2 +- 13 files changed, 21 insertions(+), 21 deletions(-) diff --git a/docs/tutorials/alibabacloud.md b/docs/tutorials/alibabacloud.md index cbe774572..de9ad9365 100644 --- a/docs/tutorials/alibabacloud.md +++ b/docs/tutorials/alibabacloud.md @@ -229,7 +229,7 @@ Create an ingress resource manifest file. > For ingress objects ExternalDNS will create a DNS record based on the host specified for the ingress object. ```yaml -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: foo diff --git a/docs/tutorials/aws.md b/docs/tutorials/aws.md index 648e3c290..3d9d7ea51 100644 --- a/docs/tutorials/aws.md +++ b/docs/tutorials/aws.md @@ -253,7 +253,7 @@ Create an ingress resource manifest file. > For ingress objects ExternalDNS will create a DNS record based on the host specified for the ingress object. ```yaml -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: foo diff --git a/docs/tutorials/azure-private-dns.md b/docs/tutorials/azure-private-dns.md index 43f4ac734..ea7cfb8de 100644 --- a/docs/tutorials/azure-private-dns.md +++ b/docs/tutorials/azure-private-dns.md @@ -375,7 +375,7 @@ spec: type: ClusterIP --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx diff --git a/docs/tutorials/azure.md b/docs/tutorials/azure.md index fd925d154..102699bfc 100644 --- a/docs/tutorials/azure.md +++ b/docs/tutorials/azure.md @@ -392,7 +392,7 @@ spec: type: ClusterIP --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx diff --git a/docs/tutorials/coredns.md b/docs/tutorials/coredns.md index b9c1282ca..b07edd930 100644 --- a/docs/tutorials/coredns.md +++ b/docs/tutorials/coredns.md @@ -194,7 +194,7 @@ minikube addons enable ingress ## Testing ingress example ``` $ cat ingress.yaml -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx diff --git a/docs/tutorials/dyn.md b/docs/tutorials/dyn.md index fcee842f2..18fb7bbd8 100644 --- a/docs/tutorials/dyn.md +++ b/docs/tutorials/dyn.md @@ -111,7 +111,7 @@ Having `--dry-run=true` and `--log-level=debug` is a great way to see _exactly_ Create a file called 'test-ingress.yaml' with the following contents: ```yaml -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: test-ingress diff --git a/docs/tutorials/exoscale.md b/docs/tutorials/exoscale.md index d3d8e92d4..faf8b70eb 100644 --- a/docs/tutorials/exoscale.md +++ b/docs/tutorials/exoscale.md @@ -104,7 +104,7 @@ subjects: Spin up a simple nginx HTTP server with the following spec (`kubectl apply -f`): ```yaml -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx diff --git a/docs/tutorials/gke.md b/docs/tutorials/gke.md index 7e978cb8b..a573f9d51 100644 --- a/docs/tutorials/gke.md +++ b/docs/tutorials/gke.md @@ -211,7 +211,7 @@ $ curl nginx.external-dns-test.gcp.zalan.do Let's check that Ingress works as well. Create the following Ingress. ```yaml -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx @@ -460,7 +460,7 @@ $ kubectl annotate serviceaccount --namespace=external-dns external-dns \ Create the following sample application to test that ExternalDNS works. ```yaml -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx diff --git a/docs/tutorials/kube-ingress-aws.md b/docs/tutorials/kube-ingress-aws.md index 99cd07714..df63e9829 100644 --- a/docs/tutorials/kube-ingress-aws.md +++ b/docs/tutorials/kube-ingress-aws.md @@ -138,7 +138,7 @@ default. Create the following Ingress to expose the echoserver application to the Internet. ```yaml -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: @@ -172,7 +172,7 @@ this Ingress object will only be fronting one backend Service, we might instead create the following: ```yaml -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: @@ -205,7 +205,7 @@ and one AAAA record) for each hostname associated with the Ingress object. Example: ```yaml -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: @@ -239,7 +239,7 @@ set to `nlb` then ExternalDNS will create an NLB instead of an ALB. Example: ```yaml -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: diff --git a/docs/tutorials/nginx-ingress.md b/docs/tutorials/nginx-ingress.md index 28a29d1f2..01e451dcf 100644 --- a/docs/tutorials/nginx-ingress.md +++ b/docs/tutorials/nginx-ingress.md @@ -290,7 +290,7 @@ Use `--dry-run` if you want to be extra careful on the first run. Note, that you Create the following sample application to test that ExternalDNS works. ```yaml -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx @@ -586,7 +586,7 @@ $ kubectl annotate serviceaccount --namespace=external-dns external-dns \ Create the following sample application to test that ExternalDNS works. ```yaml -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx diff --git a/docs/tutorials/public-private-route53.md b/docs/tutorials/public-private-route53.md index 15933bc4b..5a6bc65ca 100644 --- a/docs/tutorials/public-private-route53.md +++ b/docs/tutorials/public-private-route53.md @@ -292,7 +292,7 @@ For this setup to work, you've to create two Service definitions for your applic At first, create public Service definition: ```yaml -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: @@ -313,7 +313,7 @@ spec: Then create private Service definition: ```yaml -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: @@ -334,7 +334,7 @@ spec: Additionally, you may leverage [cert-manager](https://github.com/jetstack/cert-manager) to automatically issue SSL certificates from [Let's Encrypt](https://letsencrypt.org/). To do that, request a certificate in public service definition: ```yaml -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: @@ -363,7 +363,7 @@ spec: And reuse the requested certificate in private Service definition: ```yaml -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: diff --git a/docs/tutorials/rdns.md b/docs/tutorials/rdns.md index 3a0fc85fd..cb2d2aede 100644 --- a/docs/tutorials/rdns.md +++ b/docs/tutorials/rdns.md @@ -138,7 +138,7 @@ spec: ## Testing ingress example ``` $ cat ingress.yaml -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx diff --git a/docs/tutorials/rfc2136.md b/docs/tutorials/rfc2136.md index 923477813..8dd923ef3 100644 --- a/docs/tutorials/rfc2136.md +++ b/docs/tutorials/rfc2136.md @@ -94,7 +94,7 @@ spec: selector: app: nginx --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: my-ingress From 72b4b4f4118a9b73c1bc20957d02522e159b5fb6 Mon Sep 17 00:00:00 2001 From: Thibault Jamet Date: Thu, 11 Mar 2021 12:46:41 +0100 Subject: [PATCH 077/175] Add the ability to configure k8s event rate limit Currently, the minimum delay between 2 kubernetes events handling is hard-coded to 5s. This may cause higher synchronization rates and higher DNS provider API calls when handling an important number of kubernetes events at once. Give the opportunity to configure this delay so service owners can define the acceptable thresholds on their side --- controller/controller.go | 7 +++---- controller/controller_test.go | 4 ++-- main.go | 1 + pkg/apis/externaldns/types.go | 3 +++ pkg/apis/externaldns/types_test.go | 8 ++++++-- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/controller/controller.go b/controller/controller.go index 839327bb9..8a4b47f1e 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -119,6 +119,8 @@ type Controller struct { nextRunAtMux sync.Mutex // DNS record types that will be considered for management ManagedRecordTypes []string + // MinInterval is used as window for batching events + MinInterval time.Duration } // RunOnce runs a single iteration of a reconciliation loop. @@ -165,14 +167,11 @@ func (c *Controller) RunOnce(ctx context.Context) error { return nil } -// MinInterval is used as window for batching events -const MinInterval = 5 * time.Second - // ScheduleRunOnce makes sure execution happens at most once per interval. func (c *Controller) ScheduleRunOnce(now time.Time) { c.nextRunAtMux.Lock() defer c.nextRunAtMux.Unlock() - c.nextRunAt = now.Add(MinInterval) + c.nextRunAt = now.Add(c.MinInterval) } func (c *Controller) ShouldRunOnce(now time.Time) bool { diff --git a/controller/controller_test.go b/controller/controller_test.go index 1da9d0f12..a073eb75b 100644 --- a/controller/controller_test.go +++ b/controller/controller_test.go @@ -155,7 +155,7 @@ func TestRunOnce(t *testing.T) { } func TestShouldRunOnce(t *testing.T) { - ctrl := &Controller{Interval: 10 * time.Minute} + ctrl := &Controller{Interval: 10 * time.Minute, MinInterval: 5 * time.Second} now := time.Now() @@ -175,7 +175,7 @@ func TestShouldRunOnce(t *testing.T) { assert.False(t, ctrl.ShouldRunOnce(now.Add(100*time.Microsecond))) // But after MinInterval we should run reconciliation - now = now.Add(MinInterval) + now = now.Add(5 * time.Second) assert.True(t, ctrl.ShouldRunOnce(now)) // But just one time diff --git a/main.go b/main.go index 09860c08d..dca085eeb 100644 --- a/main.go +++ b/main.go @@ -336,6 +336,7 @@ func main() { Interval: cfg.Interval, DomainFilter: domainFilter, ManagedRecordTypes: cfg.ManagedDNSRecordTypes, + MinInterval: cfg.MinInterval, } if cfg.Once { diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index b8d43f462..f32dfa597 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -120,6 +120,7 @@ type Config struct { TXTPrefix string TXTSuffix string Interval time.Duration + MinInterval time.Duration Once bool DryRun bool UpdateEvents bool @@ -234,6 +235,7 @@ var defaultConfig = &Config{ TXTSuffix: "", TXTCacheInterval: 0, TXTWildcardReplacement: "", + MinInterval: 5 * time.Second, Interval: time.Minute, Once: false, DryRun: false, @@ -454,6 +456,7 @@ func (cfg *Config) ParseFlags(args []string) error { // Flags related to the main control loop app.Flag("txt-cache-interval", "The interval between cache synchronizations in duration format (default: disabled)").Default(defaultConfig.TXTCacheInterval.String()).DurationVar(&cfg.TXTCacheInterval) app.Flag("interval", "The interval between two consecutive synchronizations in duration format (default: 1m)").Default(defaultConfig.Interval.String()).DurationVar(&cfg.Interval) + app.Flag("min-interval", "The minimum interval between two consecutive synchronizations triggered from kubernetes events in duration format (default: 5s)").Default(defaultConfig.MinInterval.String()).DurationVar(&cfg.MinInterval) app.Flag("once", "When enabled, exits the synchronization loop after the first iteration (default: disabled)").BoolVar(&cfg.Once) app.Flag("dry-run", "When enabled, prints DNS record changes rather than actually performing them (default: disabled)").BoolVar(&cfg.DryRun) app.Flag("events", "When enabled, in addition to running every interval, the reconciliation loop will get triggered when supported sources change (default: disabled)").BoolVar(&cfg.UpdateEvents) diff --git a/pkg/apis/externaldns/types_test.go b/pkg/apis/externaldns/types_test.go index df37180d4..6eb8fc705 100644 --- a/pkg/apis/externaldns/types_test.go +++ b/pkg/apis/externaldns/types_test.go @@ -90,6 +90,7 @@ var ( TXTPrefix: "", TXTCacheInterval: 0, Interval: time.Minute, + MinInterval: 5 * time.Second, Once: false, DryRun: false, UpdateEvents: false, @@ -149,8 +150,8 @@ var ( AkamaiClientToken: "o184671d5307a388180fbf7f11dbdf46", AkamaiClientSecret: "o184671d5307a388180fbf7f11dbdf46", AkamaiAccessToken: "o184671d5307a388180fbf7f11dbdf46", - AkamaiEdgercPath: "/home/test/.edgerc", - AkamaiEdgercSection: "default", + AkamaiEdgercPath: "/home/test/.edgerc", + AkamaiEdgercSection: "default", InfobloxGridHost: "127.0.0.1", InfobloxWapiPort: 8443, InfobloxWapiUsername: "infoblox", @@ -175,6 +176,7 @@ var ( TXTPrefix: "associated-txt-record", TXTCacheInterval: 12 * time.Hour, Interval: 10 * time.Minute, + MinInterval: 50 * time.Second, Once: true, DryRun: true, UpdateEvents: true, @@ -287,6 +289,7 @@ func TestParseFlags(t *testing.T) { "--txt-prefix=associated-txt-record", "--txt-cache-interval=12h", "--interval=10m", + "--min-interval=50s", "--once", "--dry-run", "--events", @@ -378,6 +381,7 @@ func TestParseFlags(t *testing.T) { "EXTERNAL_DNS_TXT_PREFIX": "associated-txt-record", "EXTERNAL_DNS_TXT_CACHE_INTERVAL": "12h", "EXTERNAL_DNS_INTERVAL": "10m", + "EXTERNAL_DNS_MIN_INTERVAL": "50s", "EXTERNAL_DNS_ONCE": "1", "EXTERNAL_DNS_DRY_RUN": "1", "EXTERNAL_DNS_EVENTS": "1", From e20aea4d5fb88f0761ca7a6f56c437567e33b52b Mon Sep 17 00:00:00 2001 From: Tim Curless Date: Thu, 2 Jan 2020 13:55:59 -0600 Subject: [PATCH 078/175] Add Initial BlueCat Provider Support The new BlueCat provider uses the BlueCat API Gateway(REST API). Not the legacy XML based BlueCat API. https://github.com/bluecatlabs/gateway-workflows --- README.md | 2 + docs/tutorials/bluecat.md | 64 ++ go.sum | 20 +- main.go | 3 + pkg/apis/externaldns/types.go | 5 +- pkg/apis/externaldns/types_test.go | 4 + provider/bluecat/OWNERS | 6 + provider/bluecat/bluecat.go | 969 +++++++++++++++++++++++++++++ provider/bluecat/bluecat_test.go | 390 ++++++++++++ 9 files changed, 1446 insertions(+), 17 deletions(-) create mode 100644 docs/tutorials/bluecat.md create mode 100644 provider/bluecat/OWNERS create mode 100644 provider/bluecat/bluecat.go create mode 100644 provider/bluecat/bluecat_test.go diff --git a/README.md b/README.md index b56a395ba..0155aa335 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ ExternalDNS' current release is `v0.7`. This version allows you to keep selected * [AWS Route 53](https://aws.amazon.com/route53/) * [AWS Cloud Map](https://docs.aws.amazon.com/cloud-map/) * [AzureDNS](https://azure.microsoft.com/en-us/services/dns) +* [BlueCat](https://bluecatnetworks.com) * [CloudFlare](https://www.cloudflare.com/dns) * [RcodeZero](https://www.rcodezero.at/) * [DigitalOcean](https://www.digitalocean.com/products/networking) @@ -82,6 +83,7 @@ The following table clarifies the current status of the providers according to t | AWS Cloud Map | Beta | | | Akamai Edge DNS | Beta | | | AzureDNS | Beta | | +| BlueCat | Alpha | @seanmalloy @vinny-sabatini | | CloudFlare | Beta | | | RcodeZero | Alpha | | | DigitalOcean | Alpha | | diff --git a/docs/tutorials/bluecat.md b/docs/tutorials/bluecat.md new file mode 100644 index 000000000..b2150b9b7 --- /dev/null +++ b/docs/tutorials/bluecat.md @@ -0,0 +1,64 @@ +# Setting up external-dns for BlueCat + +## Prerequisites +Install the BlueCat Gateway product and deploy the [community gateway workflows](https://github.com/bluecatlabs/gateway-workflows). + +## Deploy +Setup configuration file as k8s `Secret`. +``` +cat << EOF > ~/bluecat.json +{ + "gatewayHost": "https://bluecatgw.example.com", + "gatewayUsername": "user", + "GatewayPassword": "pass", + "dnsConfiguration": "Example", + "dnsView": "Internal", + "rootZone": "example.com" +} +EOF +kubectl create secret generic bluecatconfig --from-file ~/bluecat.json -n bluecat-example +``` + +Setup up deployment/service account: +``` +apiVersion: v1 +kind: ServiceAccount +metadata: + name: external-dns + namespace: bluecat-example +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: external-dns + namespace: bluecat-example +spec: + selector: + matchLabels: + app: external-dns + strategy: + type: Recreate + template: + metadata: + labels: + app: external-dns + spec: + serviceAccountName: external-dns + volumes: + - name: bluecatconfig + secret: + secretName: bluecatconfig + containers: + - name: external-dns + image: k8s.gcr.io/external-dns/external-dns:$TAG # no released versions include the bluecat provider yet + volumeMounts: + - name: bluecatconfig + mountPath: "/etc/external-dns/" + readOnly: true + args: + - --log-level=debug + - --source=service + - --provider=bluecat + - --txt-owner-id=bluecat-example + - --bluecat-config-file=/etc/external-dns/bluecat.json +``` diff --git a/go.sum b/go.sum index 23127e8a7..8a5a6e67b 100644 --- a/go.sum +++ b/go.sum @@ -92,6 +92,7 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5 h1:P5U+E4x5OkVEKQDklVPmzs71WM56RTTRqV4OrDC//Y4= github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5/go.mod h1:976q2ETgjT2snVCf2ZaBnyBbVoPERGjUz+0sofzEfro= github.com/aliyun/alibaba-cloud-sdk-go v1.61.357 h1:3ynCSeUh9OtJLd/OzLapM1DLDv2g+0yyDdkLqSfZCaQ= github.com/aliyun/alibaba-cloud-sdk-go v1.61.357/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA= @@ -127,8 +128,6 @@ github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bodgit/tsig v0.0.2 h1:seNt23SrPW8dkWoyRYzdeuqFEzr+lDc0dAJvo94xB8U= github.com/bodgit/tsig v0.0.2/go.mod h1:0mYe0t9it36SOvDQyeFekc7bLtvljFz7H9vHS/nYbgc= -github.com/bodgit/tsig v1.1.1 h1:SViReRa8KyaweqdJ3ojdYqIE3xDyJlR3G+6wAsSbLCo= -github.com/bodgit/tsig v1.1.1/go.mod h1:8LZ3Mn7AVZHH8GN2ArvzB7msHfLjoptWsdPEJRSw/uo= github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= @@ -427,7 +426,9 @@ github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ= github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= @@ -510,8 +511,6 @@ github.com/jcmturner/gokrb5/v8 v8.4.1/go.mod h1:T1hnNppQsBtxW0tCHMHTkAt8n/sABdzZ github.com/jcmturner/rpc/v2 v2.0.2 h1:gMB4IwRXYsWw4Bc6o/az2HJgFUA1ffSh90i26ZJ6Xl0= github.com/jcmturner/rpc/v2 v2.0.2/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jinzhu/copier v0.1.0 h1:Vh8xALtH3rrKGB/XIRe5d0yCTHPZFauWPLvdpDAbi88= -github.com/jinzhu/copier v0.1.0/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -599,8 +598,6 @@ github.com/maxatome/go-testdeep v1.4.0/go.mod h1:011SgQ6efzZYAen6fDn4BqQ+lUR72ys github.com/mholt/archiver/v3 v3.3.0/go.mod h1:YnQtqsp+94Rwd0D/rk5cnLrxusUBUXg+08Ebtr1Mqao= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.6/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.30 h1:Qww6FseFn8PRfw07jueqIXqodm0JKiiKuK0DeXSqfyo= -github.com/miekg/dns v1.1.30/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.36-0.20210109083720-731b191cabd1 h1:kZZmnTeY2r+88mDNCVV/uCXL2gG3rkVPTN9jcYfGQcI= github.com/miekg/dns v1.1.36-0.20210109083720-731b191cabd1/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= @@ -690,6 +687,7 @@ github.com/openshift/api v0.0.0-20200605231317-fb2a6ca106ae/go.mod h1:l6TGeqJ92D github.com/openshift/build-machinery-go v0.0.0-20200424080330-082bf86082cc/go.mod h1:1CkcsT3aVebzRBzVTSbiKSkJMsC/CASqxesfqEMfJEc= github.com/openshift/client-go v0.0.0-20200608144219-584632b8fc73 h1:JePLt9EpNLF/30KsSsArrzxGWPaUIvYUt8Fwnw9wlgM= github.com/openshift/client-go v0.0.0-20200608144219-584632b8fc73/go.mod h1:+66gk3dEqw9e+WoiXjJFzWlS1KGhj9ZRHi/RI/YG/ZM= +github.com/openshift/gssapi v0.0.0-20161010215902-5fb4217df13b h1:it0YPE/evO6/m8t8wxis9KFI2F/aleOKsI6d9uz0cEk= github.com/openshift/gssapi v0.0.0-20161010215902-5fb4217df13b/go.mod h1:tNrEB5k8SI+g5kOlsCmL2ELASfpqEofI0+FLBgBdN08= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= @@ -948,8 +946,6 @@ golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1062,7 +1058,6 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1073,9 +1068,6 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78 h1:nVuTkr9L6Bq62qpUqKo/RnZCFfzDBL0bYo6w9OJUqZY= -golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1225,12 +1217,8 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -istio.io/api v0.0.0-20200529165953-72dad51d4ffc h1:cR9GmbIBAz3FnY3tgs1SRn/uiznhtvG+mZBfD1p2vIA= -istio.io/api v0.0.0-20200529165953-72dad51d4ffc/go.mod h1:kyq3g5w42zl/AKlbzDGppYpGMQYMYMyZKeq0/eexML8= istio.io/api v0.0.0-20210128181506-0c4b8e54850f h1:zUFsawgPj5oI9p5cf91YCExRlxLIVsEkIunN9ODUSJs= istio.io/api v0.0.0-20210128181506-0c4b8e54850f/go.mod h1:88HN3o1fSD1jo+Z1WTLlJfMm9biopur6Ct9BFKjiB64= -istio.io/client-go v0.0.0-20200529172309-31c16ea3f751 h1:yH62fTmV+5l1XVTWcomsc1jjH/oH9u/tTgn5NVmdIac= -istio.io/client-go v0.0.0-20200529172309-31c16ea3f751/go.mod h1:4SGvmmus5HNFdqQsIL+uQO1PbAhjQKtSjMTqwsvYHlg= istio.io/client-go v0.0.0-20210128182905-ee2edd059e02 h1:ZA8Y2gKkKtEeYuKfqlEzIBDfU4IE5uIAdsXDeD41T9w= istio.io/client-go v0.0.0-20210128182905-ee2edd059e02/go.mod h1:oXMjFUWhxlReUSbg4i3GjKgOhSX1WgD68ZNlHQEcmQg= istio.io/gogo-genproto v0.0.0-20190904133402-ee07f2785480/go.mod h1:uKtbae4K9k2rjjX4ToV0l6etglbc1i7gqQ94XdkshzY= diff --git a/main.go b/main.go index 09860c08d..9e0837a46 100644 --- a/main.go +++ b/main.go @@ -39,6 +39,7 @@ import ( "sigs.k8s.io/external-dns/provider/aws" "sigs.k8s.io/external-dns/provider/awssd" "sigs.k8s.io/external-dns/provider/azure" + "sigs.k8s.io/external-dns/provider/bluecat" "sigs.k8s.io/external-dns/provider/cloudflare" "sigs.k8s.io/external-dns/provider/coredns" "sigs.k8s.io/external-dns/provider/designate" @@ -194,6 +195,8 @@ func main() { p, err = azure.NewAzureProvider(cfg.AzureConfigFile, domainFilter, zoneNameFilter, zoneIDFilter, cfg.AzureResourceGroup, cfg.AzureUserAssignedIdentityClientID, cfg.DryRun) case "azure-private-dns": p, err = azure.NewAzurePrivateDNSProvider(cfg.AzureConfigFile, domainFilter, zoneIDFilter, cfg.AzureResourceGroup, cfg.AzureUserAssignedIdentityClientID, cfg.DryRun) + case "bluecat": + p, err = bluecat.NewBluecatProvider(cfg.BluecatConfigFile, domainFilter, zoneIDFilter, cfg.DryRun) case "vinyldns": p, err = vinyldns.NewVinylDNSProvider(domainFilter, zoneIDFilter, cfg.DryRun) case "vultr": diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index b8d43f462..dfda5bd91 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -82,6 +82,7 @@ type Config struct { AzureResourceGroup string AzureSubscriptionID string AzureUserAssignedIdentityClientID string + BluecatConfigFile string CloudflareProxied bool CloudflareZonesPerPage int CoreDNSPrefix string @@ -199,6 +200,7 @@ var defaultConfig = &Config{ AzureConfigFile: "/etc/kubernetes/azure.json", AzureResourceGroup: "", AzureSubscriptionID: "", + BluecatConfigFile: "/etc/kubernetes/bluecat.json", CloudflareProxied: false, CloudflareZonesPerPage: 50, CoreDNSPrefix: "/skydns/", @@ -352,7 +354,7 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("managed-record-types", "Comma separated list of record types to manage (default: A, CNAME) (supported records: CNAME, A, NS").Default("A", "CNAME").StringsVar(&cfg.ManagedDNSRecordTypes) // Flags related to providers - app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, aws-sd, godaddy, google, azure, azure-dns, azure-private-dns, cloudflare, rcodezero, digitalocean, hetzner, dnsimple, akamai, infoblox, dyn, designate, coredns, skydns, inmemory, ovh, pdns, oci, exoscale, linode, rfc2136, ns1, transip, vinyldns, rdns, scaleway, vultr, ultradns)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "aws-sd", "google", "azure", "azure-dns", "hetzner", "azure-private-dns", "alibabacloud", "cloudflare", "rcodezero", "digitalocean", "dnsimple", "akamai", "infoblox", "dyn", "designate", "coredns", "skydns", "inmemory", "ovh", "pdns", "oci", "exoscale", "linode", "rfc2136", "ns1", "transip", "vinyldns", "rdns", "scaleway", "vultr", "ultradns", "godaddy") + app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, aws-sd, godaddy, google, azure, azure-dns, azure-private-dns, bluecat, cloudflare, rcodezero, digitalocean, hetzner, dnsimple, akamai, infoblox, dyn, designate, coredns, skydns, inmemory, ovh, pdns, oci, exoscale, linode, rfc2136, ns1, transip, vinyldns, rdns, scaleway, vultr, ultradns)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "aws-sd", "google", "azure", "azure-dns", "hetzner", "azure-private-dns", "alibabacloud", "cloudflare", "rcodezero", "digitalocean", "dnsimple", "akamai", "infoblox", "dyn", "designate", "coredns", "skydns", "inmemory", "ovh", "pdns", "oci", "exoscale", "linode", "rfc2136", "ns1", "transip", "vinyldns", "rdns", "scaleway", "vultr", "ultradns", "godaddy") app.Flag("domain-filter", "Limit possible target zones by a domain suffix; specify multiple times for multiple domains (optional)").Default("").StringsVar(&cfg.DomainFilter) app.Flag("exclude-domains", "Exclude subdomains (optional)").Default("").StringsVar(&cfg.ExcludeDomains) app.Flag("zone-name-filter", "Filter target zones by zone domain (For now, only AzureDNS provider is using this flag); specify multiple times for multiple zones (optional)").Default("").StringsVar(&cfg.ZoneNameFilter) @@ -375,6 +377,7 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("azure-resource-group", "When using the Azure provider, override the Azure resource group to use (required when --provider=azure-private-dns)").Default(defaultConfig.AzureResourceGroup).StringVar(&cfg.AzureResourceGroup) app.Flag("azure-subscription-id", "When using the Azure provider, specify the Azure configuration file (required when --provider=azure-private-dns)").Default(defaultConfig.AzureSubscriptionID).StringVar(&cfg.AzureSubscriptionID) app.Flag("azure-user-assigned-identity-client-id", "When using the Azure provider, override the client id of user assigned identity in config file (optional)").Default("").StringVar(&cfg.AzureUserAssignedIdentityClientID) + app.Flag("bluecat-config-file", "When using the Bluecat provider, specify the Bluecat configuration file (required when --provider=bluecat").Default(defaultConfig.BluecatConfigFile).StringVar(&cfg.BluecatConfigFile) app.Flag("cloudflare-proxied", "When using the Cloudflare provider, specify if the proxy mode must be enabled (default: disabled)").BoolVar(&cfg.CloudflareProxied) app.Flag("cloudflare-zones-per-page", "When using the Cloudflare provider, specify how many zones per page listed, max. possible 50 (default: 50)").Default(strconv.Itoa(defaultConfig.CloudflareZonesPerPage)).IntVar(&cfg.CloudflareZonesPerPage) app.Flag("coredns-prefix", "When using the CoreDNS provider, specify the prefix name").Default(defaultConfig.CoreDNSPrefix).StringVar(&cfg.CoreDNSPrefix) diff --git a/pkg/apis/externaldns/types_test.go b/pkg/apis/externaldns/types_test.go index df37180d4..6c2b1f553 100644 --- a/pkg/apis/externaldns/types_test.go +++ b/pkg/apis/externaldns/types_test.go @@ -61,6 +61,7 @@ var ( AzureConfigFile: "/etc/kubernetes/azure.json", AzureResourceGroup: "", AzureSubscriptionID: "", + BluecatConfigFile: "/etc/kubernetes/bluecat.json", CloudflareProxied: false, CloudflareZonesPerPage: 50, CoreDNSPrefix: "/skydns/", @@ -142,6 +143,7 @@ var ( AzureConfigFile: "azure.json", AzureResourceGroup: "arg", AzureSubscriptionID: "arg", + BluecatConfigFile: "bluecat.json", CloudflareProxied: true, CloudflareZonesPerPage: 20, CoreDNSPrefix: "/coredns/", @@ -236,6 +238,7 @@ func TestParseFlags(t *testing.T) { "--azure-config-file=azure.json", "--azure-resource-group=arg", "--azure-subscription-id=arg", + "--bluecat-config-file=bluecat.json", "--cloudflare-proxied", "--cloudflare-zones-per-page=20", "--coredns-prefix=/coredns/", @@ -331,6 +334,7 @@ func TestParseFlags(t *testing.T) { "EXTERNAL_DNS_AZURE_CONFIG_FILE": "azure.json", "EXTERNAL_DNS_AZURE_RESOURCE_GROUP": "arg", "EXTERNAL_DNS_AZURE_SUBSCRIPTION_ID": "arg", + "EXTERNAL_DNS_BLUECAT_CONFIG_FILE": "bluecat.json", "EXTERNAL_DNS_CLOUDFLARE_PROXIED": "1", "EXTERNAL_DNS_CLOUDFLARE_ZONES_PER_PAGE": "20", "EXTERNAL_DNS_COREDNS_PREFIX": "/coredns/", diff --git a/provider/bluecat/OWNERS b/provider/bluecat/OWNERS new file mode 100644 index 000000000..58a6b3a17 --- /dev/null +++ b/provider/bluecat/OWNERS @@ -0,0 +1,6 @@ +approvers: +- seanmalloy +- vinny-sabatini +reviewers: +- seanmalloy +- vinny-sabatini diff --git a/provider/bluecat/bluecat.go b/provider/bluecat/bluecat.go new file mode 100644 index 000000000..2205dcc0c --- /dev/null +++ b/provider/bluecat/bluecat.go @@ -0,0 +1,969 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// TODO: Ensure we have proper error handling/logging for API calls to Bluecat. getBluecatGatewayToken has a good example of this + +package bluecat + +import ( + "bytes" + "context" + "crypto/tls" + "encoding/json" + "io" + "io/ioutil" + "net/http" + "strconv" + "strings" + + "github.com/pkg/errors" + log "github.com/sirupsen/logrus" + + "sigs.k8s.io/external-dns/endpoint" + "sigs.k8s.io/external-dns/plan" + "sigs.k8s.io/external-dns/provider" +) + +type bluecatConfig struct { + GatewayHost string `json:"gatewayHost"` + GatewayUsername string `json:"gatewayUsername"` + GatewayPassword string `json:"gatewayPassword"` + DNSConfiguration string `json:"dnsConfiguration"` + View string `json:"dnsView"` + RootZone string `json:"rootZone"` +} + +// BluecatProvider implements the DNS provider for Bluecat DNS +type BluecatProvider struct { + provider.BaseProvider + domainFilter endpoint.DomainFilter + zoneIDFilter provider.ZoneIDFilter + dryRun bool + RootZone string + DNSConfiguration string + View string + gatewayClient GatewayClient +} + +type GatewayClient interface { + getBluecatZones(zoneName string) ([]BluecatZone, error) + getHostRecords(zone string, records *[]BluecatHostRecord) error + getCNAMERecords(zone string, records *[]BluecatCNAMERecord) error + getHostRecord(name string, record *BluecatHostRecord) error + getCNAMERecord(name string, record *BluecatCNAMERecord) error + createHostRecord(zone string, req *bluecatCreateHostRecordRequest) (res interface{}, err error) + createCNAMERecord(zone string, req *bluecatCreateCNAMERecordRequest) (res interface{}, err error) + deleteHostRecord(name string) (err error) + deleteCNAMERecord(name string) (err error) + buildHTTPRequest(method, url string, body io.Reader) (*http.Request, error) + getTXTRecords(zone string, records *[]BluecatTXTRecord) error + getTXTRecord(name string, record *BluecatTXTRecord) error + createTXTRecord(zone string, req *bluecatCreateTXTRecordRequest) (res interface{}, err error) + deleteTXTRecord(name string) error +} + +// GatewayClientConfig defines new client on bluecat gateway +type GatewayClientConfig struct { + Cookie http.Cookie + Token string + Host string + DNSConfiguration string + View string + RootZone string +} + +// BluecatZone defines a zone to hold records +type BluecatZone struct { + ID int `json:"id"` + Name string `json:"name"` + Properties string `json:"properties"` + Type string `json:"type"` +} + +// BluecatHostRecord defines dns Host record +type BluecatHostRecord struct { + ID int `json:"id"` + Name string `json:"name"` + Properties string `json:"properties"` + Type string `json:"type"` +} + +// BluecatCNAMERecord defines dns CNAME record +type BluecatCNAMERecord struct { + ID int `json:"id"` + Name string `json:"name"` + Properties string `json:"properties"` + Type string `json:"type"` +} + +// BluecatTXTRecord defines dns TXT record +type BluecatTXTRecord struct { + ID int `json:"id"` + Name string `json:"name"` + Text string `json:"text"` +} + +type bluecatRecordSet struct { + obj interface{} + res interface{} +} + +type bluecatCreateHostRecordRequest struct { + AbsoluteName string `json:"absolute_name"` + IP4Address string `json:"ip4_address"` + TTL int `json:"ttl"` + Properties string `json:"properties"` +} + +type bluecatCreateCNAMERecordRequest struct { + AbsoluteName string `json:"absolute_name"` + LinkedRecord string `json:"linked_record"` + TTL int `json:"ttl"` + Properties string `json:"properties"` +} + +type bluecatCreateTXTRecordRequest struct { + AbsoluteName string `json:"absolute_name"` + Text string `json:"txt"` +} + +// NewBluecatProvider creates a new Bluecat provider. +// +// Returns a pointer to the provider or an error if a provider could not be created. +func NewBluecatProvider(configFile string, domainFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, dryRun bool) (*BluecatProvider, error) { + contents, err := ioutil.ReadFile(configFile) + if err != nil { + return nil, errors.Wrapf(err, "failed to read Bluecat config file %v", configFile) + } + + cfg := bluecatConfig{} + err = json.Unmarshal(contents, &cfg) + if err != nil { + return nil, errors.Wrapf(err, "failed to read Bluecat config file %v", configFile) + } + + token, cookie, err := getBluecatGatewayToken(cfg) + if err != nil { + return nil, errors.Wrap(err, "failed to get API token from Bluecat Gateway") + } + gatewayClient := NewGatewayClient(cookie, token, cfg.GatewayHost, cfg.DNSConfiguration, cfg.View, cfg.RootZone) + + provider := &BluecatProvider{ + domainFilter: domainFilter, + zoneIDFilter: zoneIDFilter, + dryRun: dryRun, + gatewayClient: gatewayClient, + DNSConfiguration: cfg.DNSConfiguration, + View: cfg.View, + RootZone: cfg.RootZone, + } + return provider, nil +} + +// NewGatewayClient creates and returns a new Bluecat gateway client +func NewGatewayClient(cookie http.Cookie, token, gatewayHost, dnsConfiguration, view, rootZone string) GatewayClientConfig { + // Right now the Bluecat gateway doesn't seem to have a way to get the root zone from the API. If the user + // doesn't provide one via the config file we'll assume it's 'com' + if rootZone == "" { + rootZone = "com" + } + return GatewayClientConfig{ + Cookie: cookie, + Token: token, + Host: gatewayHost, + DNSConfiguration: dnsConfiguration, + View: view, + RootZone: rootZone, + } +} + +// Records fetches Host, CNAME, and TXT records from bluecat gateway +func (p *BluecatProvider) Records(ctx context.Context) (endpoints []*endpoint.Endpoint, err error) { + zones, err := p.zones() + if err != nil { + return nil, errors.Wrap(err, "could not fetch zones") + } + + for _, zone := range zones { + log.Debugf("fetching records from zone '%s'", zone) + var resH []BluecatHostRecord + err = p.gatewayClient.getHostRecords(zone, &resH) + if err != nil { + return nil, errors.Wrapf(err, "could not fetch host records for zone: %v", zone) + } + for _, rec := range resH { + propMap := splitProperties(rec.Properties) + ips := strings.Split(propMap["addresses"], ",") + for _, ip := range ips { + ep := endpoint.NewEndpoint(propMap["absoluteName"], endpoint.RecordTypeA, ip) + endpoints = append(endpoints, ep) + } + } + + var resC []BluecatCNAMERecord + err = p.gatewayClient.getCNAMERecords(zone, &resC) + if err != nil { + return nil, errors.Wrapf(err, "could not fetch CNAME records for zone: %v", zone) + } + for _, rec := range resC { + propMap := splitProperties(rec.Properties) + endpoints = append(endpoints, endpoint.NewEndpoint(propMap["absoluteName"], endpoint.RecordTypeCNAME, propMap["linkedRecordName"])) + } + + var resT []BluecatTXTRecord + err = p.gatewayClient.getTXTRecords(zone, &resT) + if err != nil { + return nil, errors.Wrapf(err, "could not fetch TXT records for zone: %v", zone) + } + for _, rec := range resT { + endpoints = append(endpoints, endpoint.NewEndpoint(rec.Name, endpoint.RecordTypeTXT, rec.Text)) + } + } + + log.Debugf("fetched %d records from Bluecat", len(endpoints)) + return endpoints, nil +} + +// ApplyChanges updates necessary zones and replaces old records with new ones +// +// Returns nil upon success and err is there is an error +func (p *BluecatProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error { + zones, err := p.zones() + if err != nil { + return err + } + log.Infof("zones is: %+v\n", zones) + log.Infof("changes: %+v\n", changes) + created, deleted := p.mapChanges(zones, changes) + log.Infof("created: %+v\n", created) + log.Infof("deleted: %+v\n", deleted) + p.deleteRecords(deleted) + p.createRecords(created) + + // TODO: add bluecat deploy API call here + + return nil +} + +type bluecatChangeMap map[string][]*endpoint.Endpoint + +func (p *BluecatProvider) mapChanges(zones []string, changes *plan.Changes) (bluecatChangeMap, bluecatChangeMap) { + created := bluecatChangeMap{} + deleted := bluecatChangeMap{} + + mapChange := func(changeMap bluecatChangeMap, change *endpoint.Endpoint) { + zone := p.findZone(zones, change.DNSName) + if zone == "" { + log.Debugf("ignoring changes to '%s' because a suitable Bluecat DNS zone was not found", change.DNSName) + return + } + changeMap[zone] = append(changeMap[zone], change) + } + + for _, change := range changes.Delete { + mapChange(deleted, change) + } + for _, change := range changes.UpdateOld { + mapChange(deleted, change) + } + for _, change := range changes.Create { + mapChange(created, change) + } + for _, change := range changes.UpdateNew { + mapChange(created, change) + } + + return created, deleted +} + +// findZone finds the most specific matching zone for a given record 'name' from a list of all zones +func (p *BluecatProvider) findZone(zones []string, name string) string { + var result string + + for _, zone := range zones { + if strings.HasSuffix(name, "."+zone) { + if result == "" || len(zone) > len(result) { + result = zone + } + } else if strings.EqualFold(name, zone) { + if result == "" || len(zone) > len(result) { + result = zone + } + } + } + + return result +} + +func (p *BluecatProvider) zones() ([]string, error) { + log.Debugf("retrieving Bluecat zones for configuration: %s, view: %s", p.DNSConfiguration, p.View) + var zones []string + + zonelist, err := p.gatewayClient.getBluecatZones(p.RootZone) + if err != nil { + return nil, err + } + + for _, zone := range zonelist { + if !p.domainFilter.Match(zone.Name) { + continue + } + + // TODO: match to absoluteName(string) not Id(int) + if !p.zoneIDFilter.Match(strconv.Itoa(zone.ID)) { + continue + } + + zoneProps := splitProperties(zone.Properties) + + zones = append(zones, zoneProps["absoluteName"]) + } + log.Debugf("found %d zones", len(zones)) + return zones, nil +} + +func (p *BluecatProvider) createRecords(created bluecatChangeMap) { + for zone, endpoints := range created { + for _, ep := range endpoints { + if p.dryRun { + log.Infof("would create %s record named '%s' to '%s' for Bluecat DNS zone '%s'.", + ep.RecordType, + ep.DNSName, + ep.Targets, + zone, + ) + continue + } + + log.Infof("creating %s record named '%s' to '%s' for Bluecat DNS zone '%s'.", + ep.RecordType, + ep.DNSName, + ep.Targets, + zone, + ) + + recordSet, err := p.recordSet(ep, false) + if err != nil { + log.Errorf( + "Failed to retrieve %s record named '%s' to '%s' for Bluecat DNS zone '%s': %v", + ep.RecordType, + ep.DNSName, + ep.Targets, + zone, + err, + ) + continue + } + var response interface{} + switch ep.RecordType { + case endpoint.RecordTypeA: + response, err = p.gatewayClient.createHostRecord(zone, recordSet.obj.(*bluecatCreateHostRecordRequest)) + case endpoint.RecordTypeCNAME: + response, err = p.gatewayClient.createCNAMERecord(zone, recordSet.obj.(*bluecatCreateCNAMERecordRequest)) + case endpoint.RecordTypeTXT: + response, err = p.gatewayClient.createTXTRecord(zone, recordSet.obj.(*bluecatCreateTXTRecordRequest)) + } + log.Debugf("Response from create: %v", response) + if err != nil { + log.Errorf( + "Failed to create %s record named '%s' to '%s' for Bluecat DNS zone '%s': %v", + ep.RecordType, + ep.DNSName, + ep.Targets, + zone, + err, + ) + } + } + } +} + +func (p *BluecatProvider) deleteRecords(deleted bluecatChangeMap) { + // run deletions first + for zone, endpoints := range deleted { + for _, ep := range endpoints { + if p.dryRun { + log.Infof("would delete %s record named '%s' for Bluecat DNS zone '%s'.", + ep.RecordType, + ep.DNSName, + zone, + ) + continue + } else { + log.Infof("deleting %s record named '%s' for Bluecat DNS zone '%s'.", + ep.RecordType, + ep.DNSName, + zone, + ) + + recordSet, err := p.recordSet(ep, true) + if err != nil { + log.Errorf( + "Failed to retrieve %s record named '%s' to '%s' for Bluecat DNS zone '%s': %v", + ep.RecordType, + ep.DNSName, + ep.Targets, + zone, + err, + ) + continue + } + + switch ep.RecordType { + case endpoint.RecordTypeA: + for _, record := range *recordSet.res.(*[]BluecatHostRecord) { + err = p.gatewayClient.deleteHostRecord(record.Name) + } + case endpoint.RecordTypeCNAME: + for _, record := range *recordSet.res.(*[]BluecatCNAMERecord) { + err = p.gatewayClient.deleteCNAMERecord(record.Name) + } + case endpoint.RecordTypeTXT: + for _, record := range *recordSet.res.(*[]BluecatTXTRecord) { + err = p.gatewayClient.deleteTXTRecord(record.Name) + } + } + if err != nil { + log.Errorf("Failed to delete %s record named '%s' for Bluecat DNS zone '%s': %v", + ep.RecordType, + ep.DNSName, + zone, + err) + } + } + } + } +} + +func (p *BluecatProvider) recordSet(ep *endpoint.Endpoint, getObject bool) (recordSet bluecatRecordSet, err error) { + switch ep.RecordType { + case endpoint.RecordTypeA: + var res []BluecatHostRecord + // TODO Allow configurable properties/ttl + obj := bluecatCreateHostRecordRequest{ + AbsoluteName: ep.DNSName, + IP4Address: ep.Targets[0], + TTL: 0, + Properties: "", + } + if getObject { + var record BluecatHostRecord + err = p.gatewayClient.getHostRecord(ep.DNSName, &record) + if err != nil { + return + } + res = append(res, record) + } + recordSet = bluecatRecordSet{ + obj: &obj, + res: &res, + } + case endpoint.RecordTypeCNAME: + var res []BluecatCNAMERecord + obj := bluecatCreateCNAMERecordRequest{ + AbsoluteName: ep.DNSName, + LinkedRecord: ep.Targets[0], + TTL: 0, + Properties: "", + } + if getObject { + var record BluecatCNAMERecord + err = p.gatewayClient.getCNAMERecord(ep.DNSName, &record) + if err != nil { + return + } + res = append(res, record) + } + recordSet = bluecatRecordSet{ + obj: &obj, + res: &res, + } + case endpoint.RecordTypeTXT: + var res []BluecatTXTRecord + obj := bluecatCreateTXTRecordRequest{ + AbsoluteName: ep.DNSName, + Text: ep.Targets[0], + } + if getObject { + var record BluecatTXTRecord + err = p.gatewayClient.getTXTRecord(ep.DNSName, &record) + if err != nil { + return + } + res = append(res, record) + } + recordSet = bluecatRecordSet{ + obj: &obj, + res: &res, + } + } + return +} + +// getBluecatGatewayToken retrieves a Bluecat Gateway API token. +func getBluecatGatewayToken(cfg bluecatConfig) (string, http.Cookie, error) { + body, err := json.Marshal(map[string]string{ + "username": cfg.GatewayUsername, + "password": cfg.GatewayPassword, + }) + if err != nil { + return "", http.Cookie{}, errors.Wrap(err, "could not unmarshal credentials for bluecat gateway config") + } + + c := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // ignore self-signed SSL cert check + }} + + resp, err := c.Post(cfg.GatewayHost+"/rest_login", "application/json", bytes.NewBuffer(body)) + if err != nil { + return "", http.Cookie{}, errors.Wrap(err, "error obtaining API token from bluecat gateway") + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + details, _ := ioutil.ReadAll(resp.Body) + return "", http.Cookie{}, errors.Errorf("got HTTP response code %v, detailed message: %v", resp.StatusCode, string(details)) + } + + res, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", http.Cookie{}, errors.Wrap(err, "error reading get_token response from bluecat gateway") + } + + resJSON := map[string]string{} + err = json.Unmarshal(res, &resJSON) + if err != nil { + return "", http.Cookie{}, errors.Wrap(err, "error unmarshaling json response (auth) from bluecat gateway") + } + + // Example response: {"access_token": "BAMAuthToken: abc123"} + // We only care about the actual token string - i.e. abc123 + // The gateway also creates a cookie as part of the response. This seems to be the actual auth mechanism, at least + // for now. + return strings.Split(resJSON["access_token"], " ")[1], *resp.Cookies()[0], nil +} + +func (c GatewayClientConfig) getBluecatZones(zoneName string) ([]BluecatZone, error) { + transportCfg := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + } + client := &http.Client{ + Transport: transportCfg, + } + zonePath := expandZone(zoneName) + url := c.Host + "/api/v1/configurations/" + c.DNSConfiguration + "/views/" + c.View + "/" + zonePath + req, err := c.buildHTTPRequest("GET", url, nil) + if err != nil { + return nil, errors.Wrap(err, "error building http request") + } + + resp, err := client.Do(req) + if err != nil { + return nil, errors.Wrapf(err, "error retrieving zone(s) from gateway: %v, %v", url, zoneName) + } + + defer resp.Body.Close() + + zones := []BluecatZone{} + json.NewDecoder(resp.Body).Decode(&zones) + + // Bluecat Gateway only returns subzones one level deeper than the provided zone + // so this recursion is needed to traverse subzones until none are returned + for _, zone := range zones { + zoneProps := splitProperties(zone.Properties) + subZones, err := c.getBluecatZones(zoneProps["absoluteName"]) + if err != nil { + return nil, errors.Wrapf(err, "error retrieving subzones from gateway: %v", zoneName) + } + zones = append(zones, subZones...) + } + + return zones, nil +} + +func (c GatewayClientConfig) getHostRecords(zone string, records *[]BluecatHostRecord) error { + transportCfg := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + } + client := &http.Client{ + Transport: transportCfg, + } + + zonePath := expandZone(zone) + + // Remove the trailing 'zones/' + zonePath = strings.TrimSuffix(zonePath, "zones/") + + url := c.Host + "/api/v1/configurations/" + c.DNSConfiguration + "/views/" + c.View + "/" + zonePath + "host_records/" + req, err := c.buildHTTPRequest("GET", url, nil) + if err != nil { + return errors.Wrap(err, "error building http request") + } + + resp, err := client.Do(req) + if err != nil { + return errors.Wrapf(err, "error retrieving record(s) from gateway: %v", zone) + } + + defer resp.Body.Close() + + json.NewDecoder(resp.Body).Decode(records) + log.Debugf("Get Host Records Response: %v", records) + + return nil +} + +func (c GatewayClientConfig) getCNAMERecords(zone string, records *[]BluecatCNAMERecord) error { + transportCfg := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + } + client := &http.Client{ + Transport: transportCfg, + } + + zonePath := expandZone(zone) + + // Remove the trailing 'zones/' + zonePath = strings.TrimSuffix(zonePath, "zones/") + + url := c.Host + "/api/v1/configurations/" + c.DNSConfiguration + "/views/" + c.View + "/" + zonePath + "cname_records/" + req, err := c.buildHTTPRequest("GET", url, nil) + if err != nil { + return errors.Wrap(err, "error building http request") + } + + resp, err := client.Do(req) + if err != nil { + return errors.Wrapf(err, "error retrieving record(s) from gateway: %v", zone) + } + + defer resp.Body.Close() + + json.NewDecoder(resp.Body).Decode(records) + log.Debugf("Get CName Records Response: %v", records) + + return nil +} + +func (c GatewayClientConfig) getTXTRecords(zone string, records *[]BluecatTXTRecord) error { + transportCfg := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + } + client := &http.Client{ + Transport: transportCfg, + } + + zonePath := expandZone(zone) + + // Remove the trailing 'zones/' + zonePath = strings.TrimSuffix(zonePath, "zones/") + + url := c.Host + "/api/v1/configurations/" + c.DNSConfiguration + "/views/" + c.View + "/" + zonePath + "text_records/" + req, err := c.buildHTTPRequest("GET", url, nil) + if err != nil { + return errors.Wrap(err, "error building http request") + } + log.Debugf("Request: %v", req) + + resp, err := client.Do(req) + if err != nil { + return errors.Wrapf(err, "error retrieving record(s) from gateway: %v", zone) + } + log.Debugf("Get Txt Records response: %v", resp) + + defer resp.Body.Close() + + json.NewDecoder(resp.Body).Decode(records) + log.Debugf("Get TXT Records Body: %v", records) + + return nil +} + +func (c GatewayClientConfig) getHostRecord(name string, record *BluecatHostRecord) error { + transportCfg := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + } + client := &http.Client{ + Transport: transportCfg, + } + + url := c.Host + "/api/v1/configurations/" + c.DNSConfiguration + + "/views/" + c.View + "/" + + "host_records/" + name + "/" + req, err := c.buildHTTPRequest("GET", url, nil) + if err != nil { + return errors.Wrapf(err, "error building http request: %v", name) + } + + resp, err := client.Do(req) + if err != nil { + return errors.Wrapf(err, "error retrieving record(s) from gateway: %v", name) + } + + defer resp.Body.Close() + + json.NewDecoder(resp.Body).Decode(record) + log.Debugf("Get Host Record Response: %v", record) + return nil +} + +func (c GatewayClientConfig) getCNAMERecord(name string, record *BluecatCNAMERecord) error { + transportCfg := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + } + client := &http.Client{ + Transport: transportCfg, + } + + url := c.Host + "/api/v1/configurations/" + c.DNSConfiguration + + "/views/" + c.View + "/" + + "cname_records/" + name + "/" + req, err := c.buildHTTPRequest("GET", url, nil) + if err != nil { + return errors.Wrapf(err, "error building http request: %v", name) + } + + resp, err := client.Do(req) + if err != nil { + return errors.Wrapf(err, "error retrieving record(s) from gateway: %v", name) + } + + defer resp.Body.Close() + + json.NewDecoder(resp.Body).Decode(record) + log.Debugf("Get CName Record Response: %v", record) + return nil +} + +func (c GatewayClientConfig) getTXTRecord(name string, record *BluecatTXTRecord) error { + transportCfg := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + } + client := &http.Client{ + Transport: transportCfg, + } + + url := c.Host + "/api/v1/configurations/" + c.DNSConfiguration + + "/views/" + c.View + "/" + + "text_records/" + name + "/" + req, err := c.buildHTTPRequest("GET", url, nil) + if err != nil { + return errors.Wrap(err, "error building http request") + } + + resp, err := client.Do(req) + if err != nil { + return errors.Wrapf(err, "error retrieving record(s) from gateway: %v", name) + } + + defer resp.Body.Close() + + json.NewDecoder(resp.Body).Decode(record) + log.Debugf("Get TXT Record Response: %v", record) + + return nil +} + +func (c GatewayClientConfig) createHostRecord(zone string, req *bluecatCreateHostRecordRequest) (res interface{}, err error) { + transportCfg := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + } + client := &http.Client{ + Transport: transportCfg, + } + + zonePath := expandZone(zone) + // Remove the trailing 'zones/' + zonePath = strings.TrimSuffix(zonePath, "zones/") + + url := c.Host + "/api/v1/configurations/" + c.DNSConfiguration + "/views/" + c.View + "/" + zonePath + "host_records/" + body, _ := json.Marshal(req) + hreq, err := c.buildHTTPRequest("POST", url, bytes.NewBuffer(body)) + if err != nil { + return nil, errors.Wrap(err, "error building http request") + } + hreq.Header.Add("Content-Type", "application/json") + res, err = client.Do(hreq) + + return +} + +func (c GatewayClientConfig) createCNAMERecord(zone string, req *bluecatCreateCNAMERecordRequest) (res interface{}, err error) { + transportCfg := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + } + client := &http.Client{ + Transport: transportCfg, + } + + zonePath := expandZone(zone) + // Remove the trailing 'zones/' + zonePath = strings.TrimSuffix(zonePath, "zones/") + + url := c.Host + "/api/v1/configurations/" + c.DNSConfiguration + "/views/" + c.View + "/" + zonePath + "cname_records/" + body, _ := json.Marshal(req) + + hreq, err := c.buildHTTPRequest("POST", url, bytes.NewBuffer(body)) + if err != nil { + return nil, errors.Wrap(err, "error building http request") + } + + hreq.Header.Add("Content-Type", "application/json") + res, err = client.Do(hreq) + + return +} + +func (c GatewayClientConfig) createTXTRecord(zone string, req *bluecatCreateTXTRecordRequest) (interface{}, error) { + transportCfg := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + } + client := &http.Client{ + Transport: transportCfg, + } + + zonePath := expandZone(zone) + // Remove the trailing 'zones/' + zonePath = strings.TrimSuffix(zonePath, "zones/") + + url := c.Host + "/api/v1/configurations/" + c.DNSConfiguration + "/views/" + c.View + "/" + zonePath + "text_records/" + body, _ := json.Marshal(req) + hreq, err := c.buildHTTPRequest("POST", url, bytes.NewBuffer(body)) + if err != nil { + return nil, err + } + + hreq.Header.Add("Content-Type", "application/json") + res, err := client.Do(hreq) + + return res, err +} + +func (c GatewayClientConfig) deleteHostRecord(name string) (err error) { + transportCfg := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + } + client := &http.Client{ + Transport: transportCfg, + } + + url := c.Host + "/api/v1/configurations/" + c.DNSConfiguration + + "/views/" + c.View + "/" + + "host_records/" + name + "/" + req, err := c.buildHTTPRequest("DELETE", url, nil) + if err != nil { + return errors.Wrapf(err, "error building http request: %v", name) + } + + _, err = client.Do(req) + if err != nil { + return errors.Wrapf(err, "error deleting record(s) from gateway: %v", name) + } + + return nil +} + +func (c GatewayClientConfig) deleteCNAMERecord(name string) (err error) { + transportCfg := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + } + client := &http.Client{ + Transport: transportCfg, + } + + url := c.Host + "/api/v1/configurations/" + c.DNSConfiguration + + "/views/" + c.View + "/" + + "cname_records/" + name + "/" + req, err := c.buildHTTPRequest("DELETE", url, nil) + if err != nil { + return errors.Wrapf(err, "error building http request: %v", name) + } + + _, err = client.Do(req) + if err != nil { + return errors.Wrapf(err, "error deleting record(s) from gateway: %v", name) + } + + return nil +} + +func (c GatewayClientConfig) deleteTXTRecord(name string) error { + transportCfg := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + } + client := &http.Client{ + Transport: transportCfg, + } + + url := c.Host + "/api/v1/configurations/" + c.DNSConfiguration + + "/views/" + c.View + "/" + + "text_records/" + name + "/" + + req, err := c.buildHTTPRequest("DELETE", url, nil) + if err != nil { + return errors.Wrap(err, "error building http request") + } + + _, err = client.Do(req) + if err != nil { + return errors.Wrapf(err, "error deleting record(s) from gateway: %v", name) + } + + return nil +} + +//buildHTTPRequest builds a standard http Request and adds authentication headers required by Bluecat Gateway +func (c GatewayClientConfig) buildHTTPRequest(method, url string, body io.Reader) (*http.Request, error) { + req, err := http.NewRequest(method, url, body) + req.Header.Add("Accept", "application/json") + req.Header.Add("Authorization", "Basic "+c.Token) + req.AddCookie(&c.Cookie) + return req, err +} + +//splitProperties is a helper function to break a '|' separated string into key/value pairs +// i.e. "foo=bar|baz=mop" +func splitProperties(props string) map[string]string { + propMap := make(map[string]string) + + // remove trailing | character before we split + props = strings.TrimSuffix(props, "|") + + splits := strings.Split(props, "|") + for _, pair := range splits { + items := strings.Split(pair, "=") + propMap[items[0]] = items[1] + } + + return propMap +} + +//expandZone takes an absolute domain name such as 'example.com' and returns a zone hierarchy used by Bluecat Gateway, +//such as '/zones/com/zones/example/zones/' +func expandZone(zone string) string { + ze := "zones/" + parts := strings.Split(zone, ".") + if len(parts) > 1 { + last := len(parts) - 1 + for i := range parts { + ze = ze + parts[last-i] + "/zones/" + } + } else { + ze = ze + zone + "/zones/" + } + return ze +} diff --git a/provider/bluecat/bluecat_test.go b/provider/bluecat/bluecat_test.go new file mode 100644 index 000000000..1ec751d70 --- /dev/null +++ b/provider/bluecat/bluecat_test.go @@ -0,0 +1,390 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package bluecat + +import ( + "context" + "fmt" + "io" + "net/http" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "sigs.k8s.io/external-dns/endpoint" + "sigs.k8s.io/external-dns/internal/testutils" + "sigs.k8s.io/external-dns/plan" + "sigs.k8s.io/external-dns/provider" +) + +type mockGatewayClient struct { + mockBluecatZones *[]BluecatZone + mockBluecatHosts *[]BluecatHostRecord + mockBluecatCNAMEs *[]BluecatCNAMERecord + mockBluecatTXTs *[]BluecatTXTRecord +} + +type Changes struct { + // Records that need to be created + Create []*endpoint.Endpoint + // Records that need to be updated (current data) + UpdateOld []*endpoint.Endpoint + // Records that need to be updated (desired data) + UpdateNew []*endpoint.Endpoint + // Records that need to be deleted + Delete []*endpoint.Endpoint +} + +func (g mockGatewayClient) getBluecatZones(zoneName string) ([]BluecatZone, error) { + return *g.mockBluecatZones, nil +} +func (g mockGatewayClient) getHostRecords(zone string, records *[]BluecatHostRecord) error { + *records = *g.mockBluecatHosts + return nil +} +func (g mockGatewayClient) getCNAMERecords(zone string, records *[]BluecatCNAMERecord) error { + *records = *g.mockBluecatCNAMEs + return nil +} +func (g mockGatewayClient) getHostRecord(name string, record *BluecatHostRecord) error { + for _, currentRecord := range *g.mockBluecatHosts { + if currentRecord.Name == strings.Split(name, ".")[0] { + *record = currentRecord + return nil + } + } + return nil +} +func (g mockGatewayClient) getCNAMERecord(name string, record *BluecatCNAMERecord) error { + for _, currentRecord := range *g.mockBluecatCNAMEs { + if currentRecord.Name == strings.Split(name, ".")[0] { + *record = currentRecord + return nil + } + } + return nil +} +func (g mockGatewayClient) createHostRecord(zone string, req *bluecatCreateHostRecordRequest) (res interface{}, err error) { + return nil, nil +} +func (g mockGatewayClient) createCNAMERecord(zone string, req *bluecatCreateCNAMERecordRequest) (res interface{}, err error) { + return nil, nil +} +func (g mockGatewayClient) deleteHostRecord(name string) (err error) { + *g.mockBluecatHosts = nil + return nil +} +func (g mockGatewayClient) deleteCNAMERecord(name string) (err error) { + *g.mockBluecatCNAMEs = nil + return nil +} +func (g mockGatewayClient) getTXTRecords(zone string, records *[]BluecatTXTRecord) error { + *records = *g.mockBluecatTXTs + return nil +} +func (g mockGatewayClient) getTXTRecord(name string, record *BluecatTXTRecord) error { + for _, currentRecord := range *g.mockBluecatTXTs { + if currentRecord.Name == name { + *record = currentRecord + return nil + } + } + return nil +} +func (g mockGatewayClient) createTXTRecord(zone string, req *bluecatCreateTXTRecordRequest) (res interface{}, err error) { + return nil, nil +} +func (g mockGatewayClient) deleteTXTRecord(name string) error { + *g.mockBluecatTXTs = nil + return nil +} + +func (g mockGatewayClient) buildHTTPRequest(method, url string, body io.Reader) (*http.Request, error) { + request, _ := http.NewRequest("GET", fmt.Sprintf("%s/users", "http://some.com/api/v1"), nil) + return request, nil +} + +func createMockBluecatZone(fqdn string) BluecatZone { + props := "absoluteName=" + fqdn + return BluecatZone{ + Properties: props, + Name: fqdn, + ID: 3, + } +} + +func createMockBluecatHostRecord(fqdn, target string) BluecatHostRecord { + props := "absoluteName=" + fqdn + "|addresses=" + target + "|" + nameParts := strings.Split(fqdn, ".") + return BluecatHostRecord{ + Name: nameParts[0], + Properties: props, + ID: 3, + } +} + +func createMockBluecatCNAME(alias, target string) BluecatCNAMERecord { + props := "absoluteName=" + alias + "|linkedRecordName=" + target + "|" + nameParts := strings.Split(alias, ".") + return BluecatCNAMERecord{ + Name: nameParts[0], + Properties: props, + } +} + +func createMockBluecatTXT(fqdn, txt string) BluecatTXTRecord { + return BluecatTXTRecord{ + Name: fqdn, + Text: txt, + } +} + +func newBluecatProvider(domainFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, dryRun bool, client GatewayClient) *BluecatProvider { + return &BluecatProvider{ + domainFilter: domainFilter, + zoneIDFilter: zoneIDFilter, + dryRun: dryRun, + gatewayClient: client, + } +} + +type bluecatTestData []struct { + TestDescription string + Endpoints []*endpoint.Endpoint +} + +var tests = bluecatTestData{ + { + "first test case", // TODO: better test description + []*endpoint.Endpoint{ + { + DNSName: "example.com", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"123.123.123.122"}, + }, + { + DNSName: "nginx.example.com", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"123.123.123.123"}, + }, + { + DNSName: "whitespace.example.com", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"123.123.123.124"}, + }, + { + DNSName: "hack.example.com", + RecordType: endpoint.RecordTypeCNAME, + Targets: endpoint.Targets{"bluecatnetworks.com"}, + }, + { + DNSName: "abc.example.com", + RecordType: endpoint.RecordTypeTXT, + Targets: endpoint.Targets{"hello"}, + }, + }, + }, +} + +func TestBluecatRecords(t *testing.T) { + client := mockGatewayClient{ + mockBluecatZones: &[]BluecatZone{ + createMockBluecatZone("example.com"), + }, + mockBluecatHosts: &[]BluecatHostRecord{ + createMockBluecatHostRecord("example.com", "123.123.123.122"), + createMockBluecatHostRecord("nginx.example.com", "123.123.123.123"), + createMockBluecatHostRecord("whitespace.example.com", "123.123.123.124"), + }, + mockBluecatCNAMEs: &[]BluecatCNAMERecord{ + createMockBluecatCNAME("hack.example.com", "bluecatnetworks.com"), + }, + mockBluecatTXTs: &[]BluecatTXTRecord{ + createMockBluecatTXT("abc.example.com", "hello"), + }, + } + + provider := newBluecatProvider( + endpoint.NewDomainFilter([]string{"example.com"}), + provider.NewZoneIDFilter([]string{""}), false, client) + + for _, ti := range tests { + actual, err := provider.Records(context.Background()) + if err != nil { + t.Fatal(err) + } + validateEndpoints(t, actual, ti.Endpoints) + } +} + +func TestBluecatApplyChangesCreate(t *testing.T) { + client := mockGatewayClient{ + mockBluecatZones: &[]BluecatZone{ + createMockBluecatZone("example.com"), + }, + mockBluecatHosts: &[]BluecatHostRecord{}, + mockBluecatCNAMEs: &[]BluecatCNAMERecord{}, + mockBluecatTXTs: &[]BluecatTXTRecord{}, + } + + provider := newBluecatProvider( + endpoint.NewDomainFilter([]string{"example.com"}), + provider.NewZoneIDFilter([]string{""}), false, client) + + for _, ti := range tests { + err := provider.ApplyChanges(context.Background(), &plan.Changes{Create: ti.Endpoints}) + if err != nil { + t.Fatal(err) + } + + actual, err := provider.Records(context.Background()) + if err != nil { + t.Fatal(err) + } + validateEndpoints(t, actual, []*endpoint.Endpoint{}) + } +} +func TestBluecatApplyChangesDelete(t *testing.T) { + client := mockGatewayClient{ + mockBluecatZones: &[]BluecatZone{ + createMockBluecatZone("example.com"), + }, + mockBluecatHosts: &[]BluecatHostRecord{ + createMockBluecatHostRecord("example.com", "123.123.123.122"), + createMockBluecatHostRecord("nginx.example.com", "123.123.123.123"), + createMockBluecatHostRecord("whitespace.example.com", "123.123.123.124"), + }, + mockBluecatCNAMEs: &[]BluecatCNAMERecord{ + createMockBluecatCNAME("hack.example.com", "bluecatnetworks.com"), + }, + mockBluecatTXTs: &[]BluecatTXTRecord{ + createMockBluecatTXT("abc.example.com", "hello"), + }, + } + + provider := newBluecatProvider( + endpoint.NewDomainFilter([]string{"example.com"}), + provider.NewZoneIDFilter([]string{""}), false, client) + + for _, ti := range tests { + err := provider.ApplyChanges(context.Background(), &plan.Changes{Delete: ti.Endpoints}) + if err != nil { + t.Fatal(err) + } + + actual, err := provider.Records(context.Background()) + if err != nil { + t.Fatal(err) + } + validateEndpoints(t, actual, []*endpoint.Endpoint{}) + } +} + +// TODO: ensure mapChanges method is tested +// TODO: ensure findZone method is tested +// TODO: ensure zones method is tested +// TODO: ensure createRecords method is tested +// TODO: ensure deleteRecords method is tested +// TODO: ensure recordSet method is tested + +// TODO: Figure out why recordSet.res is not being set properly +func TestBluecatRecordset(t *testing.T) { + client := mockGatewayClient{ + mockBluecatZones: &[]BluecatZone{ + createMockBluecatZone("example.com"), + }, + mockBluecatHosts: &[]BluecatHostRecord{ + createMockBluecatHostRecord("example.com", "123.123.123.122"), + createMockBluecatHostRecord("nginx.example.com", "123.123.123.123"), + createMockBluecatHostRecord("whitespace.example.com", "123.123.123.124"), + }, + mockBluecatCNAMEs: &[]BluecatCNAMERecord{ + createMockBluecatCNAME("hack.example.com", "bluecatnetworks.com"), + }, + mockBluecatTXTs: &[]BluecatTXTRecord{ + createMockBluecatTXT("abc.example.com", "hello"), + }, + } + + provider := newBluecatProvider( + endpoint.NewDomainFilter([]string{"example.com"}), + provider.NewZoneIDFilter([]string{""}), false, client) + + // Test txt records for recordSet function + testTxtEndpoint := endpoint.NewEndpoint("abc.example.com", endpoint.RecordTypeTXT, "hello") + txtObj := bluecatCreateTXTRecordRequest{ + AbsoluteName: testTxtEndpoint.DNSName, + Text: testTxtEndpoint.Targets[0], + } + txtRecords := []BluecatTXTRecord{ + createMockBluecatTXT("abc.example.com", "hello"), + } + expected := bluecatRecordSet{ + obj: &txtObj, + res: &txtRecords, + } + actual, err := provider.recordSet(testTxtEndpoint, true) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, actual.obj, expected.obj) + assert.Equal(t, actual.res, expected.res) + + // Test a records for recordSet function + testHostEndpoint := endpoint.NewEndpoint("whitespace.example.com", endpoint.RecordTypeA, "123.123.123.124") + hostObj := bluecatCreateHostRecordRequest{ + AbsoluteName: testHostEndpoint.DNSName, + IP4Address: testHostEndpoint.Targets[0], + } + hostRecords := []BluecatHostRecord{ + createMockBluecatHostRecord("whitespace.example.com", "123.123.123.124"), + } + hostExpected := bluecatRecordSet{ + obj: &hostObj, + res: &hostRecords, + } + hostActual, err := provider.recordSet(testHostEndpoint, true) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, hostActual.obj, hostExpected.obj) + assert.Equal(t, hostActual.res, hostExpected.res) + + // Test CName records for recordSet function + testCnameEndpoint := endpoint.NewEndpoint("hack.example.com", endpoint.RecordTypeCNAME, "bluecatnetworks.com") + cnameObj := bluecatCreateCNAMERecordRequest{ + AbsoluteName: testCnameEndpoint.DNSName, + LinkedRecord: testCnameEndpoint.Targets[0], + } + cnameRecords := []BluecatCNAMERecord{ + createMockBluecatCNAME("hack.example.com", "bluecatnetworks.com"), + } + cnameExpected := bluecatRecordSet{ + obj: &cnameObj, + res: &cnameRecords, + } + cnameActual, err := provider.recordSet(testCnameEndpoint, true) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, cnameActual.obj, cnameExpected.obj) + assert.Equal(t, cnameActual.res, cnameExpected.res) +} + +func validateEndpoints(t *testing.T, actual, expected []*endpoint.Endpoint) { + assert.True(t, testutils.SameEndpoints(actual, expected), "actual and expected endpoints don't match. %s:%s", actual, expected) +} From 0b8e047d2e025225b422851ae5ba3c7276524cd0 Mon Sep 17 00:00:00 2001 From: stovemeerkat Date: Thu, 18 Mar 2021 11:36:46 +0100 Subject: [PATCH 079/175] rfc2136: Add new flag to specify Kerberos realm for GSS-TSIG --- main.go | 2 +- pkg/apis/externaldns/types.go | 3 +++ provider/rfc2136/rfc2136.go | 8 ++++++-- provider/rfc2136/rfc2136_test.go | 2 +- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/main.go b/main.go index 09860c08d..0773cc619 100644 --- a/main.go +++ b/main.go @@ -283,7 +283,7 @@ func main() { p, err = oci.NewOCIProvider(*config, domainFilter, zoneIDFilter, cfg.DryRun) } case "rfc2136": - p, err = rfc2136.NewRfc2136Provider(cfg.RFC2136Host, cfg.RFC2136Port, cfg.RFC2136Zone, cfg.RFC2136Insecure, cfg.RFC2136TSIGKeyName, cfg.RFC2136TSIGSecret, cfg.RFC2136TSIGSecretAlg, cfg.RFC2136TAXFR, domainFilter, cfg.DryRun, cfg.RFC2136MinTTL, cfg.RFC2136GSSTSIG, cfg.RFC2136KerberosUsername, cfg.RFC2136KerberosPassword, nil) + p, err = rfc2136.NewRfc2136Provider(cfg.RFC2136Host, cfg.RFC2136Port, cfg.RFC2136Zone, cfg.RFC2136Insecure, cfg.RFC2136TSIGKeyName, cfg.RFC2136TSIGSecret, cfg.RFC2136TSIGSecretAlg, cfg.RFC2136TAXFR, domainFilter, cfg.DryRun, cfg.RFC2136MinTTL, cfg.RFC2136GSSTSIG, cfg.RFC2136KerberosRealm, cfg.RFC2136KerberosUsername, cfg.RFC2136KerberosPassword, nil) case "ns1": p, err = ns1.NewNS1Provider( ns1.NS1Config{ diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index b8d43f462..5fc354a1d 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -142,6 +142,7 @@ type Config struct { RFC2136Zone string RFC2136Insecure bool RFC2136GSSTSIG bool + RFC2136KerberosRealm string RFC2136KerberosUsername string RFC2136KerberosPassword string RFC2136TSIGKeyName string @@ -255,6 +256,7 @@ var defaultConfig = &Config{ RFC2136Zone: "", RFC2136Insecure: false, RFC2136GSSTSIG: false, + RFC2136KerberosRealm: "", RFC2136KerberosUsername: "", RFC2136KerberosPassword: "", RFC2136TSIGKeyName: "", @@ -434,6 +436,7 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("rfc2136-tsig-axfr", "When using the RFC2136 provider, specify the TSIG (base64) value to attached to DNS messages (required when --rfc2136-insecure=false)").BoolVar(&cfg.RFC2136TAXFR) app.Flag("rfc2136-min-ttl", "When using the RFC2136 provider, specify minimal TTL (in duration format) for records. This value will be used if the provided TTL for a service/ingress is lower than this").Default(defaultConfig.RFC2136MinTTL.String()).DurationVar(&cfg.RFC2136MinTTL) app.Flag("rfc2136-gss-tsig", "When using the RFC2136 provider, specify whether to use secure updates with GSS-TSIG using Kerberos (default: false, requires --rfc2136-kerberos-username and rfc2136-kerberos-password)").Default(strconv.FormatBool(defaultConfig.RFC2136GSSTSIG)).BoolVar(&cfg.RFC2136GSSTSIG) + app.Flag("rfc2136-kerberos-realm", "When using the RFC2136 provider with GSS-TSIG, specify the Kerberos realm used for authentication (default: the value of --rfc2316-zone converted to uppercase)").Default(defaultConfig.RFC2136KerberosRealm).StringVar(&cfg.RFC2136KerberosRealm) app.Flag("rfc2136-kerberos-username", "When using the RFC2136 provider with GSS-TSIG, specify the username of the user with permissions to update DNS records (required when --rfc2136-gss-tsig=true)").Default(defaultConfig.RFC2136KerberosUsername).StringVar(&cfg.RFC2136KerberosUsername) app.Flag("rfc2136-kerberos-password", "When using the RFC2136 provider with GSS-TSIG, specify the password of the user with permissions to update DNS records (required when --rfc2136-gss-tsig=true)").Default(defaultConfig.RFC2136KerberosPassword).StringVar(&cfg.RFC2136KerberosPassword) diff --git a/provider/rfc2136/rfc2136.go b/provider/rfc2136/rfc2136.go index 611261160..893c98be1 100644 --- a/provider/rfc2136/rfc2136.go +++ b/provider/rfc2136/rfc2136.go @@ -85,12 +85,16 @@ type rfc2136Actions interface { } // NewRfc2136Provider is a factory function for OpenStack rfc2136 providers -func NewRfc2136Provider(host string, port int, zoneName string, insecure bool, keyName string, secret string, secretAlg string, axfr bool, domainFilter endpoint.DomainFilter, dryRun bool, minTTL time.Duration, gssTsig bool, krb5Username string, krb5Password string, actions rfc2136Actions) (provider.Provider, error) { +func NewRfc2136Provider(host string, port int, zoneName string, insecure bool, keyName string, secret string, secretAlg string, axfr bool, domainFilter endpoint.DomainFilter, dryRun bool, minTTL time.Duration, gssTsig bool, krb5Realm string, krb5Username string, krb5Password string, actions rfc2136Actions) (provider.Provider, error) { secretAlgChecked, ok := tsigAlgs[secretAlg] if !ok && !insecure && !gssTsig { return nil, errors.Errorf("%s is not supported TSIG algorithm", secretAlg) } + if krb5Realm == "" { + krb5Realm = strings.ToUpper(zoneName) + } + r := &rfc2136Provider{ nameserver: net.JoinHostPort(host, strconv.Itoa(port)), zoneName: dns.Fqdn(zoneName), @@ -98,7 +102,7 @@ func NewRfc2136Provider(host string, port int, zoneName string, insecure bool, k gssTsig: gssTsig, krb5Username: krb5Username, krb5Password: krb5Password, - krb5Realm: strings.ToUpper(zoneName), + krb5Realm: krb5Realm, domainFilter: domainFilter, dryRun: dryRun, axfr: axfr, diff --git a/provider/rfc2136/rfc2136_test.go b/provider/rfc2136/rfc2136_test.go index 1df3ea1c6..59d3ea818 100644 --- a/provider/rfc2136/rfc2136_test.go +++ b/provider/rfc2136/rfc2136_test.go @@ -95,7 +95,7 @@ func (r *rfc2136Stub) IncomeTransfer(m *dns.Msg, a string) (env chan *dns.Envelo } func createRfc2136StubProvider(stub *rfc2136Stub) (provider.Provider, error) { - return NewRfc2136Provider("", 0, "", false, "key", "secret", "hmac-sha512", true, endpoint.DomainFilter{}, false, 300*time.Second, false, "", "", stub) + return NewRfc2136Provider("", 0, "", false, "key", "secret", "hmac-sha512", true, endpoint.DomainFilter{}, false, 300*time.Second, false, "", "", "", stub) } func extractAuthoritySectionFromMessage(msg fmt.Stringer) []string { From 098cedb7f98094ac58fa20adb6c775a9a965e818 Mon Sep 17 00:00:00 2001 From: stovemeerkat Date: Thu, 18 Mar 2021 12:07:36 +0100 Subject: [PATCH 080/175] docs: Update and improve tutorial for the RFC2136 provider --- docs/tutorials/rfc2136.md | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/docs/tutorials/rfc2136.md b/docs/tutorials/rfc2136.md index 923477813..d352dee61 100644 --- a/docs/tutorials/rfc2136.md +++ b/docs/tutorials/rfc2136.md @@ -287,7 +287,7 @@ While `external-dns` was not developed or tested against Microsoft DNS, it can b 1. Create a DNS zone 2. Enable insecure dynamic updates for the zone -3. Enable Zone Transfers from all servers +3. Enable Zone Transfers to all servers #### `external-dns` configuration @@ -310,8 +310,10 @@ You'll want to configure `external-dns` similarly to the following: 1. Create a DNS zone 2. Enable secure dynamic updates for the zone -3. Enable Zone Transfers from all servers +3. Enable Zone Transfers to all servers +If you see any error messages which indicate that `external-dns` was somehow not able to fetch +existing DNS records from your DNS server, this could mean that you forgot about step 3. #### Kerberos Configuration @@ -339,18 +341,20 @@ data: pkinit_anchors = /etc/pki/tls/certs/ca-bundle.crt default_ccache_name = KEYRING:persistent:%{uid} - default_realm = YOURDOMAIN.COM + default_realm = YOUR-REALM.COM [realms] - YOURDOMAIN.COM = { + YOUR-REALM.COM = { kdc = dc1.yourdomain.com admin_server = dc1.yourdomain.com } [domain_realm] - yourdomain.com = YOURDOMAIN.COM - .yourdomain.com = YOURDOMAIN.COM + yourdomain.com = YOUR-REALM.COM + .yourdomain.com = YOUR-REALM.COM ``` +In most cases, the realm name will probably be the same as the domain name, so you can simply replace +`YOUR-REALM.COM` with something like `YOURDOMAIN.COM`. Once the ConfigMap is created, the container `external-dns` container needs to be told to mount that ConfigMap as a volume at the default Kerberos configuration location. The pod spec should include a similar configuration to the following: @@ -376,11 +380,22 @@ You'll want to configure `external-dns` similarly to the following: ```text ... - --provider=rfc2136 - - --rfc2136-host=123.123.123.123 + - --rfc2136-host=dns-host.yourdomain.com - --rfc2136-port=53 - --rfc2136-zone=your-domain.com + - --rfc2136-gss-tsig + - --rfc2136-kerberos-realm=YOUR-REALM.COM # optional; use if your realm's name differs from the DNS zone - --rfc2136-kerberos-username=your-domain-account - --rfc2136-kerberos-password=your-domain-password - --rfc2136-tsig-axfr # needed to enable zone transfers, which is required for deletion of records. ... ``` + +As noted above, the `--rfc2136-kerberos-realm` flag is completely optional and won't be necessary in many cases. +Most likely, you will only need it if you see errors similar to this: `KRB Error: (68) KDC_ERR_WRONG_REALM Reserved for future use`. + +The flag `--rfc2136-host` can be set to the host's domain name or IP address. +However, it also determines the name of the Kerberos principal which is used during authentication. +This means that Active Directory might only work if this is set to a specific domain name, possibly leading to errors like this: +`KDC_ERR_S_PRINCIPAL_UNKNOWN Server not found in Kerberos database`. +To fix this, try setting `--rfc2136-host` to the "actual" hostname of your DNS server. From ecbcf27e355b1b83b8abbe7f2cd528a0e66274b6 Mon Sep 17 00:00:00 2001 From: Brock Alberry <61976254+ba-work@users.noreply.github.com> Date: Thu, 18 Mar 2021 18:12:53 +0000 Subject: [PATCH 081/175] remove double type definition --- pkg/apis/externaldns/types.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index d61415477..a179fc82a 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -147,7 +147,6 @@ type Config struct { RFC2136KerberosRealm string RFC2136KerberosUsername string RFC2136KerberosPassword string - RFC2136KerberosRealm string RFC2136TSIGKeyName string RFC2136TSIGSecret string `secure:"yes"` RFC2136TSIGSecretAlg string From 9729a5370644d4b7e3fb954c4c0f0bd33444b0ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20St=C3=A4hlin?= Date: Thu, 18 Mar 2021 19:17:20 +0100 Subject: [PATCH 082/175] Fix CNAME update for hetzner provider The name conditioning was applied twice which caused CNAMES to be suffixed by a double '.'. This leads to the value being rejected by an error 422 which is not returned as an error by the hcloud-dns library. --- provider/hetzner/hetzner.go | 8 ---- provider/hetzner/hetzner_test.go | 82 ++++++++++++++++++++++++++++++-- 2 files changed, 77 insertions(+), 13 deletions(-) diff --git a/provider/hetzner/hetzner.go b/provider/hetzner/hetzner.go index c26a32332..4e84c122a 100644 --- a/provider/hetzner/hetzner.go +++ b/provider/hetzner/hetzner.go @@ -152,14 +152,6 @@ func (p *HetznerProvider) submitChanges(ctx context.Context, changes []*HetznerC "zone_id": change.ZoneID, }).Info("Changing record") - change.ResourceRecordSet.Name = strings.TrimSuffix(change.ResourceRecordSet.Name, "."+change.ZoneName) - if change.ResourceRecordSet.Name == change.ZoneName { - change.ResourceRecordSet.Name = "@" - } - if change.ResourceRecordSet.RecordType == endpoint.RecordTypeCNAME { - change.ResourceRecordSet.Value += "." - } - switch change.Action { case hetznerCreate: record := hclouddns.HCloudRecord{ diff --git a/provider/hetzner/hetzner_test.go b/provider/hetzner/hetzner_test.go index a0db75492..9ef5c92e8 100644 --- a/provider/hetzner/hetzner_test.go +++ b/provider/hetzner/hetzner_test.go @@ -16,6 +16,7 @@ package hetzner import ( "context" "fmt" + "github.com/maxatome/go-testdeep/td" "os" "reflect" "testing" @@ -45,12 +46,18 @@ type mockHCloudClientAdapter interface { UpdateRecordBulk(record []hclouddns.HCloudRecord) (hclouddns.HCloudAnswerUpdateRecords, error) } +type MockAction struct { + Name string + RecordData hclouddns.HCloudRecord +} + type mockHCloudClient struct { Token string `yaml:"token"` + Actions []MockAction } // New instance -func mockHCloudNew(t string) mockHCloudClientAdapter { +func mockHCloudNew(t string) *mockHCloudClient { return &mockHCloudClient{ Token: t, } @@ -116,12 +123,26 @@ func (m *mockHCloudClient) GetRecords(params hclouddns.HCloudGetRecordsParams) ( }, nil } func (m *mockHCloudClient) UpdateRecord(record hclouddns.HCloudRecord) (hclouddns.HCloudAnswerGetRecord, error) { + m.Actions = append(m.Actions, MockAction{ + Name: "UpdateRecord", + RecordData: record, + }) return hclouddns.HCloudAnswerGetRecord{}, nil } func (m *mockHCloudClient) DeleteRecord(ID string) (hclouddns.HCloudAnswerDeleteRecord, error) { + m.Actions = append(m.Actions, MockAction{ + Name: "DeleteRecord", + RecordData: hclouddns.HCloudRecord{ + ID: ID, + }, + }) return hclouddns.HCloudAnswerDeleteRecord{}, nil } func (m *mockHCloudClient) CreateRecord(record hclouddns.HCloudRecord) (hclouddns.HCloudAnswerGetRecord, error) { + m.Actions = append(m.Actions, MockAction{ + Name: "CreateRecord", + RecordData: record, + }) return hclouddns.HCloudAnswerGetRecord{}, nil } func (m *mockHCloudClient) CreateRecordBulk(record []hclouddns.HCloudRecord) (hclouddns.HCloudAnswerCreateRecords, error) { @@ -220,14 +241,65 @@ func TestHetznerProvider_ApplyChanges(t *testing.T) { } changes.Create = []*endpoint.Endpoint{ - {DNSName: "test.org", Targets: endpoint.Targets{"target"}}, - {DNSName: "test.test.org", Targets: endpoint.Targets{"target"}, RecordTTL: 666}, + {DNSName: "blindage.org", Targets: endpoint.Targets{"target"}}, + {DNSName: "test.blindage.org", Targets: endpoint.Targets{"target"}, RecordTTL: 666}, } - changes.UpdateNew = []*endpoint.Endpoint{{DNSName: "test.test.org", Targets: endpoint.Targets{"target-new"}, RecordType: "A", RecordTTL: 777}} - changes.Delete = []*endpoint.Endpoint{{DNSName: "test.test.org", Targets: endpoint.Targets{"target"}, RecordType: "A"}} + changes.UpdateNew = []*endpoint.Endpoint{{DNSName: "test.blindage.org", Targets: endpoint.Targets{"target-new"}, RecordType: "A", RecordTTL: 777}} + changes.Delete = []*endpoint.Endpoint{{DNSName: "test.blindage.org", Targets: endpoint.Targets{"target"}, RecordType: "A"}} err := mockedProvider.ApplyChanges(context.Background(), changes) if err != nil { t.Errorf("should not fail, %s", err) } + + if len(mockedClient.Actions) != 4 { + t.Errorf("should be 4 changes not %d", len(mockedClient.Actions)) + } +} + +func TestHetznerProvider_ApplyChangesCreateUpdateCname(t *testing.T) { + changes := &plan.Changes{} + mockedClient := mockHCloudNew("myHetznerToken") + mockedProvider := &HetznerProvider{ + Client: mockedClient, + } + + changes.Create = []*endpoint.Endpoint{ + {DNSName: "test-cname.blindage.org", Targets: endpoint.Targets{"target"}, RecordTTL: 666, RecordType: "CNAME"}, + } + changes.UpdateNew = []*endpoint.Endpoint{{DNSName: "test-cname2.blindage.org", Targets: endpoint.Targets{"target-new"}, RecordType: "CNAME", RecordTTL: 777}} + + err := mockedProvider.ApplyChanges(context.Background(), changes) + if err != nil { + t.Errorf("should not fail, %s", err) + } + + td.Cmp(t, mockedClient.Actions, []MockAction{ + { + Name: "CreateRecord", + RecordData: hclouddns.HCloudRecord{ + RecordType: "CNAME", + ID: "", + Created: "", + Modified: "", + ZoneID: "HetznerZoneID", + Name: "test-cname", + Value: "target.", + TTL: 666, + }, + }, + { + Name: "UpdateRecord", + RecordData: hclouddns.HCloudRecord{ + RecordType: "CNAME", + ID: "", + Created: "", + Modified: "", + ZoneID: "HetznerZoneID", + Name: "test-cname2", + Value: "target-new.", + TTL: 777, + }, + }, + }) } From 88917956fad6b31223bc7529470b23068b70de18 Mon Sep 17 00:00:00 2001 From: Timtor Chen Date: Fri, 19 Mar 2021 17:21:11 +0800 Subject: [PATCH 083/175] Update the usage of annotation-filter Signed-off-by: Timtor Chen --- docs/faq.md | 4 ++-- docs/tutorials/public-private-route53.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/faq.md b/docs/faq.md index 32eee328c..f743f89dc 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -258,8 +258,8 @@ one to expose DNS to the internet. To do this with ExternalDNS you can use the `--annotation-filter` to specifically tie an instance of ExternalDNS to an instance of a ingress controller. Let's assume you have two ingress controllers `nginx-internal` and `nginx-external` -then you can start two ExternalDNS providers one with `--annotation-filter=kubernetes.io/ingress.class=nginx-internal` -and one with `--annotation-filter=kubernetes.io/ingress.class=nginx-external`. +then you can start two ExternalDNS providers one with `--annotation-filter=kubernetes.io/ingress.class in (nginx-internal)` +and one with `--annotation-filter=kubernetes.io/ingress.class in (nginx-external)`. ### Can external-dns manage(add/remove) records in a hosted zone which is setup in different AWS account? diff --git a/docs/tutorials/public-private-route53.md b/docs/tutorials/public-private-route53.md index 179c59582..b9d1525b2 100644 --- a/docs/tutorials/public-private-route53.md +++ b/docs/tutorials/public-private-route53.md @@ -241,7 +241,7 @@ spec: - --provider=aws - --registry=txt - --txt-owner-id=external-dns - - --annotation-filter=kubernetes.io/ingress.class=external-ingress + - --annotation-filter=kubernetes.io/ingress.class in (external-ingress) - --aws-zone-type=public image: registry.opensource.zalan.do/teapot/external-dns:latest name: external-dns-public @@ -279,7 +279,7 @@ spec: - --provider=aws - --registry=txt - --txt-owner-id=dev.k8s.nexus - - --annotation-filter=kubernetes.io/ingress.class=internal-ingress + - --annotation-filter=kubernetes.io/ingress.class in (internal-ingress) - --aws-zone-type=private image: registry.opensource.zalan.do/teapot/external-dns:latest name: external-dns-private From ae1c2fa892ca91a6cb976cd00cded536d8266458 Mon Sep 17 00:00:00 2001 From: Bittrance Date: Sat, 20 Mar 2021 00:30:12 +0100 Subject: [PATCH 084/175] Downgrade Azure provider "Failed to extract" log to debug When running the Azure provider at default log level, this messages is 1/min and is the only messge in the log. Debug seems more reasonable and matches what Azure Private provider. --- provider/azure/azure.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/provider/azure/azure.go b/provider/azure/azure.go index 455179d9c..2b2ff2924 100644 --- a/provider/azure/azure.go +++ b/provider/azure/azure.go @@ -119,7 +119,7 @@ func (p *AzureProvider) Records(ctx context.Context) (endpoints []*endpoint.Endp } targets := extractAzureTargets(&recordSet) if len(targets) == 0 { - log.Errorf("Failed to extract targets for '%s' with type '%s'.", name, recordType) + log.Debugf("Failed to extract targets for '%s' with type '%s'.", name, recordType) return true } var ttl endpoint.TTL From bc5232d02c5f7adef4f1e699f5649f0a4934083c Mon Sep 17 00:00:00 2001 From: Patrik Cyvoct Date: Mon, 22 Mar 2021 10:42:48 +0100 Subject: [PATCH 085/175] fix(scaleway): drop support for organization ID as it's not needed Signed-off-by: Patrik Cyvoct --- provider/scaleway/scaleway.go | 4 ---- provider/scaleway/scaleway_test.go | 14 -------------- 2 files changed, 18 deletions(-) diff --git a/provider/scaleway/scaleway.go b/provider/scaleway/scaleway.go index 12cbf1620..c145d5fe2 100644 --- a/provider/scaleway/scaleway.go +++ b/provider/scaleway/scaleway.go @@ -63,10 +63,6 @@ func NewScalewayProvider(ctx context.Context, domainFilter endpoint.DomainFilter return nil, err } - if _, ok := scwClient.GetDefaultOrganizationID(); !ok { - return nil, fmt.Errorf("default organization is not set") - } - if _, ok := scwClient.GetAccessKey(); !ok { return nil, fmt.Errorf("access key no set") } diff --git a/provider/scaleway/scaleway_test.go b/provider/scaleway/scaleway_test.go index c9ca99112..a6276a309 100644 --- a/provider/scaleway/scaleway_test.go +++ b/provider/scaleway/scaleway_test.go @@ -113,26 +113,12 @@ func (m *mockScalewayDomain) UpdateDNSZoneRecords(req *domain.UpdateDNSZoneRecor func TestScalewayProvider_NewScalewayProvider(t *testing.T) { _ = os.Setenv(scw.ScwAccessKeyEnv, "SCWXXXXXXXXXXXXXXXXX") _ = os.Setenv(scw.ScwSecretKeyEnv, "11111111-1111-1111-1111-111111111111") - _ = os.Setenv(scw.ScwDefaultOrganizationIDEnv, "11111111-1111-1111-1111-111111111111") _, err := NewScalewayProvider(context.TODO(), endpoint.NewDomainFilter([]string{"example.com"}), true) if err != nil { t.Errorf("failed : %s", err) } - _ = os.Unsetenv(scw.ScwDefaultOrganizationIDEnv) - _, err = NewScalewayProvider(context.TODO(), endpoint.NewDomainFilter([]string{"example.com"}), true) - if err == nil { - t.Errorf("expected to fail") - } - - _ = os.Setenv(scw.ScwDefaultOrganizationIDEnv, "dummy") - _, err = NewScalewayProvider(context.TODO(), endpoint.NewDomainFilter([]string{"example.com"}), true) - if err == nil { - t.Errorf("expected to fail") - } - _ = os.Unsetenv(scw.ScwSecretKeyEnv) - _ = os.Setenv(scw.ScwDefaultOrganizationIDEnv, "11111111-1111-1111-1111-111111111111") _, err = NewScalewayProvider(context.TODO(), endpoint.NewDomainFilter([]string{"example.com"}), true) if err == nil { t.Errorf("expected to fail") From 4345ce6a31c21722cfd9842b1f31a4e827825a1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffen=20P=C3=B8hner=20Henriksen?= Date: Thu, 9 Jan 2020 15:08:07 +0100 Subject: [PATCH 086/175] AWS: fix handling of alias records --- provider/aws/aws.go | 86 +++++++++++++++++++++++++++++----------- provider/aws/aws_test.go | 59 +++++++++++++-------------- 2 files changed, 90 insertions(+), 55 deletions(-) diff --git a/provider/aws/aws.go b/provider/aws/aws.go index 2581af2a1..0cc02d237 100644 --- a/provider/aws/aws.go +++ b/provider/aws/aws.go @@ -42,6 +42,8 @@ const ( recordTTL = 300 // provider specific key that designates whether an AWS ALIAS record has the EvaluateTargetHealth // field set to true. + providerSpecificAlias = "alias" + providerSpecificTargetHostedZone = "aws/target-hosted-zone" providerSpecificEvaluateTargetHealth = "aws/evaluate-target-health" providerSpecificWeight = "aws/weight" providerSpecificRegion = "aws/region" @@ -51,6 +53,7 @@ const ( providerSpecificGeolocationSubdivisionCode = "aws/geolocation-subdivision-code" providerSpecificMultiValueAnswer = "aws/multi-value-answer" providerSpecificHealthCheckID = "aws/health-check-id" + sameZoneAlias = "same-zone" ) var ( @@ -330,7 +333,8 @@ func (p *AWSProvider) records(ctx context.Context, zones map[string]*route53.Hos } ep := endpoint. NewEndpointWithTTL(wildcardUnescape(aws.StringValue(r.Name)), endpoint.RecordTypeCNAME, ttl, aws.StringValue(r.AliasTarget.DNSName)). - WithProviderSpecific(providerSpecificEvaluateTargetHealth, fmt.Sprintf("%t", aws.BoolValue(r.AliasTarget.EvaluateTargetHealth))) + WithProviderSpecific(providerSpecificEvaluateTargetHealth, fmt.Sprintf("%t", aws.BoolValue(r.AliasTarget.EvaluateTargetHealth))). + WithProviderSpecific(providerSpecificAlias, "true") newEndpoints = append(newEndpoints, ep) } @@ -398,6 +402,8 @@ func (p *AWSProvider) DeleteRecords(ctx context.Context, endpoints []*endpoint.E func (p *AWSProvider) doRecords(ctx context.Context, action string, endpoints []*endpoint.Endpoint) error { zones, err := p.Zones(ctx) + p.AdjustEndpoints(endpoints) + if err != nil { return errors.Wrapf(err, "failed to list zones, aborting %s doRecords action", action) } @@ -555,6 +561,31 @@ func (p *AWSProvider) newChanges(action string, endpoints []*endpoint.Endpoint, return changes } +func (p *AWSProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) []*endpoint.Endpoint { + for _, ep := range endpoints { + alias := false + if _, ok := ep.GetProviderSpecificProperty(providerSpecificAlias); ok { + alias = true + } else if useAlias(ep, p.preferCNAME) { + alias = true + log.Debugf("Modifying endpoint: %v, setting %s=true", ep, providerSpecificAlias) + ep.ProviderSpecific = append(ep.ProviderSpecific, endpoint.ProviderSpecificProperty{ + Name: providerSpecificAlias, + Value: "true", + }) + } + + if _, ok := ep.GetProviderSpecificProperty(providerSpecificEvaluateTargetHealth); alias && !ok { + log.Debugf("Modifying endpoint: %v, setting %s=%t", ep, providerSpecificEvaluateTargetHealth, p.evaluateTargetHealth) + ep.ProviderSpecific = append(ep.ProviderSpecific, endpoint.ProviderSpecificProperty{ + Name: providerSpecificEvaluateTargetHealth, + Value: fmt.Sprintf("%t", p.evaluateTargetHealth), + }) + } + } + return endpoints +} + // newChange returns a route53 Change and a boolean indicating if there should also be a change to a AAAA record // returned Change is based on the given record by the given action, e.g. // action=ChangeActionCreate returns a change for creation of the record and @@ -567,8 +598,7 @@ func (p *AWSProvider) newChange(action string, ep *endpoint.Endpoint, recordsCac }, } dualstack := false - - if useAlias(ep, p.preferCNAME) { + if targetHostedZone := isAWSAlias(ep); targetHostedZone != "" { evalTargetHealth := p.evaluateTargetHealth if prop, ok := ep.GetProviderSpecificProperty(providerSpecificEvaluateTargetHealth); ok { evalTargetHealth = prop.Value == "true" @@ -577,22 +607,12 @@ func (p *AWSProvider) newChange(action string, ep *endpoint.Endpoint, recordsCac if val, ok := ep.Labels[endpoint.DualstackLabelKey]; ok { dualstack = val == "true" } - change.ResourceRecordSet.Type = aws.String(route53.RRTypeA) change.ResourceRecordSet.AliasTarget = &route53.AliasTarget{ DNSName: aws.String(ep.Targets[0]), - HostedZoneId: aws.String(canonicalHostedZone(ep.Targets[0])), + HostedZoneId: aws.String(cleanZoneID(targetHostedZone)), EvaluateTargetHealth: aws.Bool(evalTargetHealth), } - } else if hostedZone := isAWSAlias(ep, recordsCache); hostedZone != "" { - for _, zone := range zones { - change.ResourceRecordSet.Type = aws.String(route53.RRTypeA) - change.ResourceRecordSet.AliasTarget = &route53.AliasTarget{ - DNSName: aws.String(ep.Targets[0]), - HostedZoneId: aws.String(cleanZoneID(*zone.Id)), - EvaluateTargetHealth: aws.Bool(p.evaluateTargetHealth), - } - } } else { change.ResourceRecordSet.Type = aws.String(ep.RecordType) if !ep.RecordTTL.IsConfigured() { @@ -756,6 +776,18 @@ func changesByZone(zones map[string]*route53.HostedZone, changeSet []*route53.Ch continue } for _, z := range zones { + if c.ResourceRecordSet.AliasTarget != nil && aws.StringValue(c.ResourceRecordSet.AliasTarget.HostedZoneId) == sameZoneAlias { + // alias record is to be created; target needs to be in the same zone as endpoint + // if it's not, this will fail + rrset := *c.ResourceRecordSet + aliasTarget := *rrset.AliasTarget + aliasTarget.HostedZoneId = aws.String(cleanZoneID(aws.StringValue(z.Id))) + rrset.AliasTarget = &aliasTarget + c = &route53.Change{ + Action: c.Action, + ResourceRecordSet: &rrset, + } + } changes[aws.StringValue(z.Id)] = append(changes[aws.StringValue(z.Id)], c) log.Debugf("Adding %s to zone %s [Id: %s]", hostname, aws.StringValue(z.Name), aws.StringValue(z.Id)) } @@ -811,16 +843,24 @@ func useAlias(ep *endpoint.Endpoint, preferCNAME bool) bool { return false } -// isAWSAlias determines if a given hostname belongs to an AWS Alias record by doing an reverse lookup. -func isAWSAlias(ep *endpoint.Endpoint, addrs []*endpoint.Endpoint) string { - if prop, exists := ep.GetProviderSpecificProperty("alias"); ep.RecordType == endpoint.RecordTypeCNAME && exists && prop.Value == "true" { - for _, addr := range addrs { - if len(ep.Targets) > 0 && addr.DNSName == ep.Targets[0] { - if hostedZone := canonicalHostedZone(addr.Targets[0]); hostedZone != "" { - return hostedZone - } - } +// isAWSAlias determines if a given hostname is an AWS Alias record +func isAWSAlias(ep *endpoint.Endpoint) string { + prop, exists := ep.GetProviderSpecificProperty(providerSpecificAlias) + if exists && prop.Value == "true" && ep.RecordType == endpoint.RecordTypeCNAME && len(ep.Targets) > 0 { + // alias records can only point to canonical hosted zones (e.g. to ELBs) or other records in the same zone + + if hostedZoneID, ok := ep.GetProviderSpecificProperty(providerSpecificTargetHostedZone); ok { + // existing Endpoint where we got the target hosted zone from the Route53 data + return hostedZoneID.Value } + + // check if the target is in a canonical hosted zone + if canonicalHostedZone := canonicalHostedZone(ep.Targets[0]); canonicalHostedZone != "" { + return canonicalHostedZone + } + + // if not, target needs to be in the same zone + return sameZoneAlias } return "" } diff --git a/provider/aws/aws_test.go b/provider/aws/aws_test.go index 40e522a49..efc806f97 100644 --- a/provider/aws/aws_test.go +++ b/provider/aws/aws_test.go @@ -337,9 +337,9 @@ func TestAWSRecords(t *testing.T) { endpoint.NewEndpointWithTTL("list-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4"), endpoint.NewEndpointWithTTL("list-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8"), endpoint.NewEndpointWithTTL("*.wildcard-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8"), - endpoint.NewEndpointWithTTL("list-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false"), - endpoint.NewEndpointWithTTL("*.wildcard-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false"), - endpoint.NewEndpointWithTTL("list-test-alias-evaluate.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true"), + endpoint.NewEndpointWithTTL("list-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"), + endpoint.NewEndpointWithTTL("*.wildcard-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false").WithProviderSpecific(providerSpecificAlias, "true"), + endpoint.NewEndpointWithTTL("list-test-alias-evaluate.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true").WithProviderSpecific(providerSpecificAlias, "true"), endpoint.NewEndpointWithTTL("list-test-multiple.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8", "8.8.4.4"), endpoint.NewEndpointWithTTL("prefix-*.wildcard.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeTXT, endpoint.TTL(recordTTL), "random"), endpoint.NewEndpointWithTTL("weight-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4").WithSetIdentifier("test-set-1").WithProviderSpecific(providerSpecificWeight, "10"), @@ -361,8 +361,10 @@ func TestAWSCreateRecords(t *testing.T) { records := []*endpoint.Endpoint{ endpoint.NewEndpoint("create-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "1.2.3.4"), endpoint.NewEndpoint("create-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "8.8.8.8"), - endpoint.NewEndpointWithTTL("create-test-cname-custom-ttl.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, customTTL, "172.17.0.1"), - endpoint.NewEndpoint("create-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.elb.amazonaws.com"), + endpoint.NewEndpointWithTTL("create-test-custom-ttl.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, customTTL, "172.17.0.1"), + endpoint.NewEndpoint("create-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.example.com"), + endpoint.NewEndpoint("create-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com"), + endpoint.NewEndpoint("create-test-cname-alias.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "alias-target.zone-2.ext-dns-test-2.teapot.zalan.do").WithProviderSpecific(providerSpecificAlias, "true"), endpoint.NewEndpoint("create-test-multiple.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "8.8.8.8", "8.8.4.4"), } @@ -374,8 +376,10 @@ func TestAWSCreateRecords(t *testing.T) { validateEndpoints(t, records, []*endpoint.Endpoint{ endpoint.NewEndpointWithTTL("create-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4"), endpoint.NewEndpointWithTTL("create-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8"), - endpoint.NewEndpointWithTTL("create-test-cname-custom-ttl.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, customTTL, "172.17.0.1"), - endpoint.NewEndpointWithTTL("create-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "foo.elb.amazonaws.com"), + endpoint.NewEndpointWithTTL("create-test-custom-ttl.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, customTTL, "172.17.0.1"), + endpoint.NewEndpointWithTTL("create-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "foo.example.com"), + endpoint.NewEndpointWithTTL("create-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true").WithProviderSpecific(providerSpecificAlias, "true"), + endpoint.NewEndpointWithTTL("create-test-cname-alias.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "alias-target.zone-2.ext-dns-test-2.teapot.zalan.do").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true").WithProviderSpecific(providerSpecificAlias, "true"), endpoint.NewEndpointWithTTL("create-test-multiple.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8", "8.8.4.4"), }) } @@ -425,6 +429,7 @@ func TestAWSDeleteRecords(t *testing.T) { endpoint.NewEndpointWithTTL("delete-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "baz.elb.amazonaws.com"), endpoint.NewEndpoint("delete-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false"), endpoint.NewEndpoint("delete-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true"), + endpoint.NewEndpoint("delete-test-cname-alias.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "delete-test.zone-2.ext-dns-test-2.teapot.zalan.do").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true").WithProviderSpecific(providerSpecificAlias, "true").WithProviderSpecific(providerSpecificTargetHostedZone, "/hostedzone/zone-2.ext-dns-test-2.teapot.zalan.do."), endpoint.NewEndpointWithTTL("delete-test-multiple.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.8.8", "8.8.4.4"), } @@ -461,7 +466,7 @@ func TestAWSApplyChanges(t *testing.T) { endpoint.NewEndpointWithTTL("update-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.4.4"), endpoint.NewEndpointWithTTL("delete-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.4.4"), endpoint.NewEndpointWithTTL("update-test-a-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.1.1.1"), - endpoint.NewEndpointWithTTL("update-test-alias-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "foo.eu-central-1.elb.amazonaws.com"), + endpoint.NewEndpointWithTTL("update-test-alias-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true"), endpoint.NewEndpointWithTTL("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "bar.elb.amazonaws.com"), endpoint.NewEndpointWithTTL("delete-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "qux.elb.amazonaws.com"), endpoint.NewEndpointWithTTL("update-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "bar.elb.amazonaws.com"), @@ -482,7 +487,7 @@ func TestAWSApplyChanges(t *testing.T) { endpoint.NewEndpoint("update-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "8.8.8.8"), endpoint.NewEndpoint("update-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "8.8.4.4"), endpoint.NewEndpoint("update-test-a-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "1.1.1.1"), - endpoint.NewEndpoint("update-test-alias-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com"), + endpoint.NewEndpoint("update-test-alias-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true"), endpoint.NewEndpoint("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "bar.elb.amazonaws.com"), endpoint.NewEndpoint("update-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "bar.elb.amazonaws.com"), endpoint.NewEndpoint("update-test-multiple.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "8.8.8.8", "8.8.4.4"), @@ -490,7 +495,7 @@ func TestAWSApplyChanges(t *testing.T) { updatedRecords := []*endpoint.Endpoint{ endpoint.NewEndpoint("update-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "1.2.3.4"), endpoint.NewEndpoint("update-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "4.3.2.1"), - endpoint.NewEndpoint("update-test-a-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.elb.amazonaws.com"), + endpoint.NewEndpoint("update-test-a-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true"), endpoint.NewEndpoint("update-test-alias-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "my-internal-host.example.com"), endpoint.NewEndpoint("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "baz.elb.amazonaws.com"), endpoint.NewEndpoint("update-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "baz.elb.amazonaws.com"), @@ -530,7 +535,7 @@ func TestAWSApplyChanges(t *testing.T) { endpoint.NewEndpointWithTTL("update-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4"), endpoint.NewEndpointWithTTL("create-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "8.8.4.4"), endpoint.NewEndpointWithTTL("update-test.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "4.3.2.1"), - endpoint.NewEndpointWithTTL("update-test-a-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "foo.elb.amazonaws.com"), + endpoint.NewEndpointWithTTL("update-test-a-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "foo.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true").WithProviderSpecific(providerSpecificAlias, "true"), endpoint.NewEndpointWithTTL("update-test-alias-to-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "my-internal-host.example.com"), endpoint.NewEndpointWithTTL("create-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "foo.elb.amazonaws.com"), endpoint.NewEndpointWithTTL("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "baz.elb.amazonaws.com"), @@ -841,7 +846,7 @@ func TestAWSBatchChangeSetExceedingNameChange(t *testing.T) { } func validateEndpoints(t *testing.T, endpoints []*endpoint.Endpoint, expected []*endpoint.Endpoint) { - assert.True(t, testutils.SameEndpoints(endpoints, expected), "actual and expected endpoints don't match. %s:%s", endpoints, expected) + assert.True(t, testutils.SameEndpoints(endpoints, expected), "actual and expected endpoints don't match. %+v:%+v", endpoints, expected) } func validateAWSZones(t *testing.T, zones map[string]*route53.HostedZone, expected map[string]*route53.HostedZone) { @@ -991,33 +996,23 @@ func TestAWSisAWSAlias(t *testing.T) { for _, tc := range []struct { target string recordType string - alias string - expected string + alias bool + hz string }{ - {"bar.example.org", endpoint.RecordTypeCNAME, "true", "Z215JYRZR1TBD5"}, - {"foo.example.org", endpoint.RecordTypeCNAME, "true", ""}, + {"foo.example.org", endpoint.RecordTypeCNAME, false, ""}, // normal CNAME + {"bar.eu-central-1.elb.amazonaws.com", endpoint.RecordTypeCNAME, true, "Z215JYRZR1TBD5"}, // pointing to ELB DNS name + {"foobar.example.org", endpoint.RecordTypeCNAME, true, "Z1234567890ABC"}, // HZID retrieved by Route53 + {"baz.example.org", endpoint.RecordTypeCNAME, true, sameZoneAlias}, // record to be created } { ep := &endpoint.Endpoint{ Targets: endpoint.Targets{tc.target}, RecordType: tc.recordType, - ProviderSpecific: endpoint.ProviderSpecific{ - endpoint.ProviderSpecificProperty{ - Name: "alias", - Value: tc.alias, - }, - }, } - addrs := []*endpoint.Endpoint{ - { - DNSName: "foo.example.org", - Targets: endpoint.Targets{"foobar.example.org"}, - }, - { - DNSName: "bar.example.org", - Targets: endpoint.Targets{"bar.eu-central-1.elb.amazonaws.com"}, - }, + if tc.alias { + ep = ep.WithProviderSpecific(providerSpecificAlias, "true") + ep = ep.WithProviderSpecific(providerSpecificTargetHostedZone, tc.hz) } - assert.Equal(t, tc.expected, isAWSAlias(ep, addrs)) + assert.Equal(t, tc.hz, isAWSAlias(ep), "%v", tc) } } From d0120542ca0ab4a83fa1168252af755ac2b24f5a Mon Sep 17 00:00:00 2001 From: Thibault Jamet Date: Wed, 24 Mar 2021 11:15:02 +0100 Subject: [PATCH 087/175] Use a constant 300 AWS page size --- provider/aws/aws.go | 15 ++++++++------- provider/aws/aws_test.go | 4 ++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/provider/aws/aws.go b/provider/aws/aws.go index 425bd654c..dd36d8fd8 100644 --- a/provider/aws/aws.go +++ b/provider/aws/aws.go @@ -40,6 +40,13 @@ import ( const ( recordTTL = 300 + // From the experiments, it seems that the default MaxItems applied is 100, + // and that, on the server side, there is a hard limit of 300 elements per page. + // After a discussion with AWS representants, clients should accept + // when less items are returned, and still paginate accordingly. + // As we are using the standard AWS client, this should already be compliant. + // Hence, ifever AWS decides to raise this limit, we will automatically reduce the pressure on rate limits + route53PageSize = "300" // provider specific key that designates whether an AWS ALIAS record has the EvaluateTargetHealth // field set to true. providerSpecificEvaluateTargetHealth = "aws/evaluate-target-health" @@ -376,13 +383,7 @@ func (p *AWSProvider) records(ctx context.Context, zones map[string]*route53.Hos for _, z := range zones { params := &route53.ListResourceRecordSetsInput{ HostedZoneId: z.Id, - // From the experiments, it seems that the default MaxItems applied is 100, - // and that, on the server side, there is a hard limit of 300 elements per page. - // After a discussion with AWS representants, clients should accept - // when less items are returned, and still paginate accordingly. - // As we are using the standard AWS client, this should already be compliant. - // Hence, ifever AWS decides to raise this limit, we will automatically reduce the pressure on rate limits - MaxItems: aws.String("1000"), + MaxItems: aws.String(route53PageSize), } if err := p.client.ListResourceRecordSetsPagesWithContext(ctx, params, f); err != nil { diff --git a/provider/aws/aws_test.go b/provider/aws/aws_test.go index 09259c3de..4e5d3eaa8 100644 --- a/provider/aws/aws_test.go +++ b/provider/aws/aws_test.go @@ -80,7 +80,7 @@ func NewRoute53APIStub(t *testing.T) *Route53APIStub { func (r *Route53APIStub) ListResourceRecordSetsPagesWithContext(ctx context.Context, input *route53.ListResourceRecordSetsInput, fn func(p *route53.ListResourceRecordSetsOutput, lastPage bool) (shouldContinue bool), opts ...request.Option) error { output := route53.ListResourceRecordSetsOutput{} // TODO: Support optional input args. require.NotNil(r.t, input.MaxItems) - assert.EqualValues(r.t, "1000", *input.MaxItems) + assert.EqualValues(r.t, route53PageSize, *input.MaxItems) if len(r.recordSets) == 0 { output.ResourceRecordSets = []*route53.ResourceRecordSet{} } else if _, ok := r.recordSets[aws.StringValue(input.HostedZoneId)]; !ok { @@ -1202,7 +1202,7 @@ func listAWSRecords(t *testing.T, client Route53API, zone string) []*route53.Res recordSets := []*route53.ResourceRecordSet{} require.NoError(t, client.ListResourceRecordSetsPagesWithContext(context.Background(), &route53.ListResourceRecordSetsInput{ HostedZoneId: aws.String(zone), - MaxItems: aws.String("1000"), + MaxItems: aws.String(route53PageSize), }, func(resp *route53.ListResourceRecordSetsOutput, _ bool) bool { recordSets = append(recordSets, resp.ResourceRecordSets...) return true From 43f9f564b397fe835de5ddc223e42ab41a8d1735 Mon Sep 17 00:00:00 2001 From: Thibault Jamet Date: Wed, 24 Mar 2021 11:01:18 +0100 Subject: [PATCH 088/175] Rename MinInterval to MinEventSyncInterval Co-authored-by: Raffaele Di Fazio --- controller/controller.go | 6 +++--- controller/controller_test.go | 2 +- main.go | 14 +++++++------- pkg/apis/externaldns/types.go | 6 +++--- pkg/apis/externaldns/types_test.go | 8 ++++---- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/controller/controller.go b/controller/controller.go index 8a4b47f1e..4353fe44f 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -119,8 +119,8 @@ type Controller struct { nextRunAtMux sync.Mutex // DNS record types that will be considered for management ManagedRecordTypes []string - // MinInterval is used as window for batching events - MinInterval time.Duration + // MinEventSyncInterval is used as window for batching events + MinEventSyncInterval time.Duration } // RunOnce runs a single iteration of a reconciliation loop. @@ -171,7 +171,7 @@ func (c *Controller) RunOnce(ctx context.Context) error { func (c *Controller) ScheduleRunOnce(now time.Time) { c.nextRunAtMux.Lock() defer c.nextRunAtMux.Unlock() - c.nextRunAt = now.Add(c.MinInterval) + c.nextRunAt = now.Add(c.MinEventSyncInterval) } func (c *Controller) ShouldRunOnce(now time.Time) bool { diff --git a/controller/controller_test.go b/controller/controller_test.go index a073eb75b..8c042d085 100644 --- a/controller/controller_test.go +++ b/controller/controller_test.go @@ -155,7 +155,7 @@ func TestRunOnce(t *testing.T) { } func TestShouldRunOnce(t *testing.T) { - ctrl := &Controller{Interval: 10 * time.Minute, MinInterval: 5 * time.Second} + ctrl := &Controller{Interval: 10 * time.Minute, MinEventSyncInterval: 5 * time.Second} now := time.Now() diff --git a/main.go b/main.go index dca085eeb..fa13b3cd3 100644 --- a/main.go +++ b/main.go @@ -330,13 +330,13 @@ func main() { } ctrl := controller.Controller{ - Source: endpointsSource, - Registry: r, - Policy: policy, - Interval: cfg.Interval, - DomainFilter: domainFilter, - ManagedRecordTypes: cfg.ManagedDNSRecordTypes, - MinInterval: cfg.MinInterval, + Source: endpointsSource, + Registry: r, + Policy: policy, + Interval: cfg.Interval, + DomainFilter: domainFilter, + ManagedRecordTypes: cfg.ManagedDNSRecordTypes, + MinEventSyncInterval: cfg.MinEventSyncInterval, } if cfg.Once { diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index f32dfa597..e1114a0ca 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -120,7 +120,7 @@ type Config struct { TXTPrefix string TXTSuffix string Interval time.Duration - MinInterval time.Duration + MinEventSyncInterval time.Duration Once bool DryRun bool UpdateEvents bool @@ -235,7 +235,7 @@ var defaultConfig = &Config{ TXTSuffix: "", TXTCacheInterval: 0, TXTWildcardReplacement: "", - MinInterval: 5 * time.Second, + MinEventSyncInterval: 5 * time.Second, Interval: time.Minute, Once: false, DryRun: false, @@ -456,7 +456,7 @@ func (cfg *Config) ParseFlags(args []string) error { // Flags related to the main control loop app.Flag("txt-cache-interval", "The interval between cache synchronizations in duration format (default: disabled)").Default(defaultConfig.TXTCacheInterval.String()).DurationVar(&cfg.TXTCacheInterval) app.Flag("interval", "The interval between two consecutive synchronizations in duration format (default: 1m)").Default(defaultConfig.Interval.String()).DurationVar(&cfg.Interval) - app.Flag("min-interval", "The minimum interval between two consecutive synchronizations triggered from kubernetes events in duration format (default: 5s)").Default(defaultConfig.MinInterval.String()).DurationVar(&cfg.MinInterval) + app.Flag("min-event-sync-interval", "The minimum interval between two consecutive synchronizations triggered from kubernetes events in duration format (default: 5s)").Default(defaultConfig.MinEventSyncInterval.String()).DurationVar(&cfg.MinEventSyncInterval) app.Flag("once", "When enabled, exits the synchronization loop after the first iteration (default: disabled)").BoolVar(&cfg.Once) app.Flag("dry-run", "When enabled, prints DNS record changes rather than actually performing them (default: disabled)").BoolVar(&cfg.DryRun) app.Flag("events", "When enabled, in addition to running every interval, the reconciliation loop will get triggered when supported sources change (default: disabled)").BoolVar(&cfg.UpdateEvents) diff --git a/pkg/apis/externaldns/types_test.go b/pkg/apis/externaldns/types_test.go index 6eb8fc705..343e67085 100644 --- a/pkg/apis/externaldns/types_test.go +++ b/pkg/apis/externaldns/types_test.go @@ -90,7 +90,7 @@ var ( TXTPrefix: "", TXTCacheInterval: 0, Interval: time.Minute, - MinInterval: 5 * time.Second, + MinEventSyncInterval: 5 * time.Second, Once: false, DryRun: false, UpdateEvents: false, @@ -176,7 +176,7 @@ var ( TXTPrefix: "associated-txt-record", TXTCacheInterval: 12 * time.Hour, Interval: 10 * time.Minute, - MinInterval: 50 * time.Second, + MinEventSyncInterval: 50 * time.Second, Once: true, DryRun: true, UpdateEvents: true, @@ -289,7 +289,7 @@ func TestParseFlags(t *testing.T) { "--txt-prefix=associated-txt-record", "--txt-cache-interval=12h", "--interval=10m", - "--min-interval=50s", + "--min-event-sync-interval=50s", "--once", "--dry-run", "--events", @@ -381,7 +381,7 @@ func TestParseFlags(t *testing.T) { "EXTERNAL_DNS_TXT_PREFIX": "associated-txt-record", "EXTERNAL_DNS_TXT_CACHE_INTERVAL": "12h", "EXTERNAL_DNS_INTERVAL": "10m", - "EXTERNAL_DNS_MIN_INTERVAL": "50s", + "EXTERNAL_DNS_MIN_EVENT_SYNC_INTERVAL": "50s", "EXTERNAL_DNS_ONCE": "1", "EXTERNAL_DNS_DRY_RUN": "1", "EXTERNAL_DNS_EVENTS": "1", From b09d7abc559904d111e7f398dd79bd69a45177f7 Mon Sep 17 00:00:00 2001 From: Reinier Schoof Date: Tue, 23 Mar 2021 12:17:32 +0100 Subject: [PATCH 089/175] update TransIP's Go client to v6 --- go.mod | 2 +- go.sum | 4 +- provider/transip/transip.go | 413 ++++++++++++++++--------------- provider/transip/transip_test.go | 346 +++++++++++++++++--------- 4 files changed, 446 insertions(+), 319 deletions(-) diff --git a/go.mod b/go.mod index feff79fa2..8ed81f3cd 100644 --- a/go.mod +++ b/go.mod @@ -50,7 +50,7 @@ require ( github.com/smartystreets/gunit v1.3.4 // indirect github.com/stretchr/testify v1.6.1 github.com/terra-farm/udnssdk v1.3.5 // indirect - github.com/transip/gotransip v5.8.2+incompatible + github.com/transip/gotransip/v6 v6.6.0 github.com/ultradns/ultradns-sdk-go v0.0.0-20200616202852-e62052662f60 github.com/vinyldns/go-vinyldns v0.0.0-20200211145900-fe8a3d82e556 github.com/vultr/govultr v0.4.2 diff --git a/go.sum b/go.sum index 8a5a6e67b..deb93320b 100644 --- a/go.sum +++ b/go.sum @@ -856,8 +856,8 @@ github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhV github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/transip/gotransip v5.8.2+incompatible h1:aNJhw/w/3QBqFcHAIPz1ytoK5FexeMzbUCGrrhWr3H0= -github.com/transip/gotransip v5.8.2+incompatible/go.mod h1:uacMoJVmrfOcscM4Bi5NVg708b7c6rz2oDTWqa7i2Ic= +github.com/transip/gotransip/v6 v6.6.0 h1:dAHCTZzX98H6QE2kA4R9acAXu5RPPTwMSUFtpKZF3Nk= +github.com/transip/gotransip/v6 v6.6.0/go.mod h1:pQZ36hWWRahCUXkFWlx9Hs711gLd8J4qdgLdRzmtY+g= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= diff --git a/provider/transip/transip.go b/provider/transip/transip.go index 297678ab0..6543da915 100644 --- a/provider/transip/transip.go +++ b/provider/transip/transip.go @@ -23,8 +23,8 @@ import ( "strings" log "github.com/sirupsen/logrus" - "github.com/transip/gotransip" - transip "github.com/transip/gotransip/domain" + "github.com/transip/gotransip/v6" + "github.com/transip/gotransip/v6/domain" "sigs.k8s.io/external-dns/endpoint" "sigs.k8s.io/external-dns/plan" @@ -40,9 +40,11 @@ const ( // TransIPProvider is an implementation of Provider for TransIP. type TransIPProvider struct { provider.BaseProvider - client gotransip.SOAPClient + domainRepo domain.Repository domainFilter endpoint.DomainFilter dryRun bool + + zoneMap provider.ZoneIDName } // NewTransIPProvider initializes a new TransIP Provider. @@ -64,7 +66,7 @@ func NewTransIPProvider(accountName, privateKeyFile string, domainFilter endpoin } // create new TransIP API client - c, err := gotransip.NewSOAPClient(gotransip.ClientConfig{ + client, err := gotransip.NewClient(gotransip.ClientConfiguration{ AccountName: accountName, PrivateKeyPath: privateKeyFile, Mode: apiMode, @@ -73,233 +75,280 @@ func NewTransIPProvider(accountName, privateKeyFile string, domainFilter endpoin return nil, fmt.Errorf("could not setup TransIP API client: %s", err.Error()) } - // return tipCloud struct + // return TransIPProvider struct return &TransIPProvider{ - client: c, + domainRepo: domain.Repository{Client: client}, domainFilter: domainFilter, dryRun: dryRun, + zoneMap: provider.ZoneIDName{}, }, nil } // ApplyChanges applies a given set of changes in a given zone. func (p *TransIPProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error { - // build zonefinder with all our zones so we can use FindZone - // and a mapping of zones and their domain name - zones, err := p.fetchZones() + // fetch all zones we currently have + // this does NOT include any DNS entries, so we'll have to fetch these for + // each zone that gets updated + zones, err := p.domainRepo.GetAll() if err != nil { return err } - zoneNameMapper := provider.ZoneIDName{} - zonesByName := make(map[string]transip.Domain) - updatedZones := make(map[string]bool) + // refresh zone mapping + zoneMap := provider.ZoneIDName{} for _, zone := range zones { // TransIP API doesn't expose a unique identifier for zones, other than than // the domain name itself - zoneNameMapper.Add(zone.Name, zone.Name) - zonesByName[zone.Name] = zone + zoneMap.Add(zone.Name, zone.Name) } + p.zoneMap = zoneMap - // first see if we need to delete anything + // first remove obsolete DNS records for _, ep := range changes.Delete { - log.WithFields(log.Fields{"record": ep.DNSName, "type": ep.RecordType}).Info("endpoint has to go") + epLog := log.WithFields(log.Fields{ + "record": ep.DNSName, + "type": ep.RecordType, + }) + epLog.Info("endpoint has to go") - zone, err := p.zoneForZoneName(ep.DNSName, zoneNameMapper, zonesByName) + zoneName, entries, err := p.entriesForEndpoint(ep) if err != nil { - log.Errorf("could not find zone for %s: %s", ep.DNSName, err.Error()) - continue + epLog.WithError(err).Error("could not get DNS entries") + return err } - log.Debugf("removing records for %s", zone.Name) + epLog = epLog.WithField("zone", zoneName) - // remove current records from DNS entry set - entries := p.removeEndpointFromEntries(ep, zone) - - // update zone in zone map - zone.DNSEntries = entries - zonesByName[zone.Name] = zone - // flag zone for updating - updatedZones[zone.Name] = true - } - - for _, ep := range changes.Create { - log.WithFields(log.Fields{"record": ep.DNSName, "type": ep.RecordType}).Info("endpoint is missing") - - zone, err := p.zoneForZoneName(ep.DNSName, zoneNameMapper, zonesByName) - if err != nil { - log.Errorf("could not find zone for %s: %s", ep.DNSName, err.Error()) - continue - } - - log.Debugf("creating records for %s", zone.Name) - - // add new entries to set - zone.DNSEntries = p.addEndpointToEntries(ep, zone, zone.DNSEntries) - - // update zone in zone map - zonesByName[zone.Name] = zone - // flag zone for updating - updatedZones[zone.Name] = true - log.WithFields(log.Fields{"zone": zone.Name}).Debug("flagging for update") - } - - for _, ep := range changes.UpdateNew { - log.WithFields(log.Fields{"record": ep.DNSName, "type": ep.RecordType}).Debug("needs updating") - - zone, err := p.zoneForZoneName(ep.DNSName, zoneNameMapper, zonesByName) - if err != nil { - log.WithFields(log.Fields{"record": ep.DNSName}).Warn(err.Error()) - continue - } - - // updating the records is basically finding all matching records according - // to the name and the type, removing them from the set and add the new - // records - log.WithFields(log.Fields{ - "zone": zone.Name, - "dnsname": ep.DNSName, - "recordtype": ep.RecordType, - }).Debug("removing matching entries") - - // remove current records from DNS entry set - entries := p.removeEndpointFromEntries(ep, zone) - - // add new entries to set - entries = p.addEndpointToEntries(ep, zone, entries) - - // check to see if actually anything changed in the DNSEntry set - if p.dnsEntriesAreEqual(entries, zone.DNSEntries) { - log.WithFields(log.Fields{"zone": zone.Name}).Debug("not updating identical entries") - continue - } - - // update zone in zone map - zone.DNSEntries = entries - zonesByName[zone.Name] = zone - // flag zone for updating - updatedZones[zone.Name] = true - - log.WithFields(log.Fields{"zone": zone.Name}).Debug("flagging for update") - } - - // go over all updated zones and set new DNSEntry set - for uz := range updatedZones { - zone, ok := zonesByName[uz] - if !ok { - log.WithFields(log.Fields{"zone": uz}).Debug("updated zone no longer found") + if len(entries) == 0 { + epLog.Info("no matching entries found") continue } if p.dryRun { - log.WithFields(log.Fields{"zone": zone.Name}).Info("not updating in dry-run mode") + epLog.Info("not removing DNS entries in dry-run mode") continue } - log.WithFields(log.Fields{"zone": zone.Name}).Info("updating DNS entries") - if err := transip.SetDNSEntries(p.client, zone.Name, zone.DNSEntries); err != nil { - log.WithFields(log.Fields{"zone": zone.Name, "error": err.Error()}).Warn("failed to update") + for _, entry := range entries { + log.WithFields(log.Fields{ + "domain": zoneName, + "name": entry.Name, + "type": entry.Type, + "content": entry.Content, + "ttl": entry.Expire, + }).Info("removing DNS entry") + + err = p.domainRepo.RemoveDNSEntry(zoneName, entry) + if err != nil { + epLog.WithError(err).Error("could not remove DNS entry") + return err + } + } + } + + // then create new DNS records + for _, ep := range changes.Create { + epLog := log.WithFields(log.Fields{ + "record": ep.DNSName, + "type": ep.RecordType, + }) + epLog.Info("endpoint should be created") + + zoneName, err := p.zoneNameForDNSName(ep.DNSName) + if err != nil { + epLog.WithError(err).Warn("could not find zone for endpoint") + continue + } + + epLog = epLog.WithField("zone", zoneName) + + if p.dryRun { + epLog.Info("not adding DNS entries in dry-run mode") + continue + } + + for _, entry := range dnsEntriesForEndpoint(ep, zoneName) { + log.WithFields(log.Fields{ + "domain": zoneName, + "name": entry.Name, + "type": entry.Type, + "content": entry.Content, + "ttl": entry.Expire, + }).Info("creating DNS entry") + + err = p.domainRepo.AddDNSEntry(zoneName, entry) + if err != nil { + epLog.WithError(err).Error("could not add DNS entry") + return err + } + } + } + + // then update existing DNS records + for _, ep := range changes.UpdateNew { + epLog := log.WithFields(log.Fields{ + "record": ep.DNSName, + "type": ep.RecordType, + }) + epLog.Debug("endpoint needs updating") + + zoneName, entries, err := p.entriesForEndpoint(ep) + if err != nil { + epLog.WithError(err).Error("could not get DNS entries") + return err + } + + epLog = epLog.WithField("zone", zoneName) + + if len(entries) == 0 { + epLog.Info("no matching entries found") + continue + } + + newEntries := dnsEntriesForEndpoint(ep, zoneName) + + // check to see if actually anything changed in the DNSEntry set + if dnsEntriesAreEqual(newEntries, entries) { + epLog.Debug("not updating identical DNS entries") + continue + } + + if p.dryRun { + epLog.Info("not updating DNS entries in dry-run mode") + continue + } + + // TransIP API client does have an UpdateDNSEntry call but that does only + // allow you to update the content of a DNSEntry, not the TTL + // to work around this, remove the old entry first and add the new entry + for _, entry := range entries { + log.WithFields(log.Fields{ + "domain": zoneName, + "name": entry.Name, + "type": entry.Type, + "content": entry.Content, + "ttl": entry.Expire, + }).Info("removing DNS entry") + + err = p.domainRepo.RemoveDNSEntry(zoneName, entry) + if err != nil { + epLog.WithError(err).Error("could not remove DNS entry") + return err + } + } + + for _, entry := range newEntries { + log.WithFields(log.Fields{ + "domain": zoneName, + "name": entry.Name, + "type": entry.Type, + "content": entry.Content, + "ttl": entry.Expire, + }).Info("adding DNS entry") + + err = p.domainRepo.AddDNSEntry(zoneName, entry) + if err != nil { + epLog.WithError(err).Error("could not add DNS entry") + return err + } } } return nil } -// fetchZones returns a list of all domains within the account -func (p *TransIPProvider) fetchZones() ([]transip.Domain, error) { - domainNames, err := transip.GetDomainNames(p.client) - if err != nil { - return nil, err - } - - domains, err := transip.BatchGetInfo(p.client, domainNames) - if err != nil { - return nil, err - } - - var zones []transip.Domain - for _, d := range domains { - if !p.domainFilter.Match(d.Name) { - continue - } - - zones = append(zones, d) - } - - return zones, nil -} - -// Zones returns the list of hosted zones. -func (p *TransIPProvider) Zones() ([]transip.Domain, error) { - zones, err := p.fetchZones() - if err != nil { - return nil, err - } - - return zones, nil -} - -// Records returns the list of records in a given zone. +// Records returns the list of records in all zones func (p *TransIPProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error) { - zones, err := p.Zones() + zones, err := p.domainRepo.GetAll() if err != nil { return nil, err } var endpoints []*endpoint.Endpoint - var name string // go over all zones and their DNS entries and create endpoints for them for _, zone := range zones { - for _, r := range zone.DNSEntries { - if !provider.SupportedRecordType(string(r.Type)) { + entries, err := p.domainRepo.GetDNSEntries(zone.Name) + if err != nil { + return nil, err + } + + for _, r := range entries { + if !provider.SupportedRecordType(r.Type) { continue } - name = p.endpointNameForRecord(r, zone) - endpoints = append(endpoints, endpoint.NewEndpointWithTTL(name, string(r.Type), endpoint.TTL(r.TTL), r.Content)) + name := endpointNameForRecord(r, zone.Name) + endpoints = append(endpoints, endpoint.NewEndpointWithTTL(name, r.Type, endpoint.TTL(r.Expire), r.Content)) } } return endpoints, nil } +func (p *TransIPProvider) entriesForEndpoint(ep *endpoint.Endpoint) (string, []domain.DNSEntry, error) { + zoneName, err := p.zoneNameForDNSName(ep.DNSName) + if err != nil { + return "", nil, err + } + + epName := recordNameForEndpoint(ep, zoneName) + dnsEntries, err := p.domainRepo.GetDNSEntries(zoneName) + if err != nil { + return zoneName, nil, err + } + + matches := []domain.DNSEntry{} + for _, entry := range dnsEntries { + if ep.RecordType != entry.Type { + continue + } + + if entry.Name == epName { + matches = append(matches, entry) + } + } + + return zoneName, matches, nil +} + // endpointNameForRecord returns "www.example.org" for DNSEntry with Name "www" and // Domain with Name "example.org" -func (p *TransIPProvider) endpointNameForRecord(r transip.DNSEntry, d transip.Domain) string { +func endpointNameForRecord(r domain.DNSEntry, zoneName string) string { // root name is identified by "@" and should be translated to domain name for // the endpoint entry. if r.Name == "@" { - return d.Name + return zoneName } - return fmt.Sprintf("%s.%s", r.Name, d.Name) + return fmt.Sprintf("%s.%s", r.Name, zoneName) } // recordNameForEndpoint returns "www" for Endpoint with DNSName "www.example.org" // and Domain with Name "example.org" -func (p *TransIPProvider) recordNameForEndpoint(ep *endpoint.Endpoint, d transip.Domain) string { +func recordNameForEndpoint(ep *endpoint.Endpoint, zoneName string) string { // root name is identified by "@" and should be translated to domain name for // the endpoint entry. - if ep.DNSName == d.Name { + if ep.DNSName == zoneName { return "@" } - return strings.TrimSuffix(ep.DNSName, "."+d.Name) + return strings.TrimSuffix(ep.DNSName, "."+zoneName) } // getMinimalValidTTL returns max between given Endpoint's RecordTTL and // transipMinimalValidTTL -func (p *TransIPProvider) getMinimalValidTTL(ep *endpoint.Endpoint) int64 { +func getMinimalValidTTL(ep *endpoint.Endpoint) int { // TTL cannot be lower than transipMinimalValidTTL if ep.RecordTTL < transipMinimalValidTTL { return transipMinimalValidTTL } - return int64(ep.RecordTTL) + return int(ep.RecordTTL) } // dnsEntriesAreEqual compares the entries in 2 sets and returns true if the // content of the entries is equal -func (p *TransIPProvider) dnsEntriesAreEqual(a, b transip.DNSEntries) bool { +func dnsEntriesAreEqual(a, b []domain.DNSEntry) bool { if len(a) != len(b) { return false } @@ -315,7 +364,7 @@ func (p *TransIPProvider) dnsEntriesAreEqual(a, b transip.DNSEntries) bool { continue } - if aa.TTL != bb.TTL { + if aa.Expire != bb.Expire { continue } @@ -330,45 +379,22 @@ func (p *TransIPProvider) dnsEntriesAreEqual(a, b transip.DNSEntries) bool { return (len(a) == match) } -// removeEndpointFromEntries removes DNS entries from zone's set that match the -// type and name from given endpoint and returns the resulting DNS entry set -func (p *TransIPProvider) removeEndpointFromEntries(ep *endpoint.Endpoint, zone transip.Domain) transip.DNSEntries { - // create new entry set - entries := transip.DNSEntries{} - // go over each DNS entry to see if it is a match - for _, e := range zone.DNSEntries { - // if we have match, don't copy it to the new entry set - if p.endpointNameForRecord(e, zone) == ep.DNSName && string(e.Type) == ep.RecordType { - log.WithFields(log.Fields{ - "name": e.Name, - "content": e.Content, - "type": e.Type, - }).Debug("found match") - continue +// dnsEntriesForEndpoint creates DNS entries for given endpoint and returns +// resulting DNS entry set +func dnsEntriesForEndpoint(ep *endpoint.Endpoint, zoneName string) []domain.DNSEntry { + ttl := getMinimalValidTTL(ep) + + entries := []domain.DNSEntry{} + for _, target := range ep.Targets { + // external hostnames require a trailing dot in TransIP API + if ep.RecordType == "CNAME" { + target = provider.EnsureTrailingDot(target) } - entries = append(entries, e) - } - - return entries -} - -// addEndpointToEntries creates DNS entries for given endpoint and returns -// resulting DNS entry set -func (p *TransIPProvider) addEndpointToEntries(ep *endpoint.Endpoint, zone transip.Domain, entries transip.DNSEntries) transip.DNSEntries { - ttl := p.getMinimalValidTTL(ep) - for _, target := range ep.Targets { - log.WithFields(log.Fields{ - "zone": zone.Name, - "dnsname": ep.DNSName, - "recordtype": ep.RecordType, - "ttl": ttl, - "target": target, - }).Debugf("adding new record") - entries = append(entries, transip.DNSEntry{ - Name: p.recordNameForEndpoint(ep, zone), - TTL: ttl, - Type: transip.DNSEntryType(ep.RecordType), + entries = append(entries, domain.DNSEntry{ + Name: recordNameForEndpoint(ep, zoneName), + Expire: ttl, + Type: ep.RecordType, Content: target, }) } @@ -378,16 +404,11 @@ func (p *TransIPProvider) addEndpointToEntries(ep *endpoint.Endpoint, zone trans // zoneForZoneName returns the zone mapped to given name or error if zone could // not be found -func (p *TransIPProvider) zoneForZoneName(name string, m provider.ZoneIDName, z map[string]transip.Domain) (transip.Domain, error) { - _, zoneName := m.FindZone(name) +func (p *TransIPProvider) zoneNameForDNSName(name string) (string, error) { + _, zoneName := p.zoneMap.FindZone(name) if zoneName == "" { - return transip.Domain{}, fmt.Errorf("could not find zoneName for %s", name) + return "", fmt.Errorf("could not find zoneName for %s", name) } - zone, ok := z[zoneName] - if !ok { - return zone, fmt.Errorf("could not find zone for %s", zoneName) - } - - return zone, nil + return zoneName, nil } diff --git a/provider/transip/transip_test.go b/provider/transip/transip_test.go index 76e090b78..91c622afb 100644 --- a/provider/transip/transip_test.go +++ b/provider/transip/transip_test.go @@ -17,116 +17,123 @@ limitations under the License. package transip import ( + "context" + "encoding/json" + "errors" + "strings" "testing" "github.com/stretchr/testify/assert" - transip "github.com/transip/gotransip/domain" + "github.com/stretchr/testify/require" + "github.com/transip/gotransip/v6/domain" + "github.com/transip/gotransip/v6/rest" "sigs.k8s.io/external-dns/endpoint" + "sigs.k8s.io/external-dns/provider" ) +func newProvider() *TransIPProvider { + return &TransIPProvider{ + zoneMap: provider.ZoneIDName{}, + } +} + func TestTransIPDnsEntriesAreEqual(t *testing.T) { - p := TransIPProvider{} // test with equal set - a := transip.DNSEntries{ - transip.DNSEntry{ + a := []domain.DNSEntry{ + { Name: "www.example.org", - Type: transip.DNSEntryTypeCNAME, - TTL: 3600, + Type: "CNAME", + Expire: 3600, Content: "www.example.com", }, - transip.DNSEntry{ + { Name: "www.example.com", - Type: transip.DNSEntryTypeA, - TTL: 3600, + Type: "A", + Expire: 3600, Content: "192.168.0.1", }, } - b := transip.DNSEntries{ - transip.DNSEntry{ + b := []domain.DNSEntry{ + { Name: "www.example.com", - Type: transip.DNSEntryTypeA, - TTL: 3600, + Type: "A", + Expire: 3600, Content: "192.168.0.1", }, - transip.DNSEntry{ + { Name: "www.example.org", - Type: transip.DNSEntryTypeCNAME, - TTL: 3600, + Type: "CNAME", + Expire: 3600, Content: "www.example.com", }, } - assert.Equal(t, true, p.dnsEntriesAreEqual(a, b)) + assert.Equal(t, true, dnsEntriesAreEqual(a, b)) // change type on one of b's records - b[1].Type = transip.DNSEntryTypeNS - assert.Equal(t, false, p.dnsEntriesAreEqual(a, b)) - b[1].Type = transip.DNSEntryTypeCNAME + b[1].Type = "NS" + assert.Equal(t, false, dnsEntriesAreEqual(a, b)) + b[1].Type = "CNAME" // change ttl on one of b's records - b[1].TTL = 1800 - assert.Equal(t, false, p.dnsEntriesAreEqual(a, b)) - b[1].TTL = 3600 + b[1].Expire = 1800 + assert.Equal(t, false, dnsEntriesAreEqual(a, b)) + b[1].Expire = 3600 // change name on one of b's records b[1].Name = "example.org" - assert.Equal(t, false, p.dnsEntriesAreEqual(a, b)) + assert.Equal(t, false, dnsEntriesAreEqual(a, b)) // remove last entry of b b = b[:1] - assert.Equal(t, false, p.dnsEntriesAreEqual(a, b)) + assert.Equal(t, false, dnsEntriesAreEqual(a, b)) } func TestTransIPGetMinimalValidTTL(t *testing.T) { - p := TransIPProvider{} // test with 'unconfigured' TTL ep := &endpoint.Endpoint{} - assert.Equal(t, int64(transipMinimalValidTTL), p.getMinimalValidTTL(ep)) + assert.EqualValues(t, transipMinimalValidTTL, getMinimalValidTTL(ep)) // test with lower than minimal ttl ep.RecordTTL = (transipMinimalValidTTL - 1) - assert.Equal(t, int64(transipMinimalValidTTL), p.getMinimalValidTTL(ep)) + assert.EqualValues(t, transipMinimalValidTTL, getMinimalValidTTL(ep)) // test with higher than minimal ttl ep.RecordTTL = (transipMinimalValidTTL + 1) - assert.Equal(t, int64(transipMinimalValidTTL+1), p.getMinimalValidTTL(ep)) + assert.EqualValues(t, transipMinimalValidTTL+1, getMinimalValidTTL(ep)) } func TestTransIPRecordNameForEndpoint(t *testing.T) { - p := TransIPProvider{} ep := &endpoint.Endpoint{ DNSName: "example.org", } - d := transip.Domain{ + d := domain.Domain{ Name: "example.org", } - assert.Equal(t, "@", p.recordNameForEndpoint(ep, d)) + assert.Equal(t, "@", recordNameForEndpoint(ep, d.Name)) ep.DNSName = "www.example.org" - assert.Equal(t, "www", p.recordNameForEndpoint(ep, d)) + assert.Equal(t, "www", recordNameForEndpoint(ep, d.Name)) } func TestTransIPEndpointNameForRecord(t *testing.T) { - p := TransIPProvider{} - r := transip.DNSEntry{ + r := domain.DNSEntry{ Name: "@", } - d := transip.Domain{ + d := domain.Domain{ Name: "example.org", } - assert.Equal(t, d.Name, p.endpointNameForRecord(r, d)) + assert.Equal(t, d.Name, endpointNameForRecord(r, d.Name)) r.Name = "www" - assert.Equal(t, "www.example.org", p.endpointNameForRecord(r, d)) + assert.Equal(t, "www.example.org", endpointNameForRecord(r, d.Name)) } func TestTransIPAddEndpointToEntries(t *testing.T) { - p := TransIPProvider{} - // prepare endpoint ep := &endpoint.Endpoint{ DNSName: "www.example.org", @@ -139,94 +146,193 @@ func TestTransIPAddEndpointToEntries(t *testing.T) { } // prepare zone with DNS entry set - zone := transip.Domain{ + zone := domain.Domain{ Name: "example.org", - // 2 matching A records - DNSEntries: transip.DNSEntries{ - // 1 non-matching A record - transip.DNSEntry{ - Name: "mail", - Type: transip.DNSEntryTypeA, - Content: "192.168.0.1", - TTL: 3600, - }, - // 1 non-matching MX record - transip.DNSEntry{ - Name: "@", - Type: transip.DNSEntryTypeMX, - Content: "mail.example.org", - TTL: 3600, - }, - }, } // add endpoint to zone's entries - result := p.addEndpointToEntries(ep, zone, zone.DNSEntries) + result := dnsEntriesForEndpoint(ep, zone.Name) - assert.Equal(t, 4, len(result)) - assert.Equal(t, "mail", result[0].Name) - assert.Equal(t, transip.DNSEntryTypeA, result[0].Type) - assert.Equal(t, "@", result[1].Name) - assert.Equal(t, transip.DNSEntryTypeMX, result[1].Type) - assert.Equal(t, "www", result[2].Name) - assert.Equal(t, transip.DNSEntryTypeA, result[2].Type) - assert.Equal(t, "192.168.0.1", result[2].Content) - assert.Equal(t, int64(1800), result[2].TTL) - assert.Equal(t, "www", result[3].Name) - assert.Equal(t, transip.DNSEntryTypeA, result[3].Type) - assert.Equal(t, "192.168.0.2", result[3].Content) - assert.Equal(t, int64(1800), result[3].TTL) -} - -func TestTransIPRemoveEndpointFromEntries(t *testing.T) { - p := TransIPProvider{} - - // prepare endpoint - ep := &endpoint.Endpoint{ - DNSName: "www.example.org", - RecordType: "A", + if assert.Equal(t, 2, len(result)) { + assert.Equal(t, "www", result[0].Name) + assert.Equal(t, "A", result[0].Type) + assert.Equal(t, "192.168.0.1", result[0].Content) + assert.EqualValues(t, 1800, result[0].Expire) + assert.Equal(t, "www", result[1].Name) + assert.Equal(t, "A", result[1].Type) + assert.Equal(t, "192.168.0.2", result[1].Content) + assert.EqualValues(t, 1800, result[1].Expire) } - // prepare zone with DNS entry set - zone := transip.Domain{ - Name: "example.org", - // 2 matching A records - DNSEntries: transip.DNSEntries{ - transip.DNSEntry{ - Name: "www", - Type: transip.DNSEntryTypeA, - Content: "192.168.0.1", - TTL: 3600, - }, - transip.DNSEntry{ - Name: "www", - Type: transip.DNSEntryTypeA, - Content: "192.168.0.2", - TTL: 3600, - }, - // 1 non-matching A record - transip.DNSEntry{ - Name: "mail", - Type: transip.DNSEntryTypeA, - Content: "192.168.0.1", - TTL: 3600, - }, - // 1 non-matching MX record - transip.DNSEntry{ - Name: "@", - Type: transip.DNSEntryTypeMX, - Content: "mail.example.org", - TTL: 3600, - }, + // try again with CNAME + ep.RecordType = "CNAME" + ep.Targets = []string{"foo.bar"} + result = dnsEntriesForEndpoint(ep, zone.Name) + if assert.Equal(t, 1, len(result)) { + assert.Equal(t, "CNAME", result[0].Type) + assert.Equal(t, "foo.bar.", result[0].Content) + } +} + +func TestZoneNameForDNSName(t *testing.T) { + p := newProvider() + p.zoneMap.Add("example.com", "example.com") + + zoneName, err := p.zoneNameForDNSName("www.example.com") + if assert.NoError(t, err) { + assert.Equal(t, "example.com", zoneName) + } + + _, err = p.zoneNameForDNSName("www.example.org") + if assert.Error(t, err) { + assert.Equal(t, "could not find zoneName for www.example.org", err.Error()) + } +} + +// fakeClient mocks the REST API client +type fakeClient struct { + getFunc func(rest.Request, interface{}) error +} + +func (f *fakeClient) Get(request rest.Request, dest interface{}) error { + if f.getFunc == nil { + return errors.New("GET not defined") + } + + return f.getFunc(request, dest) +} + +func (f fakeClient) Put(request rest.Request) error { + return errors.New("PUT not implemented") +} + +func (f fakeClient) Post(request rest.Request) error { + return errors.New("POST not implemented") +} + +func (f fakeClient) Delete(request rest.Request) error { + return errors.New("DELETE not implemented") +} + +func (f fakeClient) Patch(request rest.Request) error { + return errors.New("PATCH not implemented") +} + +func TestProviderRecords(t *testing.T) { + // set up the fake REST client + client := &fakeClient{} + client.getFunc = func(req rest.Request, dest interface{}) error { + var data []byte + switch { + case req.Endpoint == "/domains": + // return list of some domain names + // names only, other fields are not used + data = []byte(`{"domains":[{"name":"example.org"}, {"name":"example.com"}]}`) + case strings.HasSuffix(req.Endpoint, "/dns"): + // return list of DNS entries + // also some unsupported types + data = []byte(`{"dnsEntries":[{"name":"www", "expire":1234, "type":"CNAME", "content":"@"},{"type":"MX"},{"type":"AAAA"}]}`) + } + + // unmarshal the prepared return data into the given destination type + return json.Unmarshal(data, &dest) + } + + // set up provider + p := newProvider() + p.domainRepo = domain.Repository{Client: client} + + endpoints, err := p.Records(context.TODO()) + if assert.NoError(t, err) { + if assert.Equal(t, 2, len(endpoints)) { + assert.Equal(t, "www.example.org", endpoints[0].DNSName) + assert.EqualValues(t, "@", endpoints[0].Targets[0]) + assert.Equal(t, "CNAME", endpoints[0].RecordType) + assert.Equal(t, 0, len(endpoints[0].Labels)) + assert.EqualValues(t, 1234, endpoints[0].RecordTTL) + } + } +} + +func TestProviderEntriesForEndpoint(t *testing.T) { + // set up fake REST client + client := &fakeClient{} + + // set up provider + p := newProvider() + p.domainRepo = domain.Repository{Client: client} + p.zoneMap.Add("example.com", "example.com") + + // get entries for endpoint with unknown zone + _, _, err := p.entriesForEndpoint(&endpoint.Endpoint{ + DNSName: "www.example.org", + }) + if assert.Error(t, err) { + assert.Equal(t, "could not find zoneName for www.example.org", err.Error()) + } + + // get entries for endpoint with known zone but client returns error + // we leave GET functions undefined so we know which error to expect + zoneName, _, err := p.entriesForEndpoint(&endpoint.Endpoint{ + DNSName: "www.example.com", + }) + if assert.Error(t, err) { + assert.Equal(t, "GET not defined", err.Error()) + } + assert.Equal(t, "example.com", zoneName) + + // to be able to return a valid set of DNS entries through the API, we define + // some first, then JSON encode them and have the fake API client's Get function + // return that + // in this set are some entries that do and others that don't match the given + // endpoint + dnsEntries := []domain.DNSEntry{ + { + Name: "www", + Type: "A", + Expire: 3600, + Content: "1.2.3.4", + }, + { + Name: "ftp", + Type: "A", + Expire: 86400, + Content: "3.4.5.6", + }, + { + Name: "www", + Type: "A", + Expire: 3600, + Content: "2.3.4.5", + }, + { + Name: "www", + Type: "CNAME", + Expire: 3600, + Content: "@", }, } + var v struct { + DNSEntries []domain.DNSEntry `json:"dnsEntries"` + } + v.DNSEntries = dnsEntries + returnData, err := json.Marshal(&v) + require.NoError(t, err) - // remove endpoint from zone's entries - result := p.removeEndpointFromEntries(ep, zone) - - assert.Equal(t, 2, len(result)) - assert.Equal(t, "mail", result[0].Name) - assert.Equal(t, transip.DNSEntryTypeA, result[0].Type) - assert.Equal(t, "@", result[1].Name) - assert.Equal(t, transip.DNSEntryTypeMX, result[1].Type) + // define GET function + client.getFunc = func(unused rest.Request, dest interface{}) error { + // unmarshal the prepared return data into the given dnsEntriesWrapper + return json.Unmarshal(returnData, &dest) + } + _, entries, err := p.entriesForEndpoint(&endpoint.Endpoint{ + DNSName: "www.example.com", + RecordType: "A", + }) + if assert.NoError(t, err) { + if assert.Equal(t, 2, len(entries)) { + // only first and third entry should be returned + assert.Equal(t, dnsEntries[0], entries[0]) + assert.Equal(t, dnsEntries[2], entries[1]) + } + } } From a19deebe27896849d9537b0e17cedbb601d63ed8 Mon Sep 17 00:00:00 2001 From: Allen Porter Date: Sat, 27 Mar 2021 15:42:10 -0700 Subject: [PATCH 090/175] Avoid nil pointer deference in extractHeadlessEndpoints Skip address when TargetRef is nil --- source/service.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/service.go b/source/service.go index 18ab29041..aeb9c8661 100644 --- a/source/service.go +++ b/source/service.go @@ -284,7 +284,7 @@ func (sc *serviceSource) extractHeadlessEndpoints(svc *v1.Service, hostname stri for _, address := range addresses { // find pod for this address - if address.TargetRef.APIVersion != "" || address.TargetRef.Kind != "Pod" { + if address.TargetRef == nil || address.TargetRef.APIVersion != "" || address.TargetRef.Kind != "Pod" { log.Debugf("Skipping address because its target is not a pod: %v", address) continue } From 5800f6df866c00e863ef4851f5616036ad4ca022 Mon Sep 17 00:00:00 2001 From: Thomas Stig Jacobsen Date: Tue, 30 Mar 2021 11:10:17 +0200 Subject: [PATCH 091/175] Update .github/workflows/ci.yml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nick Jüttner --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9a1ce1a31..19266d35f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: - name: Set up Go 1.x uses: actions/setup-go@v2 with: - go-version: ^1.16.2 + go-version: ^1.16 id: go - name: Check out code into the Go module directory From deb805c8d46ce2ddedc1f69404aeda9b264f1e88 Mon Sep 17 00:00:00 2001 From: Thomas Stig Jacobsen Date: Tue, 30 Mar 2021 11:10:26 +0200 Subject: [PATCH 092/175] Update Dockerfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nick Jüttner --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index a4b0932de..dd9e80552 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,7 @@ # builder image ARG ARCH -FROM golang:1.16.2 as builder +FROM golang:1.16 as builder ARG ARCH WORKDIR /sigs.k8s.io/external-dns From f67242e3e5e81739af61ed5189749f9737a785fc Mon Sep 17 00:00:00 2001 From: Thomas Stig Jacobsen Date: Tue, 30 Mar 2021 11:10:32 +0200 Subject: [PATCH 093/175] Update Dockerfile.mini MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nick Jüttner --- Dockerfile.mini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.mini b/Dockerfile.mini index 6c5f41933..d3b02877f 100644 --- a/Dockerfile.mini +++ b/Dockerfile.mini @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM golang:1.16.2 as builder +FROM golang:1.16 as builder WORKDIR /sigs.k8s.io/external-dns From 67ef48f8ba82746ff72c5e1b0ec269771238be14 Mon Sep 17 00:00:00 2001 From: Thomas Stig Jacobsen Date: Tue, 30 Mar 2021 11:10:40 +0200 Subject: [PATCH 094/175] Update docs/contributing/getting-started.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nick Jüttner --- docs/contributing/getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing/getting-started.md b/docs/contributing/getting-started.md index be4a89f97..9a51861b4 100644 --- a/docs/contributing/getting-started.md +++ b/docs/contributing/getting-started.md @@ -1,7 +1,7 @@ # Quick Start - [Git](https://git-scm.com/downloads) -- [Go 1.16.2+](https://golang.org/dl/) +- [Go 1.16+](https://golang.org/dl/) - [Go modules](https://github.com/golang/go/wiki/Modules) - [golangci-lint](https://github.com/golangci/golangci-lint) - [Docker](https://docs.docker.com/install/) From 088449d68f6d2e305e4591962830330464c6f150 Mon Sep 17 00:00:00 2001 From: Patrik Cyvoct Date: Wed, 31 Mar 2021 09:23:51 +0200 Subject: [PATCH 095/175] doc(scaleway): remove organization ID usage Signed-off-by: Patrik Cyvoct --- docs/tutorials/scaleway.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docs/tutorials/scaleway.md b/docs/tutorials/scaleway.md index 3e7d229bb..9c3c8c8b6 100644 --- a/docs/tutorials/scaleway.md +++ b/docs/tutorials/scaleway.md @@ -24,7 +24,6 @@ Note that you will also need to the Organization ID, which can be retrieve on th Three environment variables are needed to run ExternalDNS with Scaleway DNS: - `SCW_ACCESS_KEY` which is the Access Key. - `SCW_SECRET_KEY` which is the Secret Key. -- `SCW_DEFAULT_ORGANIZATION_ID` which is your Organization ID. ## Deploy ExternalDNS @@ -63,8 +62,6 @@ spec: value: "" - name: SCW_SECRET_KEY value: "" - - name: SCW_DEFAULT_ORGANIZATION_ID - value: "" ``` ### Manifest (for clusters with RBAC enabled) @@ -131,8 +128,6 @@ spec: value: "" - name: SCW_SECRET_KEY value: "" - - name: SCW_DEFAULT_ORGANIZATION_ID - value: "" ``` From 5a465842214cbf0defcf9dfa24998122e9ec7a15 Mon Sep 17 00:00:00 2001 From: Ole Markus With Date: Sun, 28 Mar 2021 14:54:39 +0200 Subject: [PATCH 096/175] Add pod source Pod source is a key feature of kOps' DNS Controller. Among other things, i is used for etcd and API discovery. --- README.md | 3 + pkg/apis/externaldns/types.go | 2 +- source/pod.go | 123 ++++++++++++ source/pod_test.go | 350 ++++++++++++++++++++++++++++++++++ source/store.go | 6 + 5 files changed, 483 insertions(+), 1 deletion(-) create mode 100644 source/pod.go create mode 100644 source/pod_test.go diff --git a/README.md b/README.md index 0155aa335..0d27eb7f0 100644 --- a/README.md +++ b/README.md @@ -282,6 +282,9 @@ Here's a rough outline on what is to come (subject to change): ### v1.0 - [ ] Ability to replace Kops' [DNS Controller](https://github.com/kubernetes/kops/tree/HEAD/dns-controller) + - [x] Add support for pod source + - [ ] Add support for DNS Controller annotations for pod, ingress, and service sources + - [ ] Add support for kOps gossip provider - [x] Ability to replace Zalando's [Mate](https://github.com/linki/mate) - [x] Ability to replace Molecule Software's [route53-kubernetes](https://github.com/wearemolecule/route53-kubernetes) diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 566d19f73..0a802abab 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -343,7 +343,7 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("skipper-routegroup-groupversion", "The resource version for skipper routegroup").Default(source.DefaultRoutegroupVersion).StringVar(&cfg.SkipperRouteGroupVersion) // Flags related to processing sources - app.Flag("source", "The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress, node, fake, connector, istio-gateway, istio-virtualservice, cloudfoundry, contour-ingressroute, contour-httpproxy, gloo-proxy, crd, empty, skipper-routegroup, openshift-route, ambassador-host)").Required().PlaceHolder("source").EnumsVar(&cfg.Sources, "service", "ingress", "node", "istio-gateway", "istio-virtualservice", "cloudfoundry", "contour-ingressroute", "contour-httpproxy", "gloo-proxy", "fake", "connector", "crd", "empty", "skipper-routegroup", "openshift-route", "ambassador-host") + app.Flag("source", "The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress, node, fake, connector, istio-gateway, istio-virtualservice, cloudfoundry, contour-ingressroute, contour-httpproxy, gloo-proxy, crd, empty, skipper-routegroup, openshift-route, ambassador-host)").Required().PlaceHolder("source").EnumsVar(&cfg.Sources, "service", "ingress", "node", "pod", "istio-gateway", "istio-virtualservice", "cloudfoundry", "contour-ingressroute", "contour-httpproxy", "gloo-proxy", "fake", "connector", "crd", "empty", "skipper-routegroup", "openshift-route", "ambassador-host") app.Flag("namespace", "Limit sources of endpoints to a specific namespace (default: all namespaces)").Default(defaultConfig.Namespace).StringVar(&cfg.Namespace) app.Flag("annotation-filter", "Filter sources managed by external-dns via annotation using label selector semantics (default: all sources)").Default(defaultConfig.AnnotationFilter).StringVar(&cfg.AnnotationFilter) app.Flag("label-filter", "Filter sources managed by external-dns via label selector when listing all resources; currently only supported by source CRD").Default(defaultConfig.LabelFilter).StringVar(&cfg.LabelFilter) diff --git a/source/pod.go b/source/pod.go new file mode 100644 index 000000000..ed0bb9ceb --- /dev/null +++ b/source/pod.go @@ -0,0 +1,123 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package source + +import ( + "context" + "fmt" + "time" + + "sigs.k8s.io/external-dns/endpoint" + + log "github.com/sirupsen/logrus" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/util/wait" + kubeinformers "k8s.io/client-go/informers" + coreinformers "k8s.io/client-go/informers/core/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/cache" +) + +type podSource struct { + client kubernetes.Interface + namespace string + podInformer coreinformers.PodInformer + nodeInformer coreinformers.NodeInformer +} + +// NewPodSource creates a new podSource with the given config. +func NewPodSource(kubeClient kubernetes.Interface, namespace string) (Source, error) { + informerFactory := kubeinformers.NewSharedInformerFactoryWithOptions(kubeClient, 0, kubeinformers.WithNamespace(namespace)) + podInformer := informerFactory.Core().V1().Pods() + nodeInformer := informerFactory.Core().V1().Nodes() + + podInformer.Informer().AddEventHandler( + cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + }, + }, + ) + nodeInformer.Informer().AddEventHandler( + cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + }, + }, + ) + + informerFactory.Start(wait.NeverStop) + + // wait for the local cache to be populated. + err := poll(time.Second, 60*time.Second, func() (bool, error) { + return podInformer.Informer().HasSynced() && + nodeInformer.Informer().HasSynced(), nil + }) + if err != nil { + return nil, fmt.Errorf("failed to sync cache: %v", err) + } + + return &podSource{ + client: kubeClient, + podInformer: podInformer, + nodeInformer: nodeInformer, + namespace: namespace, + }, nil +} + +func (*podSource) AddEventHandler(ctx context.Context, handler func()) { + +} + +func (ps *podSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error) { + pods, err := ps.podInformer.Lister().Pods(ps.namespace).List(labels.Everything()) + if err != nil { + return nil, err + } + + domains := make(map[string][]string) + for _, pod := range pods { + if !pod.Spec.HostNetwork { + log.Debugf("skipping pod %s. hostNetwork=false", pod.Name) + continue + } + + if domain, ok := pod.Annotations[internalHostnameAnnotationKey]; ok { + if _, ok := domains[domain]; !ok { + domains[domain] = []string{} + } + domains[domain] = append(domains[domain], pod.Status.PodIP) + } + + if domain, ok := pod.Annotations[hostnameAnnotationKey]; ok { + if _, ok := domains[domain]; !ok { + domains[domain] = []string{} + } + + node, _ := ps.nodeInformer.Lister().Get(pod.Spec.NodeName) + for _, address := range node.Status.Addresses { + if address.Type == corev1.NodeExternalIP { + domains[domain] = append(domains[domain], address.Address) + } + } + } + } + endpoints := []*endpoint.Endpoint{} + for domain, targets := range domains { + endpoints = append(endpoints, endpoint.NewEndpoint(domain, endpoint.RecordTypeA, targets...)) + } + return endpoints, nil +} diff --git a/source/pod_test.go b/source/pod_test.go new file mode 100644 index 000000000..c471789fa --- /dev/null +++ b/source/pod_test.go @@ -0,0 +1,350 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package source + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/fake" + "sigs.k8s.io/external-dns/endpoint" +) + +// testPodSource tests that various services generate the correct endpoints. +func TestPodSource(t *testing.T) { + for _, tc := range []struct { + title string + targetNamespace string + expected []*endpoint.Endpoint + expectError bool + nodes []*corev1.Node + pods []*corev1.Pod + }{ + { + "create records based on pod's external and internal IPs", + "", + []*endpoint.Endpoint{ + {DNSName: "a.foo.example.org", Targets: endpoint.Targets{"54.10.11.1", "54.10.11.2"}, RecordType: endpoint.RecordTypeA}, + {DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"10.0.1.1", "10.0.1.2"}, RecordType: endpoint.RecordTypeA}, + }, + false, + []*corev1.Node{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-node1", + }, + Status: corev1.NodeStatus{ + Addresses: []corev1.NodeAddress{ + {Type: corev1.NodeExternalIP, Address: "54.10.11.1"}, + {Type: corev1.NodeInternalIP, Address: "10.0.1.1"}, + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-node2", + }, + Status: corev1.NodeStatus{ + Addresses: []corev1.NodeAddress{ + {Type: corev1.NodeExternalIP, Address: "54.10.11.2"}, + {Type: corev1.NodeInternalIP, Address: "10.0.1.2"}, + }, + }, + }, + }, + []*corev1.Pod{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-pod1", + Namespace: "kube-system", + Annotations: map[string]string{ + internalHostnameAnnotationKey: "internal.a.foo.example.org", + hostnameAnnotationKey: "a.foo.example.org", + }, + }, + Spec: corev1.PodSpec{ + HostNetwork: true, + NodeName: "my-node1", + }, + Status: corev1.PodStatus{ + PodIP: "10.0.1.1", + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-pod2", + Namespace: "kube-system", + Annotations: map[string]string{ + internalHostnameAnnotationKey: "internal.a.foo.example.org", + hostnameAnnotationKey: "a.foo.example.org", + }, + }, + Spec: corev1.PodSpec{ + HostNetwork: true, + NodeName: "my-node2", + }, + Status: corev1.PodStatus{ + PodIP: "10.0.1.2", + }, + }, + }, + }, + { + "create multiple records", + "", + []*endpoint.Endpoint{ + {DNSName: "a.foo.example.org", Targets: endpoint.Targets{"54.10.11.1"}, RecordType: endpoint.RecordTypeA}, + {DNSName: "b.foo.example.org", Targets: endpoint.Targets{"54.10.11.2"}, RecordType: endpoint.RecordTypeA}, + }, + false, + []*corev1.Node{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-node1", + }, + Status: corev1.NodeStatus{ + Addresses: []corev1.NodeAddress{ + {Type: corev1.NodeExternalIP, Address: "54.10.11.1"}, + {Type: corev1.NodeInternalIP, Address: "10.0.1.1"}, + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-node2", + }, + Status: corev1.NodeStatus{ + Addresses: []corev1.NodeAddress{ + {Type: corev1.NodeExternalIP, Address: "54.10.11.2"}, + {Type: corev1.NodeInternalIP, Address: "10.0.1.2"}, + }, + }, + }, + }, + []*corev1.Pod{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-pod1", + Namespace: "kube-system", + Annotations: map[string]string{ + hostnameAnnotationKey: "a.foo.example.org", + }, + }, + Spec: corev1.PodSpec{ + HostNetwork: true, + NodeName: "my-node1", + }, + Status: corev1.PodStatus{ + PodIP: "10.0.1.1", + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-pod2", + Namespace: "kube-system", + Annotations: map[string]string{ + hostnameAnnotationKey: "b.foo.example.org", + }, + }, + Spec: corev1.PodSpec{ + HostNetwork: true, + NodeName: "my-node2", + }, + Status: corev1.PodStatus{ + PodIP: "10.0.1.2", + }, + }, + }, + }, + { + "pods with hostNetwore=false should be ignored", + "", + []*endpoint.Endpoint{ + {DNSName: "a.foo.example.org", Targets: endpoint.Targets{"54.10.11.1"}, RecordType: endpoint.RecordTypeA}, + {DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"10.0.1.1"}, RecordType: endpoint.RecordTypeA}, + }, + false, + []*corev1.Node{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-node1", + }, + Status: corev1.NodeStatus{ + Addresses: []corev1.NodeAddress{ + {Type: corev1.NodeExternalIP, Address: "54.10.11.1"}, + {Type: corev1.NodeInternalIP, Address: "10.0.1.1"}, + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-node2", + }, + Status: corev1.NodeStatus{ + Addresses: []corev1.NodeAddress{ + {Type: corev1.NodeExternalIP, Address: "54.10.11.2"}, + {Type: corev1.NodeInternalIP, Address: "10.0.1.2"}, + }, + }, + }, + }, + []*corev1.Pod{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-pod1", + Namespace: "kube-system", + Annotations: map[string]string{ + internalHostnameAnnotationKey: "internal.a.foo.example.org", + hostnameAnnotationKey: "a.foo.example.org", + }, + }, + Spec: corev1.PodSpec{ + HostNetwork: true, + NodeName: "my-node1", + }, + Status: corev1.PodStatus{ + PodIP: "10.0.1.1", + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-pod2", + Namespace: "kube-system", + Annotations: map[string]string{ + internalHostnameAnnotationKey: "internal.a.foo.example.org", + hostnameAnnotationKey: "a.foo.example.org", + }, + }, + Spec: corev1.PodSpec{ + HostNetwork: false, + NodeName: "my-node2", + }, + Status: corev1.PodStatus{ + PodIP: "100.0.1.2", + }, + }, + }, + }, + { + "only watch a given namespace", + "kube-system", + []*endpoint.Endpoint{ + {DNSName: "a.foo.example.org", Targets: endpoint.Targets{"54.10.11.1"}, RecordType: endpoint.RecordTypeA}, + {DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"10.0.1.1"}, RecordType: endpoint.RecordTypeA}, + }, + false, + []*corev1.Node{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-node1", + }, + Status: corev1.NodeStatus{ + Addresses: []corev1.NodeAddress{ + {Type: corev1.NodeExternalIP, Address: "54.10.11.1"}, + {Type: corev1.NodeInternalIP, Address: "10.0.1.1"}, + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-node2", + }, + Status: corev1.NodeStatus{ + Addresses: []corev1.NodeAddress{ + {Type: corev1.NodeExternalIP, Address: "54.10.11.2"}, + {Type: corev1.NodeInternalIP, Address: "10.0.1.2"}, + }, + }, + }, + }, + []*corev1.Pod{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-pod1", + Namespace: "kube-system", + Annotations: map[string]string{ + internalHostnameAnnotationKey: "internal.a.foo.example.org", + hostnameAnnotationKey: "a.foo.example.org", + }, + }, + Spec: corev1.PodSpec{ + HostNetwork: true, + NodeName: "my-node1", + }, + Status: corev1.PodStatus{ + PodIP: "10.0.1.1", + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-pod2", + Namespace: "default", + Annotations: map[string]string{ + internalHostnameAnnotationKey: "internal.a.foo.example.org", + hostnameAnnotationKey: "a.foo.example.org", + }, + }, + Spec: corev1.PodSpec{ + HostNetwork: true, + NodeName: "my-node2", + }, + Status: corev1.PodStatus{ + PodIP: "100.0.1.2", + }, + }, + }, + }, + } { + t.Run(tc.title, func(t *testing.T) { + // Create a Kubernetes testing client + kubernetes := fake.NewSimpleClientset() + ctx := context.Background() + + // Create the nodes + for _, node := range tc.nodes { + if _, err := kubernetes.CoreV1().Nodes().Create(ctx, node, metav1.CreateOptions{}); err != nil { + t.Fatal(err) + } + } + + for _, pod := range tc.pods { + pods := kubernetes.CoreV1().Pods(pod.Namespace) + + if _, err := pods.Create(ctx, pod, metav1.CreateOptions{}); err != nil { + t.Fatal(err) + } + } + + client, err := NewPodSource(kubernetes, tc.targetNamespace) + require.NoError(t, err) + + endpoints, err := client.Endpoints(ctx) + if tc.expectError { + require.Error(t, err) + } else { + require.NoError(t, err) + } + + // Validate returned endpoints against desired endpoints. + validateEndpoints(t, endpoints, tc.expected) + }) + + } +} diff --git a/source/store.go b/source/store.go index 0c934c407..8bff6a056 100644 --- a/source/store.go +++ b/source/store.go @@ -188,6 +188,12 @@ func BuildWithConfig(source string, p ClientGenerator, cfg *Config) (Source, err return nil, err } return NewIngressSource(client, cfg.Namespace, cfg.AnnotationFilter, cfg.FQDNTemplate, cfg.CombineFQDNAndAnnotation, cfg.IgnoreHostnameAnnotation, cfg.IgnoreIngressTLSSpec) + case "pod": + client, err := p.KubeClient() + if err != nil { + return nil, err + } + return NewPodSource(client, cfg.Namespace) case "istio-gateway": kubernetesClient, err := p.KubeClient() if err != nil { From 663459d43650e771c55604e3a34292fc5ae2ce2f Mon Sep 17 00:00:00 2001 From: brross <49499414+brross@users.noreply.github.com> Date: Wed, 31 Mar 2021 18:10:46 -0700 Subject: [PATCH 097/175] Add 'bluecat' as possible option to the provider flag 'bluecat' was missing from the enumerated list of possible values for the provider flag --- pkg/apis/externaldns/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 566d19f73..342082625 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -362,7 +362,7 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("managed-record-types", "Comma separated list of record types to manage (default: A, CNAME) (supported records: CNAME, A, NS").Default("A", "CNAME").StringsVar(&cfg.ManagedDNSRecordTypes) // Flags related to providers - app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, aws-sd, godaddy, google, azure, azure-dns, azure-private-dns, bluecat, cloudflare, rcodezero, digitalocean, hetzner, dnsimple, akamai, infoblox, dyn, designate, coredns, skydns, inmemory, ovh, pdns, oci, exoscale, linode, rfc2136, ns1, transip, vinyldns, rdns, scaleway, vultr, ultradns)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "aws-sd", "google", "azure", "azure-dns", "hetzner", "azure-private-dns", "alibabacloud", "cloudflare", "rcodezero", "digitalocean", "dnsimple", "akamai", "infoblox", "dyn", "designate", "coredns", "skydns", "inmemory", "ovh", "pdns", "oci", "exoscale", "linode", "rfc2136", "ns1", "transip", "vinyldns", "rdns", "scaleway", "vultr", "ultradns", "godaddy") + app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, aws-sd, godaddy, google, azure, azure-dns, azure-private-dns, bluecat, cloudflare, rcodezero, digitalocean, hetzner, dnsimple, akamai, infoblox, dyn, designate, coredns, skydns, inmemory, ovh, pdns, oci, exoscale, linode, rfc2136, ns1, transip, vinyldns, rdns, scaleway, vultr, ultradns)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "aws-sd", "google", "azure", "azure-dns", "hetzner", "azure-private-dns", "alibabacloud", "cloudflare", "rcodezero", "digitalocean", "dnsimple", "akamai", "infoblox", "dyn", "designate", "coredns", "skydns", "inmemory", "ovh", "pdns", "oci", "exoscale", "linode", "rfc2136", "ns1", "transip", "vinyldns", "rdns", "scaleway", "vultr", "ultradns", "godaddy", "bluecat") app.Flag("domain-filter", "Limit possible target zones by a domain suffix; specify multiple times for multiple domains (optional)").Default("").StringsVar(&cfg.DomainFilter) app.Flag("exclude-domains", "Exclude subdomains (optional)").Default("").StringsVar(&cfg.ExcludeDomains) app.Flag("zone-name-filter", "Filter target zones by zone domain (For now, only AzureDNS provider is using this flag); specify multiple times for multiple zones (optional)").Default("").StringsVar(&cfg.ZoneNameFilter) From 98284a94a5ed3eecdf8638c44e4ada9d8248e14d Mon Sep 17 00:00:00 2001 From: Allen Porter Date: Wed, 31 Mar 2021 23:47:21 -0700 Subject: [PATCH 098/175] Add unit test that exercises behavior of headless endpoint with no TargetRef. --- source/service_test.go | 58 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/source/service_test.go b/source/service_test.go index 9349e7698..d69b88a73 100644 --- a/source/service_test.go +++ b/source/service_test.go @@ -2423,6 +2423,7 @@ func TestHeadlessServicesHostIP(t *testing.T) { podnames []string hostnames []string podsReady []bool + targetRefs []*v1.ObjectReference publishNotReadyAddresses bool expected []*endpoint.Endpoint expectError bool @@ -2449,6 +2450,10 @@ func TestHeadlessServicesHostIP(t *testing.T) { []string{"foo-0", "foo-1"}, []string{"foo-0", "foo-1"}, []bool{true, true}, + []*v1.ObjectReference{ + {APIVersion: "", Kind: "Pod", Name: "foo-0"}, + {APIVersion: "", Kind: "Pod", Name: "foo-1"}, + }, false, []*endpoint.Endpoint{ {DNSName: "foo-0.service.example.org", Targets: endpoint.Targets{"1.1.1.1"}}, @@ -2479,6 +2484,10 @@ func TestHeadlessServicesHostIP(t *testing.T) { []string{"foo-0", "foo-1"}, []string{"foo-0", "foo-1"}, []bool{true, true}, + []*v1.ObjectReference{ + {APIVersion: "", Kind: "Pod", Name: "foo-0"}, + {APIVersion: "", Kind: "Pod", Name: "foo-1"}, + }, false, []*endpoint.Endpoint{}, false, @@ -2506,6 +2515,10 @@ func TestHeadlessServicesHostIP(t *testing.T) { []string{"foo-0", "foo-1"}, []string{"foo-0", "foo-1"}, []bool{true, true}, + []*v1.ObjectReference{ + {APIVersion: "", Kind: "Pod", Name: "foo-0"}, + {APIVersion: "", Kind: "Pod", Name: "foo-1"}, + }, false, []*endpoint.Endpoint{ {DNSName: "foo-0.service.example.org", Targets: endpoint.Targets{"1.1.1.1"}, RecordTTL: endpoint.TTL(1)}, @@ -2536,6 +2549,10 @@ func TestHeadlessServicesHostIP(t *testing.T) { []string{"foo-0", "foo-1"}, []string{"foo-0", "foo-1"}, []bool{true, false}, + []*v1.ObjectReference{ + {APIVersion: "", Kind: "Pod", Name: "foo-0"}, + {APIVersion: "", Kind: "Pod", Name: "foo-1"}, + }, false, []*endpoint.Endpoint{ {DNSName: "foo-0.service.example.org", Targets: endpoint.Targets{"1.1.1.1"}}, @@ -2565,6 +2582,10 @@ func TestHeadlessServicesHostIP(t *testing.T) { []string{"foo-0", "foo-1"}, []string{"foo-0", "foo-1"}, []bool{true, false}, + []*v1.ObjectReference{ + {APIVersion: "", Kind: "Pod", Name: "foo-0"}, + {APIVersion: "", Kind: "Pod", Name: "foo-1"}, + }, true, []*endpoint.Endpoint{ {DNSName: "foo-0.service.example.org", Targets: endpoint.Targets{"1.1.1.1"}}, @@ -2595,12 +2616,43 @@ func TestHeadlessServicesHostIP(t *testing.T) { []string{"foo-0", "foo-1"}, []string{"", ""}, []bool{true, true}, + []*v1.ObjectReference{ + {APIVersion: "", Kind: "Pod", Name: "foo-0"}, + {APIVersion: "", Kind: "Pod", Name: "foo-1"}, + }, false, []*endpoint.Endpoint{ {DNSName: "service.example.org", Targets: endpoint.Targets{"1.1.1.1", "1.1.1.2"}}, }, false, }, + { + "annotated Headless services without a targetRef has no endpoints", + "", + "testing", + "foo", + v1.ServiceTypeClusterIP, + "", + "", + false, + map[string]string{"component": "foo"}, + map[string]string{ + hostnameAnnotationKey: "service.example.org", + }, + v1.ClusterIPNone, + []string{"1.1.1.1"}, + map[string]string{ + "component": "foo", + }, + []string{}, + []string{"foo-0"}, + []string{"foo-0"}, + []bool{true, true}, + []*v1.ObjectReference{nil}, + false, + []*endpoint.Endpoint{}, + false, + }, } { t.Run(tc.title, func(t *testing.T) { // Create a Kubernetes testing client @@ -2648,11 +2700,7 @@ func TestHeadlessServicesHostIP(t *testing.T) { address := v1.EndpointAddress{ IP: "4.3.2.1", - TargetRef: &v1.ObjectReference{ - APIVersion: "", - Kind: "Pod", - Name: podname, - }, + TargetRef: tc.targetRefs[i], } if tc.podsReady[i] { addresses = append(addresses, address) From b5f7570c356065cb61ca8df036415ae50cb3b9cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20St=C3=A4hlin?= Date: Wed, 31 Mar 2021 22:47:51 +0200 Subject: [PATCH 099/175] Add Gandi provider --- README.md | 3 + docs/tutorials/gandi.md | 191 +++++++++ go.mod | 1 + go.sum | 3 + main.go | 3 + pkg/apis/externaldns/types.go | 2 +- provider/gandi/client.go | 120 ++++++ provider/gandi/gandi.go | 268 ++++++++++++ provider/gandi/gandi_test.go | 755 ++++++++++++++++++++++++++++++++++ 9 files changed, 1345 insertions(+), 1 deletion(-) create mode 100644 docs/tutorials/gandi.md create mode 100644 provider/gandi/client.go create mode 100644 provider/gandi/gandi.go create mode 100644 provider/gandi/gandi_test.go diff --git a/README.md b/README.md index 0155aa335..6596cf9ca 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ ExternalDNS' current release is `v0.7`. This version allows you to keep selected * [Scaleway](https://www.scaleway.com) * [Akamai Edge DNS](https://learn.akamai.com/en-us/products/cloud_security/edge_dns.html) * [GoDaddy](https://www.godaddy.com) +* [Gandi](https://www.gandi.net) From this release, ExternalDNS can become aware of the records it is managing (enabled via `--registry=txt`), therefore ExternalDNS can safely manage non-empty hosted zones. We strongly encourage you to use `v0.5` (or greater) with `--registry=txt` enabled and `--txt-owner-id` set to a unique value that doesn't change for the lifetime of your cluster. You might also want to run ExternalDNS in a dry run mode (`--dry-run` flag) to see the changes to be submitted to your DNS Provider API. @@ -107,6 +108,7 @@ The following table clarifies the current status of the providers according to t | Vultr | Alpha | | | UltraDNS | Alpha | | | GoDaddy | Alpha | | +| Gandi | Alpha | @packi | ## Running ExternalDNS: @@ -160,6 +162,7 @@ The following tutorials are provided: * [Vultr](docs/tutorials/vultr.md) * [UltraDNS](docs/tutorials/ultradns.md) * [GoDaddy](docs/tutorials/godaddy.md) +* [Gandi](docs/tutorials/gandi.md) ### Running Locally diff --git a/docs/tutorials/gandi.md b/docs/tutorials/gandi.md new file mode 100644 index 000000000..c37d464fd --- /dev/null +++ b/docs/tutorials/gandi.md @@ -0,0 +1,191 @@ +# Setting up ExternalDNS for Services on Gandi + +This tutorial describes how to setup ExternalDNS for usage within a Kubernetes cluster using Gandi. + +Make sure to use **>=0.7.7** version of ExternalDNS for this tutorial. + +## Creating a Gandi DNS zone (domain) + +Create a new DNS zone where you want to create your records in. Let's use `example.com` as an example here. Make sure the zone uses + +## Creating Gandi API Key + +Generate an API key on [your account](https://account.gandi.net) (click on "Security"). + +The environment variable `GANDI_KEY` will be needed to run ExternalDNS with Gandi. + +## Deploy ExternalDNS + +Connect your `kubectl` client to the cluster you want to test ExternalDNS with. +Then apply one of the following manifests file to deploy ExternalDNS. + +### Manifest (for clusters without RBAC enabled) +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: external-dns +spec: + replicas: 1 + selector: + matchLabels: + app: external-dns + strategy: + type: Recreate + template: + metadata: + labels: + app: external-dns + spec: + containers: + - name: external-dns + image: k8s.gcr.io/external-dns/external-dns:v0.7.7 + args: + - --source=service # ingress is also possible + - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. + - --provider=gandi + env: + - name: GANDI_KEY + value: "YOUR_GANDI_API_KEY" +``` + +### Manifest (for clusters with RBAC enabled) +```yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: external-dns +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: external-dns +rules: +- apiGroups: [""] + resources: ["services","endpoints","pods"] + verbs: ["get","watch","list"] +- apiGroups: ["extensions","networking.k8s.io"] + resources: ["ingresses"] + verbs: ["get","watch","list"] +- apiGroups: [""] + resources: ["nodes"] + verbs: ["list","watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: external-dns-viewer +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: external-dns +subjects: +- kind: ServiceAccount + name: external-dns + namespace: default +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: external-dns +spec: + replicas: 1 + selector: + matchLabels: + app: external-dns + strategy: + type: Recreate + template: + metadata: + labels: + app: external-dns + spec: + serviceAccountName: external-dns + containers: + - name: external-dns + image: k8s.gcr.io/external-dns/external-dns:v0.7.7 + args: + - --source=service # ingress is also possible + - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. + - --provider=gandi + env: + - name: GANDI_KEY + value: "YOUR_GANDI_API_KEY" +``` + + +## Deploying an Nginx Service + +Create a service file called 'nginx.yaml' with the following contents: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx +spec: + replicas: 1 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx + name: nginx + ports: + - containerPort: 80 +--- +apiVersion: v1 +kind: Service +metadata: + name: nginx + annotations: + external-dns.alpha.kubernetes.io/hostname: my-app.example.com +spec: + selector: + app: nginx + type: LoadBalancer + ports: + - protocol: TCP + port: 80 + targetPort: 80 +``` + +Note the annotation on the service; use the same hostname as the Gandi Domain. Make sure that your Domain is configured to use Live-DNS. + +ExternalDNS uses this annotation to determine what services should be registered with DNS. Removing the annotation will cause ExternalDNS to remove the corresponding DNS records. + +Create the deployment and service: + +```console +$ kubectl create -f nginx.yaml +``` + +Depending where you run your service it can take a little while for your cloud provider to create an external IP for the service. + +Once the service has an external IP assigned, ExternalDNS will notice the new service IP address and synchronize the Gandi DNS records. + +## Verifying Gandi DNS records + +Check your [Gandi Dashboard](https://admin.gandi.net/domain) to view the records for your Gandi DNS zone. + +Click on the zone for the one created above if a different domain was used. + +This should show the external IP address of the service as the A record for your domain. + +## Cleanup + +Now that we have verified that ExternalDNS will automatically manage Gandi DNS records, we can delete the tutorial's example: + +``` +$ kubectl delete service -f nginx.yaml +$ kubectl delete service -f externaldns.yaml +``` + +# Additional options + +If you're using organizations to separate your domains, you can pass the organization's ID in an environment variable called `GANDI_SHARING_ID` to get access to it. diff --git a/go.mod b/go.mod index 28644e915..49da323b9 100644 --- a/go.mod +++ b/go.mod @@ -26,6 +26,7 @@ require ( github.com/exoscale/egoscale v0.18.1 github.com/fatih/structs v1.1.0 // indirect github.com/ffledgling/pdns-go v0.0.0-20180219074714-524e7daccd99 + github.com/go-gandi/go-gandi v0.0.0-20200921091836-0d8a64b9cc09 github.com/golang/sync v0.0.0-20180314180146-1d60e4601c6f github.com/google/go-cmp v0.4.1 github.com/gophercloud/gophercloud v0.1.0 diff --git a/go.sum b/go.sum index 8a5a6e67b..960227ef8 100644 --- a/go.sum +++ b/go.sum @@ -84,6 +84,7 @@ github.com/alecthomas/colour v0.1.0 h1:nOE9rJm6dsZ66RGWYSFrXw461ZIt9A6+nHgL7FRrD github.com/alecthomas/colour v0.1.0/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0= github.com/alecthomas/kingpin v2.2.5+incompatible h1:umWl1NNd72+ZvRti3T9C0SYean2hPZ7ZhxU8bsgc9BQ= github.com/alecthomas/kingpin v2.2.5+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= +github.com/alecthomas/kong v0.2.2/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE= github.com/alecthomas/repr v0.0.0-20200325044227-4184120f674c h1:MVVbswUlqicyj8P/JljoocA7AyCo62gzD0O7jfvrhtE= github.com/alecthomas/repr v0.0.0-20200325044227-4184120f674c/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -266,6 +267,8 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gandi/go-gandi v0.0.0-20200921091836-0d8a64b9cc09 h1:w+iZczt5J4LJa13RX5uguKI866vIEMOESgXr4XcwrwA= +github.com/go-gandi/go-gandi v0.0.0-20200921091836-0d8a64b9cc09/go.mod h1:Vv36tv/GTi8FNAFIQ88+9GPHm4CAihAuJu7rfqRJ9aY= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= diff --git a/main.go b/main.go index 571772b79..5d52110a9 100644 --- a/main.go +++ b/main.go @@ -47,6 +47,7 @@ import ( "sigs.k8s.io/external-dns/provider/dnsimple" "sigs.k8s.io/external-dns/provider/dyn" "sigs.k8s.io/external-dns/provider/exoscale" + "sigs.k8s.io/external-dns/provider/gandi" "sigs.k8s.io/external-dns/provider/godaddy" "sigs.k8s.io/external-dns/provider/google" "sigs.k8s.io/external-dns/provider/hetzner" @@ -305,6 +306,8 @@ func main() { p, err = scaleway.NewScalewayProvider(ctx, domainFilter, cfg.DryRun) case "godaddy": p, err = godaddy.NewGoDaddyProvider(ctx, domainFilter, cfg.GoDaddyTTL, cfg.GoDaddyAPIKey, cfg.GoDaddySecretKey, cfg.GoDaddyOTE, cfg.DryRun) + case "gandi": + p, err = gandi.NewGandiProvider(ctx, domainFilter, cfg.DryRun) default: log.Fatalf("unknown dns provider: %s", cfg.Provider) } diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 342082625..b8f29cda5 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -362,7 +362,7 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("managed-record-types", "Comma separated list of record types to manage (default: A, CNAME) (supported records: CNAME, A, NS").Default("A", "CNAME").StringsVar(&cfg.ManagedDNSRecordTypes) // Flags related to providers - app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, aws-sd, godaddy, google, azure, azure-dns, azure-private-dns, bluecat, cloudflare, rcodezero, digitalocean, hetzner, dnsimple, akamai, infoblox, dyn, designate, coredns, skydns, inmemory, ovh, pdns, oci, exoscale, linode, rfc2136, ns1, transip, vinyldns, rdns, scaleway, vultr, ultradns)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "aws-sd", "google", "azure", "azure-dns", "hetzner", "azure-private-dns", "alibabacloud", "cloudflare", "rcodezero", "digitalocean", "dnsimple", "akamai", "infoblox", "dyn", "designate", "coredns", "skydns", "inmemory", "ovh", "pdns", "oci", "exoscale", "linode", "rfc2136", "ns1", "transip", "vinyldns", "rdns", "scaleway", "vultr", "ultradns", "godaddy", "bluecat") + app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, aws-sd, godaddy, google, azure, azure-dns, azure-private-dns, bluecat, cloudflare, rcodezero, digitalocean, hetzner, dnsimple, akamai, infoblox, dyn, designate, coredns, skydns, inmemory, ovh, pdns, oci, exoscale, linode, rfc2136, ns1, transip, vinyldns, rdns, scaleway, vultr, ultradns, gandi)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "aws-sd", "google", "azure", "azure-dns", "hetzner", "azure-private-dns", "alibabacloud", "cloudflare", "rcodezero", "digitalocean", "dnsimple", "akamai", "infoblox", "dyn", "designate", "coredns", "skydns", "inmemory", "ovh", "pdns", "oci", "exoscale", "linode", "rfc2136", "ns1", "transip", "vinyldns", "rdns", "scaleway", "vultr", "ultradns", "godaddy", "bluecat", "gandi") app.Flag("domain-filter", "Limit possible target zones by a domain suffix; specify multiple times for multiple domains (optional)").Default("").StringsVar(&cfg.DomainFilter) app.Flag("exclude-domains", "Exclude subdomains (optional)").Default("").StringsVar(&cfg.ExcludeDomains) app.Flag("zone-name-filter", "Filter target zones by zone domain (For now, only AzureDNS provider is using this flag); specify multiple times for multiple zones (optional)").Default("").StringsVar(&cfg.ZoneNameFilter) diff --git a/provider/gandi/client.go b/provider/gandi/client.go new file mode 100644 index 000000000..93e31e5ee --- /dev/null +++ b/provider/gandi/client.go @@ -0,0 +1,120 @@ +/* +Copyright 2021 The Kubernetes Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package gandi + +import ( + "github.com/go-gandi/go-gandi/domain" + "github.com/go-gandi/go-gandi/livedns" +) + +type DomainClientAdapter interface { + ListDomains() (domains []domain.ListResponse, err error) +} + +type DomainClient struct { + Client *domain.Domain +} + +func (p *DomainClient) ListDomains() (domains []domain.ListResponse, err error) { + return p.Client.ListDomains() +} + +func NewDomainClient(client *domain.Domain) DomainClientAdapter { + return &DomainClient{client} +} + +// StandardResponse copied from go-gandi/internal/gandi.go +type StandardResponse struct { + Code int `json:"code,omitempty"` + Message string `json:"message,omitempty"` + UUID string `json:"uuid,omitempty"` + Object string `json:"object,omitempty"` + Cause string `json:"cause,omitempty"` + Status string `json:"status,omitempty"` + Errors []StandardError `json:"errors,omitempty"` +} + +// StandardError copied from go-gandi/internal/gandi.go +type StandardError struct { + Location string `json:"location"` + Name string `json:"name"` + Description string `json:"description"` +} + +type LiveDNSClientAdapter interface { + GetDomainRecords(fqdn string) (records []livedns.DomainRecord, err error) + CreateDomainRecord(fqdn, name, recordtype string, ttl int, values []string) (response StandardResponse, err error) + DeleteDomainRecord(fqdn, name, recordtype string) (err error) + UpdateDomainRecordByNameAndType(fqdn, name, recordtype string, ttl int, values []string) (response StandardResponse, err error) +} + +type LiveDNSClient struct { + Client *livedns.LiveDNS +} + +func NewLiveDNSClient(client *livedns.LiveDNS) LiveDNSClientAdapter { + return &LiveDNSClient{client} +} + +func (p *LiveDNSClient) GetDomainRecords(fqdn string) (records []livedns.DomainRecord, err error) { + return p.Client.GetDomainRecords(fqdn) +} + +func (p *LiveDNSClient) CreateDomainRecord(fqdn, name, recordtype string, ttl int, values []string) (response StandardResponse, err error) { + res, err := p.Client.CreateDomainRecord(fqdn, name, recordtype, ttl, values) + if err != nil { + return StandardResponse{}, err + } + + // response needs to be copied as the Standard* structs are internal + var errors []StandardError + for _, e := range res.Errors { + errors = append(errors, StandardError(e)) + } + return StandardResponse{ + Code: res.Code, + Message: res.Message, + UUID: res.UUID, + Object: res.Object, + Cause: res.Cause, + Status: res.Status, + Errors: errors, + }, err +} + +func (p *LiveDNSClient) DeleteDomainRecord(fqdn, name, recordtype string) (err error) { + return p.Client.DeleteDomainRecord(fqdn, name, recordtype) +} + +func (p *LiveDNSClient) UpdateDomainRecordByNameAndType(fqdn, name, recordtype string, ttl int, values []string) (response StandardResponse, err error) { + res, err := p.Client.UpdateDomainRecordByNameAndType(fqdn, name, recordtype, ttl, values) + if err != nil { + return StandardResponse{}, err + } + + // response needs to be copied as the Standard* structs are internal + var errors []StandardError + for _, e := range res.Errors { + errors = append(errors, StandardError(e)) + } + return StandardResponse{ + Code: res.Code, + Message: res.Message, + UUID: res.UUID, + Object: res.Object, + Cause: res.Cause, + Status: res.Status, + Errors: errors, + }, err +} diff --git a/provider/gandi/gandi.go b/provider/gandi/gandi.go new file mode 100644 index 000000000..d239238cc --- /dev/null +++ b/provider/gandi/gandi.go @@ -0,0 +1,268 @@ +/* +Copyright 2021 The Kubernetes Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package gandi + +import ( + "context" + "errors" + "fmt" + "os" + "strings" + + "github.com/go-gandi/go-gandi" + "github.com/go-gandi/go-gandi/livedns" + log "github.com/sirupsen/logrus" + + "sigs.k8s.io/external-dns/endpoint" + "sigs.k8s.io/external-dns/plan" + "sigs.k8s.io/external-dns/provider" +) + +const ( + gandiCreate = "CREATE" + gandiDelete = "DELETE" + gandiUpdate = "UPDATE" + gandiTTL = 600 + gandiLiveDNSProvider = "livedns" +) + +type GandiChanges struct { + Action string + ZoneName string + Record livedns.DomainRecord +} + +type GandiProvider struct { + provider.BaseProvider + LiveDNSClient LiveDNSClientAdapter + DomainClient DomainClientAdapter + domainFilter endpoint.DomainFilter + DryRun bool +} + +func NewGandiProvider(ctx context.Context, domainFilter endpoint.DomainFilter, dryRun bool) (*GandiProvider, error) { + key, ok := os.LookupEnv("GANDI_KEY") + if !ok { + return nil, errors.New("no environment variable GANDI_KEY provided") + } + sharingID, _ := os.LookupEnv("GANDI_SHARING_ID") + + g := gandi.Config{ + SharingID: sharingID, + Debug: false, + // dry-run doesn't work but it won't hurt passing the flag + DryRun: dryRun, + } + + liveDNSClient := gandi.NewLiveDNSClient(key, g) + domainClient := gandi.NewDomainClient(key, g) + + gandiProvider := &GandiProvider{ + LiveDNSClient: NewLiveDNSClient(liveDNSClient), + DomainClient: NewDomainClient(domainClient), + domainFilter: domainFilter, + DryRun: dryRun, + } + return gandiProvider, nil +} + +func (p *GandiProvider) Zones() (zones []string, err error) { + availableDomains, err := p.DomainClient.ListDomains() + if err != nil { + return nil, err + } + zones = []string{} + for _, domain := range availableDomains { + if !p.domainFilter.Match(domain.FQDN) { + log.Debugf("Excluding domain %s by domain-filter", domain.FQDN) + continue + } + + if domain.NameServer.Current != gandiLiveDNSProvider { + log.Debugf("Excluding domain %s, not configured for livedns", domain.FQDN) + continue + } + + zones = append(zones, domain.FQDN) + } + return zones, nil +} + +func (p *GandiProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error) { + liveDNSZones, err := p.Zones() + if err != nil { + return nil, err + } + endpoints := []*endpoint.Endpoint{} + for _, zone := range liveDNSZones { + records, err := p.LiveDNSClient.GetDomainRecords(zone) + if err != nil { + return nil, err + } + + for _, r := range records { + if provider.SupportedRecordType(r.RrsetType) { + name := r.RrsetName + "." + zone + + if r.RrsetName == "@" { + name = zone + } + + if len(r.RrsetValues) > 1 { + return nil, fmt.Errorf("can't handle multiple values for rrset %s", name) + } + + endpoints = append(endpoints, endpoint.NewEndpoint(name, r.RrsetType, r.RrsetValues[0])) + } + } + } + + return endpoints, nil +} + +func (p *GandiProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error { + combinedChanges := make([]*GandiChanges, 0, len(changes.Create)+len(changes.UpdateNew)+len(changes.Delete)) + + combinedChanges = append(combinedChanges, p.newGandiChanges(gandiCreate, changes.Create)...) + combinedChanges = append(combinedChanges, p.newGandiChanges(gandiUpdate, changes.UpdateNew)...) + combinedChanges = append(combinedChanges, p.newGandiChanges(gandiDelete, changes.Delete)...) + + return p.submitChanges(ctx, combinedChanges) +} + +func (p *GandiProvider) submitChanges(ctx context.Context, changes []*GandiChanges) error { + if len(changes) == 0 { + log.Infof("All records are already up to date") + return nil + } + + liveDNSDomains, err := p.Zones() + if err != nil { + return err + } + + zoneChanges := p.groupAndFilterByZone(liveDNSDomains, changes) + + for _, changes := range zoneChanges { + for _, change := range changes { + // Prepare record name + recordName := strings.TrimSuffix(change.Record.RrsetName, "."+change.ZoneName) + if recordName == change.ZoneName { + recordName = "@" + } + if change.Record.RrsetType == endpoint.RecordTypeCNAME && !strings.HasSuffix(change.Record.RrsetValues[0], ".") { + change.Record.RrsetValues[0] += "." + } + change.Record.RrsetName = recordName + + log.WithFields(log.Fields{ + "record": change.Record.RrsetName, + "type": change.Record.RrsetType, + "value": change.Record.RrsetValues[0], + "ttl": change.Record.RrsetTTL, + "action": change.Action, + "zone": change.ZoneName, + }).Info("Changing record") + + if !p.DryRun { + switch change.Action { + case gandiCreate: + answer, err := p.LiveDNSClient.CreateDomainRecord( + change.ZoneName, + change.Record.RrsetName, + change.Record.RrsetType, + change.Record.RrsetTTL, + change.Record.RrsetValues, + ) + if err != nil { + log.WithFields(log.Fields{ + "Code": answer.Code, + "Message": answer.Message, + "Cause": answer.Cause, + "Errors": answer.Errors, + }).Warning("Create problem") + return err + } + case gandiDelete: + err := p.LiveDNSClient.DeleteDomainRecord(change.ZoneName, change.Record.RrsetName, change.Record.RrsetType) + if err != nil { + log.Warning("Delete problem") + return err + } + case gandiUpdate: + answer, err := p.LiveDNSClient.UpdateDomainRecordByNameAndType( + change.ZoneName, + change.Record.RrsetName, + change.Record.RrsetType, + change.Record.RrsetTTL, + change.Record.RrsetValues, + ) + if err != nil { + log.WithFields(log.Fields{ + "Code": answer.Code, + "Message": answer.Message, + "Cause": answer.Cause, + "Errors": answer.Errors, + }).Warning("Update problem") + return err + } + } + } + } + } + + return nil +} + +func (p *GandiProvider) newGandiChanges(action string, endpoints []*endpoint.Endpoint) []*GandiChanges { + changes := make([]*GandiChanges, 0, len(endpoints)) + ttl := gandiTTL + for _, e := range endpoints { + if e.RecordTTL.IsConfigured() { + ttl = int(e.RecordTTL) + } + change := &GandiChanges{ + Action: action, + Record: livedns.DomainRecord{ + RrsetType: e.RecordType, + RrsetName: e.DNSName, + RrsetValues: e.Targets, + RrsetTTL: ttl, + }, + } + changes = append(changes, change) + } + return changes +} + +func (p *GandiProvider) groupAndFilterByZone(zones []string, changes []*GandiChanges) map[string][]*GandiChanges { + change := make(map[string][]*GandiChanges) + zoneNameID := provider.ZoneIDName{} + + for _, z := range zones { + zoneNameID.Add(z, z) + change[z] = []*GandiChanges{} + } + + for _, c := range changes { + zoneID, zoneName := zoneNameID.FindZone(c.Record.RrsetName) + if zoneName == "" { + log.Debugf("Skipping record %s because no hosted domain matching record DNS Name was detected", c.Record.RrsetName) + continue + } + c.ZoneName = zoneName + change[zoneID] = append(change[zoneID], c) + } + return change +} diff --git a/provider/gandi/gandi_test.go b/provider/gandi/gandi_test.go new file mode 100644 index 000000000..8b372ac7b --- /dev/null +++ b/provider/gandi/gandi_test.go @@ -0,0 +1,755 @@ +/* +Copyright 2021 The Kubernetes Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package gandi + +import ( + "context" + "fmt" + "github.com/go-gandi/go-gandi/domain" + "github.com/go-gandi/go-gandi/livedns" + "github.com/maxatome/go-testdeep/td" + "strings" + + "os" + "reflect" + "testing" + + "github.com/stretchr/testify/assert" + + "sigs.k8s.io/external-dns/endpoint" + "sigs.k8s.io/external-dns/plan" +) + +type MockAction struct { + Name string + FQDN string + Record livedns.DomainRecord +} + +type mockGandiClient struct { + Actions []MockAction + FunctionToFail string + RecordsToReturn []livedns.DomainRecord +} + +func mockGandiClientNew() *mockGandiClient { + return &mockGandiClient{ + RecordsToReturn: testRecords(), + } +} + +func mockGandiClientNewWithRecords(recordsToReturn []livedns.DomainRecord) *mockGandiClient { + return &mockGandiClient{ + RecordsToReturn: recordsToReturn, + } +} + +func mockGandiClientNewWithFailure(functionToFail string) *mockGandiClient { + return &mockGandiClient{ + FunctionToFail: functionToFail, + RecordsToReturn: testRecords(), + } +} + +func testRecords() []livedns.DomainRecord { + return []livedns.DomainRecord{ + { + RrsetType: endpoint.RecordTypeCNAME, + RrsetTTL: 600, + RrsetName: "@", + RrsetHref: "https://api.gandi.net/v5/domain/domains/example.com/records/%40/A", + RrsetValues: []string{"192.168.0.1"}, + }, + { + RrsetType: endpoint.RecordTypeCNAME, + RrsetTTL: 600, + RrsetName: "www", + RrsetHref: "https://api.gandi.net/v5/domain/domains/example.com/records/www/CNAME", + RrsetValues: []string{"lb.example.com"}, + }, + { + RrsetType: endpoint.RecordTypeA, + RrsetTTL: 600, + RrsetName: "test", + RrsetHref: "https://api.gandi.net/v5/domain/domains/example.com/records/test/A", + RrsetValues: []string{"192.168.0.2"}, + }, + } +} + +// Mock all methods + +func (m *mockGandiClient) GetDomainRecords(fqdn string) (records []livedns.DomainRecord, err error) { + m.Actions = append(m.Actions, MockAction{ + Name: "GetDomainRecords", + FQDN: fqdn, + }) + if m.FunctionToFail == "GetDomainRecords" { + return nil, fmt.Errorf("injected error") + } + + return m.RecordsToReturn, err +} + +func (m *mockGandiClient) CreateDomainRecord(fqdn, name, recordtype string, ttl int, values []string) (response StandardResponse, err error) { + m.Actions = append(m.Actions, MockAction{ + Name: "CreateDomainRecord", + FQDN: fqdn, + Record: livedns.DomainRecord{ + RrsetType: recordtype, + RrsetTTL: ttl, + RrsetName: name, + RrsetValues: values, + }, + }) + if m.FunctionToFail == "CreateDomainRecord" { + return StandardResponse{}, fmt.Errorf("injected error") + } + + return StandardResponse{}, nil +} + +func (m *mockGandiClient) DeleteDomainRecord(fqdn, name, recordtype string) (err error) { + m.Actions = append(m.Actions, MockAction{ + Name: "DeleteDomainRecord", + FQDN: fqdn, + Record: livedns.DomainRecord{ + RrsetType: recordtype, + RrsetName: name, + }, + }) + + if m.FunctionToFail == "DeleteDomainRecord" { + return fmt.Errorf("injected error") + } + + return nil +} + +func (m *mockGandiClient) UpdateDomainRecordByNameAndType(fqdn, name, recordtype string, ttl int, values []string) (response StandardResponse, err error) { + m.Actions = append(m.Actions, MockAction{ + Name: "UpdateDomainRecordByNameAndType", + FQDN: fqdn, + Record: livedns.DomainRecord{ + RrsetType: recordtype, + RrsetTTL: ttl, + RrsetName: name, + RrsetValues: values, + }, + }) + + if m.FunctionToFail == "UpdateDomainRecordByNameAndType" { + return StandardResponse{}, fmt.Errorf("injected error") + } + + return StandardResponse{}, nil +} + +func (m *mockGandiClient) ListDomains() (domains []domain.ListResponse, err error) { + m.Actions = append(m.Actions, MockAction{ + Name: "ListDomains", + }) + + if m.FunctionToFail == "ListDomains" { + return []domain.ListResponse{}, fmt.Errorf("injected error") + } + + return []domain.ListResponse{ + { + FQDN: "example.com", + FQDNUnicode: "example.com", + Href: "https://api.gandi.net/v5/domain/domains/example.com", + ID: "b3e9c271-1c29-4441-97d9-bc021a7ac7c3", + NameServer: &domain.NameServerConfig{ + Current: gandiLiveDNSProvider, + }, + TLD: "com", + }, + { + FQDN: "example.net", + FQDNUnicode: "example.net", + Href: "https://api.gandi.net/v5/domain/domains/example.net", + ID: "dc78c1d8-6143-4edb-93bc-3a20d8bc3570", + NameServer: &domain.NameServerConfig{ + Current: "other", + }, + TLD: "net", + }, + }, nil +} + +// Tests + +func TestNewGandiProvider(t *testing.T) { + _ = os.Setenv("GANDI_KEY", "myGandiKey") + provider, err := NewGandiProvider(context.Background(), endpoint.NewDomainFilter([]string{"example.com"}), true) + if err != nil { + t.Errorf("failed : %s", err) + } + assert.Equal(t, true, provider.DryRun) + + _ = os.Setenv("GANDI_SHARING_ID", "aSharingId") + provider, err = NewGandiProvider(context.Background(), endpoint.NewDomainFilter([]string{"example.com"}), false) + if err != nil { + t.Errorf("failed : %s", err) + } + assert.Equal(t, false, provider.DryRun) + + _ = os.Unsetenv("GANDI_KEY") + _, err = NewGandiProvider(context.Background(), endpoint.NewDomainFilter([]string{"example.com"}), true) + if err == nil { + t.Errorf("expected to fail") + } +} + +func TestGandiProvider_TestData(t *testing.T) { + mockedClient := mockGandiClientNew() + + // Check test zone data is ok + expectedZonesAnswer := []domain.ListResponse{ + { + FQDN: "example.com", + FQDNUnicode: "example.com", + Href: "https://api.gandi.net/v5/domain/domains/example.com", + ID: "b3e9c271-1c29-4441-97d9-bc021a7ac7c3", + NameServer: &domain.NameServerConfig{ + Current: gandiLiveDNSProvider, + }, + TLD: "com", + }, + { + FQDN: "example.net", + FQDNUnicode: "example.net", + Href: "https://api.gandi.net/v5/domain/domains/example.net", + ID: "dc78c1d8-6143-4edb-93bc-3a20d8bc3570", + NameServer: &domain.NameServerConfig{ + Current: "other", + }, + TLD: "net", + }, + } + + testingZonesAnswer, err := mockedClient.ListDomains() + if err != nil { + t.Errorf("should not fail, %s", err) + } + + if !reflect.DeepEqual(expectedZonesAnswer, testingZonesAnswer) { + t.Errorf("should be equal, %s", err) + } + + // Check test record data is ok + expectedRecordsAnswer := []livedns.DomainRecord{ + { + RrsetType: endpoint.RecordTypeCNAME, + RrsetTTL: 600, + RrsetName: "@", + RrsetHref: "https://api.gandi.net/v5/domain/domains/example.com/records/%40/A", + RrsetValues: []string{"192.168.0.1"}, + }, + { + RrsetType: endpoint.RecordTypeCNAME, + RrsetTTL: 600, + RrsetName: "www", + RrsetHref: "https://api.gandi.net/v5/domain/domains/example.com/records/www/CNAME", + RrsetValues: []string{"lb.example.com"}, + }, + { + RrsetType: endpoint.RecordTypeA, + RrsetTTL: 600, + RrsetName: "test", + RrsetHref: "https://api.gandi.net/v5/domain/domains/example.com/records/test/A", + RrsetValues: []string{"192.168.0.2"}, + }, + } + + testingRecordsAnswer, err := mockedClient.GetDomainRecords("example.com") + if err != nil { + t.Errorf("should not fail, %s", err) + } + + if !reflect.DeepEqual(expectedRecordsAnswer, testingRecordsAnswer) { + t.Errorf("should be equal, %s", err) + } + +} + +func TestGandiProvider_Records(t *testing.T) { + mockedClient := mockGandiClientNew() + + mockedProvider := &GandiProvider{ + DomainClient: mockedClient, + LiveDNSClient: mockedClient, + } + + expectedActions := []MockAction{ + { + Name: "ListDomains", + }, + { + Name: "GetDomainRecords", + FQDN: "example.com", + }, + } + + endpoints, err := mockedProvider.Records(context.Background()) + if err != nil { + t.Errorf("should not fail, %s", err) + } + assert.Equal(t, 3, len(endpoints)) + fmt.Printf("%+v\n", endpoints[0].DNSName) + assert.Equal(t, "example.com", endpoints[0].DNSName) + assert.Equal(t, endpoint.RecordTypeCNAME, endpoints[0].RecordType) + td.Cmp(t, expectedActions, mockedClient.Actions) +} + +func TestGandiProvider_RecordsAppliesDomainFilter(t *testing.T) { + + mockedClient := mockGandiClientNew() + + mockedProvider := &GandiProvider{ + DomainClient: mockedClient, + LiveDNSClient: mockedClient, + domainFilter: endpoint.NewDomainFilterWithExclusions([]string{}, []string{"example.com"}), + } + + expectedActions := []MockAction{ + { + Name: "ListDomains", + }, + } + + endpoints, err := mockedProvider.Records(context.Background()) + if err != nil { + t.Errorf("should not fail, %s", err) + } + assert.Equal(t, 0, len(endpoints)) + td.Cmp(t, expectedActions, mockedClient.Actions) +} + +func TestGandiProvider_RecordsErrorOnMultipleValues(t *testing.T) { + + mockedClient := mockGandiClientNewWithRecords([]livedns.DomainRecord{ + { + RrsetValues: []string{"foo", "bar"}, + RrsetType: endpoint.RecordTypeCNAME, + }, + }) + + mockedProvider := &GandiProvider{ + DomainClient: mockedClient, + LiveDNSClient: mockedClient, + } + + expectedActions := []MockAction{ + { + Name: "ListDomains", + }, + { + Name: "GetDomainRecords", + FQDN: "example.com", + }, + } + + endpoints, err := mockedProvider.Records(context.Background()) + if err == nil { + t.Errorf("expected to fail") + } + assert.Equal(t, 0, len(endpoints)) + assert.True(t, strings.HasPrefix(err.Error(), "can't handle multiple values for rrset")) + td.Cmp(t, expectedActions, mockedClient.Actions) +} + +func TestGandiProvider_ApplyChangesEmpty(t *testing.T) { + changes := &plan.Changes{} + mockedClient := mockGandiClientNew() + mockedProvider := &GandiProvider{ + DomainClient: mockedClient, + LiveDNSClient: mockedClient, + } + + err := mockedProvider.ApplyChanges(context.Background(), changes) + if err != nil { + t.Errorf("should not fail, %s", err) + } + + if mockedClient.Actions != nil { + t.Error("expected no changes") + } +} + +func TestGandiProvider_ApplyChanges(t *testing.T) { + changes := &plan.Changes{} + mockedClient := mockGandiClientNew() + mockedProvider := &GandiProvider{ + DomainClient: mockedClient, + LiveDNSClient: mockedClient, + } + + changes.Create = []*endpoint.Endpoint{{DNSName: "test2.example.com", Targets: endpoint.Targets{"target"}, RecordType: "A", RecordTTL: 666}} + changes.UpdateNew = []*endpoint.Endpoint{{DNSName: "test3.example.com", Targets: endpoint.Targets{"target-new"}, RecordType: "A", RecordTTL: 777}} + changes.Delete = []*endpoint.Endpoint{{DNSName: "test4.example.com", Targets: endpoint.Targets{"target-other"}, RecordType: "A"}} + + err := mockedProvider.ApplyChanges(context.Background(), changes) + if err != nil { + t.Errorf("should not fail, %s", err) + } + + td.Cmp(t, mockedClient.Actions, []MockAction{ + { + Name: "ListDomains", + }, + { + Name: "CreateDomainRecord", + FQDN: "example.com", + Record: livedns.DomainRecord{ + RrsetType: endpoint.RecordTypeA, + RrsetName: "test2", + RrsetValues: []string{"target"}, + RrsetTTL: 666, + }, + }, + { + Name: "UpdateDomainRecordByNameAndType", + FQDN: "example.com", + Record: livedns.DomainRecord{ + RrsetType: endpoint.RecordTypeA, + RrsetName: "test3", + RrsetValues: []string{"target-new"}, + RrsetTTL: 777, + }, + }, + { + Name: "DeleteDomainRecord", + FQDN: "example.com", + Record: livedns.DomainRecord{ + RrsetType: endpoint.RecordTypeA, + RrsetName: "test4", + }, + }, + }) +} + +func TestGandiProvider_ApplyChangesSkipsNonManaged(t *testing.T) { + changes := &plan.Changes{} + mockedClient := mockGandiClientNew() + mockedProvider := &GandiProvider{ + DomainClient: mockedClient, + LiveDNSClient: mockedClient, + } + + changes.Create = []*endpoint.Endpoint{{DNSName: "example.net", Targets: endpoint.Targets{"target"}}} + changes.UpdateNew = []*endpoint.Endpoint{{DNSName: "test.example.net", Targets: endpoint.Targets{"target-new"}, RecordType: "A", RecordTTL: 777}} + changes.Delete = []*endpoint.Endpoint{{DNSName: "test2.example.net", Targets: endpoint.Targets{"target"}, RecordType: "A"}} + + err := mockedProvider.ApplyChanges(context.Background(), changes) + if err != nil { + t.Errorf("should not fail, %s", err) + } + + td.Cmp(t, mockedClient.Actions, []MockAction{ + { + Name: "ListDomains", + }, + }) +} + +func TestGandiProvider_ApplyChangesCreateUpdateCname(t *testing.T) { + changes := &plan.Changes{} + mockedClient := mockGandiClientNew() + mockedProvider := &GandiProvider{ + DomainClient: mockedClient, + LiveDNSClient: mockedClient, + } + + changes.Create = []*endpoint.Endpoint{ + {DNSName: "test-cname.example.com", Targets: endpoint.Targets{"target"}, RecordTTL: 666, RecordType: "CNAME"}, + } + changes.UpdateNew = []*endpoint.Endpoint{{DNSName: "test-cname2.example.com", Targets: endpoint.Targets{"target-new"}, RecordType: "CNAME", RecordTTL: 777}} + + err := mockedProvider.ApplyChanges(context.Background(), changes) + if err != nil { + t.Errorf("should not fail, %s", err) + } + + td.Cmp(t, mockedClient.Actions, []MockAction{ + { + Name: "ListDomains", + }, + { + Name: "CreateDomainRecord", + FQDN: "example.com", + Record: livedns.DomainRecord{ + RrsetType: endpoint.RecordTypeCNAME, + RrsetName: "test-cname", + RrsetValues: []string{"target."}, + RrsetTTL: 666, + }, + }, + { + Name: "UpdateDomainRecordByNameAndType", + FQDN: "example.com", + Record: livedns.DomainRecord{ + RrsetType: endpoint.RecordTypeCNAME, + RrsetName: "test-cname2", + RrsetValues: []string{"target-new."}, + RrsetTTL: 777, + }, + }, + }) +} + +func TestGandiProvider_ApplyChangesCreateEmpty(t *testing.T) { + changes := &plan.Changes{} + mockedClient := mockGandiClientNew() + mockedProvider := &GandiProvider{ + DomainClient: mockedClient, + LiveDNSClient: mockedClient, + } + + changes.Create = []*endpoint.Endpoint{ + {DNSName: "example.com", Targets: endpoint.Targets{"target"}, RecordTTL: 666, RecordType: "A"}, + } + changes.UpdateNew = []*endpoint.Endpoint{} + + err := mockedProvider.ApplyChanges(context.Background(), changes) + if err != nil { + t.Errorf("should not fail, %s", err) + } + + td.Cmp(t, mockedClient.Actions, []MockAction{ + { + Name: "ListDomains", + }, + { + Name: "CreateDomainRecord", + FQDN: "example.com", + Record: livedns.DomainRecord{ + RrsetType: endpoint.RecordTypeA, + RrsetName: "@", + RrsetValues: []string{"target"}, + RrsetTTL: 666, + }, + }, + }) +} + +func TestGandiProvider_ApplyChangesRespectsDryRun(t *testing.T) { + changes := &plan.Changes{} + mockedClient := mockGandiClientNew() + mockedProvider := &GandiProvider{ + DomainClient: mockedClient, + LiveDNSClient: mockedClient, + DryRun: true, + } + + changes.Create = []*endpoint.Endpoint{ + {DNSName: "foo.example.com", Targets: endpoint.Targets{"target"}, RecordTTL: 666, RecordType: "A"}, + } + changes.UpdateNew = []*endpoint.Endpoint{ + {DNSName: "bar.example.com", Targets: endpoint.Targets{"target"}, RecordTTL: 666, RecordType: "A"}, + } + changes.Delete = []*endpoint.Endpoint{ + {DNSName: "baz.example.com", Targets: endpoint.Targets{"target"}, RecordTTL: 666, RecordType: "A"}, + } + + err := mockedProvider.ApplyChanges(context.Background(), changes) + if err != nil { + t.Errorf("should not fail, %s", err) + } + + td.Cmp(t, mockedClient.Actions, []MockAction{ + { + Name: "ListDomains", + }, + }) +} + +func TestGandiProvider_ApplyChangesErrorListDomains(t *testing.T) { + changes := &plan.Changes{} + mockedClient := mockGandiClientNewWithFailure("ListDomains") + mockedProvider := &GandiProvider{ + DomainClient: mockedClient, + LiveDNSClient: mockedClient, + } + + changes.Create = []*endpoint.Endpoint{ + {DNSName: "foo.example.com", Targets: endpoint.Targets{"target"}, RecordTTL: 666, RecordType: "A"}, + } + changes.UpdateNew = []*endpoint.Endpoint{ + {DNSName: "bar.example.com", Targets: endpoint.Targets{"target"}, RecordTTL: 666, RecordType: "A"}, + } + changes.Delete = []*endpoint.Endpoint{ + {DNSName: "baz.example.com", Targets: endpoint.Targets{"target"}, RecordTTL: 666, RecordType: "A"}, + } + + err := mockedProvider.ApplyChanges(context.Background(), changes) + if err == nil { + t.Error("should have failed") + } + + td.Cmp(t, mockedClient.Actions, []MockAction{ + { + Name: "ListDomains", + }, + }) +} + +func TestGandiProvider_ApplyChangesErrorCreate(t *testing.T) { + changes := &plan.Changes{} + mockedClient := mockGandiClientNewWithFailure("CreateDomainRecord") + mockedProvider := &GandiProvider{ + DomainClient: mockedClient, + LiveDNSClient: mockedClient, + } + + changes.Create = []*endpoint.Endpoint{ + {DNSName: "foo.example.com", Targets: endpoint.Targets{"target"}, RecordTTL: 666, RecordType: "A"}, + } + changes.UpdateNew = []*endpoint.Endpoint{ + {DNSName: "bar.example.com", Targets: endpoint.Targets{"target"}, RecordTTL: 666, RecordType: "A"}, + } + changes.Delete = []*endpoint.Endpoint{ + {DNSName: "baz.example.com", Targets: endpoint.Targets{"target"}, RecordTTL: 666, RecordType: "A"}, + } + + err := mockedProvider.ApplyChanges(context.Background(), changes) + if err == nil { + t.Error("should have failed") + } + + td.Cmp(t, mockedClient.Actions, []MockAction{ + { + Name: "ListDomains", + }, + { + Name: "CreateDomainRecord", + FQDN: "example.com", + Record: livedns.DomainRecord{ + RrsetType: endpoint.RecordTypeA, + RrsetName: "foo", + RrsetValues: []string{"target"}, + RrsetTTL: 666, + }, + }, + }) +} + +func TestGandiProvider_ApplyChangesErrorUpdate(t *testing.T) { + changes := &plan.Changes{} + mockedClient := mockGandiClientNewWithFailure("UpdateDomainRecordByNameAndType") + mockedProvider := &GandiProvider{ + DomainClient: mockedClient, + LiveDNSClient: mockedClient, + } + + changes.Create = []*endpoint.Endpoint{ + {DNSName: "foo.example.com", Targets: endpoint.Targets{"target"}, RecordTTL: 666, RecordType: "A"}, + } + changes.UpdateNew = []*endpoint.Endpoint{ + {DNSName: "bar.example.com", Targets: endpoint.Targets{"target"}, RecordTTL: 666, RecordType: "A"}, + } + changes.Delete = []*endpoint.Endpoint{ + {DNSName: "baz.example.com", Targets: endpoint.Targets{"target"}, RecordTTL: 666, RecordType: "A"}, + } + + err := mockedProvider.ApplyChanges(context.Background(), changes) + if err == nil { + t.Error("should have failed") + } + + td.Cmp(t, mockedClient.Actions, []MockAction{ + { + Name: "ListDomains", + }, + { + Name: "CreateDomainRecord", + FQDN: "example.com", + Record: livedns.DomainRecord{ + RrsetType: endpoint.RecordTypeA, + RrsetName: "foo", + RrsetValues: []string{"target"}, + RrsetTTL: 666, + }, + }, + { + Name: "UpdateDomainRecordByNameAndType", + FQDN: "example.com", + Record: livedns.DomainRecord{ + RrsetType: endpoint.RecordTypeA, + RrsetName: "bar", + RrsetValues: []string{"target"}, + RrsetTTL: 666, + }, + }, + }) +} + +func TestGandiProvider_ApplyChangesErrorDelete(t *testing.T) { + changes := &plan.Changes{} + mockedClient := mockGandiClientNewWithFailure("DeleteDomainRecord") + mockedProvider := &GandiProvider{ + DomainClient: mockedClient, + LiveDNSClient: mockedClient, + } + + changes.Create = []*endpoint.Endpoint{ + {DNSName: "foo.example.com", Targets: endpoint.Targets{"target"}, RecordTTL: 666, RecordType: "A"}, + } + changes.UpdateNew = []*endpoint.Endpoint{ + {DNSName: "bar.example.com", Targets: endpoint.Targets{"target"}, RecordTTL: 666, RecordType: "A"}, + } + changes.Delete = []*endpoint.Endpoint{ + {DNSName: "baz.example.com", Targets: endpoint.Targets{"target"}, RecordTTL: 666, RecordType: "A"}, + } + + err := mockedProvider.ApplyChanges(context.Background(), changes) + if err == nil { + t.Error("should have failed") + } + + td.Cmp(t, mockedClient.Actions, []MockAction{ + { + Name: "ListDomains", + }, + { + Name: "CreateDomainRecord", + FQDN: "example.com", + Record: livedns.DomainRecord{ + RrsetType: endpoint.RecordTypeA, + RrsetName: "foo", + RrsetValues: []string{"target"}, + RrsetTTL: 666, + }, + }, + { + Name: "UpdateDomainRecordByNameAndType", + FQDN: "example.com", + Record: livedns.DomainRecord{ + RrsetType: endpoint.RecordTypeA, + RrsetName: "bar", + RrsetValues: []string{"target"}, + RrsetTTL: 666, + }, + }, + { + Name: "DeleteDomainRecord", + FQDN: "example.com", + Record: livedns.DomainRecord{ + RrsetType: endpoint.RecordTypeA, + RrsetName: "baz", + }, + }, + }) +} From 0d4cf9915c3fda74e7474972d17e3db50b7d1d59 Mon Sep 17 00:00:00 2001 From: Alfred Krohmer Date: Mon, 5 Apr 2021 21:27:26 +0200 Subject: [PATCH 100/175] Address review comments --- internal/testutils/endpoint.go | 12 +++++++++++- provider/aws/aws.go | 17 ++++++++++++----- provider/aws/aws_test.go | 24 ++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/internal/testutils/endpoint.go b/internal/testutils/endpoint.go index 62e5c5465..7e8bf4d10 100644 --- a/internal/testutils/endpoint.go +++ b/internal/testutils/endpoint.go @@ -25,6 +25,12 @@ import ( /** test utility functions for endpoints verifications */ +type byNames endpoint.ProviderSpecific + +func (p byNames) Len() int { return len(p) } +func (p byNames) Swap(i, j int) { p[i], p[j] = p[j], p[i] } +func (p byNames) Less(i, j int) bool { return p[i].Name < p[j].Name } + type byAllFields []*endpoint.Endpoint func (b byAllFields) Len() int { return len(b) } @@ -102,5 +108,9 @@ func SamePlanChanges(a, b map[string][]*endpoint.Endpoint) bool { // SameProviderSpecific verifies that two maps contain the same string/string key/value pairs func SameProviderSpecific(a, b endpoint.ProviderSpecific) bool { - return reflect.DeepEqual(a, b) + sa := a + sb := b + sort.Sort(byNames(sa)) + sort.Sort(byNames(sb)) + return reflect.DeepEqual(sa, sb) } diff --git a/provider/aws/aws.go b/provider/aws/aws.go index 0cc02d237..6bec5b7e8 100644 --- a/provider/aws/aws.go +++ b/provider/aws/aws.go @@ -402,8 +402,6 @@ func (p *AWSProvider) DeleteRecords(ctx context.Context, endpoints []*endpoint.E func (p *AWSProvider) doRecords(ctx context.Context, action string, endpoints []*endpoint.Endpoint) error { zones, err := p.Zones(ctx) - p.AdjustEndpoints(endpoints) - if err != nil { return errors.Wrapf(err, "failed to list zones, aborting %s doRecords action", action) } @@ -412,6 +410,9 @@ func (p *AWSProvider) doRecords(ctx context.Context, action string, endpoints [] if err != nil { log.Errorf("failed to list records while preparing %s doRecords action: %s", action, err) } + + p.AdjustEndpoints(endpoints) + return p.submitChanges(ctx, p.newChanges(action, endpoints, records, zones), zones) } @@ -561,11 +562,16 @@ func (p *AWSProvider) newChanges(action string, endpoints []*endpoint.Endpoint, return changes } +// AdjustEndpoints modifies the provided endpoints (coming from various sources) to match +// the endpoints that the provider returns in `Records` so that the change plan will not have +// unneeded (potentially failing) changes. +// Example: CNAME endpoints pointing to ELBs will have a `alias` provider-specific property +// added to match the endpoints generated from existing alias records in Route53. func (p *AWSProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) []*endpoint.Endpoint { for _, ep := range endpoints { alias := false - if _, ok := ep.GetProviderSpecificProperty(providerSpecificAlias); ok { - alias = true + if aliasString, ok := ep.GetProviderSpecificProperty(providerSpecificAlias); ok { + alias = aliasString.Value == "true" } else if useAlias(ep, p.preferCNAME) { alias = true log.Debugf("Modifying endpoint: %v, setting %s=true", ep, providerSpecificAlias) @@ -843,7 +849,8 @@ func useAlias(ep *endpoint.Endpoint, preferCNAME bool) bool { return false } -// isAWSAlias determines if a given hostname is an AWS Alias record +// isAWSAlias determines if a given endpoint is supposed to create an AWS Alias record +// and (if so) returns the target hosted zone ID func isAWSAlias(ep *endpoint.Endpoint) string { prop, exists := ep.GetProviderSpecificProperty(providerSpecificAlias) if exists && prop.Value == "true" && ep.RecordType == endpoint.RecordTypeCNAME && len(ep.Targets) > 0 { diff --git a/provider/aws/aws_test.go b/provider/aws/aws_test.go index efc806f97..ef720e4b6 100644 --- a/provider/aws/aws_test.go +++ b/provider/aws/aws_test.go @@ -354,6 +354,30 @@ func TestAWSRecords(t *testing.T) { }) } +func TestAWSAdjustEndpoints(t *testing.T) { + provider, _ := newAWSProvider(t, endpoint.NewDomainFilter([]string{"ext-dns-test-2.teapot.zalan.do."}), provider.NewZoneIDFilter([]string{}), provider.NewZoneTypeFilter(""), defaultEvaluateTargetHealth, false, []*endpoint.Endpoint{}) + + records := []*endpoint.Endpoint{ + endpoint.NewEndpoint("a-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "8.8.8.8"), + endpoint.NewEndpoint("cname-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.example.com"), + endpoint.NewEndpoint("cname-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "alias-target.zone-2.ext-dns-test-2.teapot.zalan.do").WithProviderSpecific(providerSpecificAlias, "true"), + endpoint.NewEndpoint("cname-test-elb.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com"), + endpoint.NewEndpoint("cname-test-elb-no-alias.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "false"), + endpoint.NewEndpoint("cname-test-elb-no-eth.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false"), // eth = evaluate target health + } + + provider.AdjustEndpoints(records) + + validateEndpoints(t, records, []*endpoint.Endpoint{ + endpoint.NewEndpoint("a-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, "8.8.8.8"), + endpoint.NewEndpoint("cname-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.example.com"), + endpoint.NewEndpoint("cname-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "alias-target.zone-2.ext-dns-test-2.teapot.zalan.do").WithProviderSpecific(providerSpecificAlias, "true").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true"), + endpoint.NewEndpoint("cname-test-elb.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "true"), + endpoint.NewEndpoint("cname-test-elb-no-alias.zone-2.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "false"), + endpoint.NewEndpoint("cname-test-elb-no-eth.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeCNAME, "foo.eu-central-1.elb.amazonaws.com").WithProviderSpecific(providerSpecificAlias, "true").WithProviderSpecific(providerSpecificEvaluateTargetHealth, "false"), // eth = evaluate target health + }) +} + func TestAWSCreateRecords(t *testing.T) { customTTL := endpoint.TTL(60) provider, _ := newAWSProvider(t, endpoint.NewDomainFilter([]string{"ext-dns-test-2.teapot.zalan.do."}), provider.NewZoneIDFilter([]string{}), provider.NewZoneTypeFilter(""), defaultEvaluateTargetHealth, false, []*endpoint.Endpoint{}) From 210a952dfe0127512ee9fc5d574dae78e39d395d Mon Sep 17 00:00:00 2001 From: Sean Malloy Date: Mon, 5 Apr 2021 15:54:32 -0500 Subject: [PATCH 101/175] Add seanmalloy As Reviewer --- OWNERS | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/OWNERS b/OWNERS index dbedf552f..613f70f9d 100644 --- a/OWNERS +++ b/OWNERS @@ -5,6 +5,11 @@ approvers: - raffo - njuettner +reviewers: + - njuettner + - raffo + - seanmalloy + emeritus_approvers: - hjacobs - linki From a5ddddbfb68b6c04fd545aff584811b0a6ca102a Mon Sep 17 00:00:00 2001 From: Raffaele Di Fazio Date: Tue, 6 Apr 2021 17:40:08 +0200 Subject: [PATCH 102/175] adds release conventions --- docs/release.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/release.md b/docs/release.md index 639a5f80e..6595ca070 100644 --- a/docs/release.md +++ b/docs/release.md @@ -4,6 +4,16 @@ Currently we don't release regularly. Whenever we think it makes sense to release a new version we do it, but we aim to do a new release every month. You might want to ask in our Slack channel [external-dns](https://kubernetes.slack.com/archives/C771MKDKQ) when the next release will come out. +## Versioning convention + +Those are the conventions that we will be using for releases following `0.7.6`: + +- **Patch** version should be updated if we need to merge bugfixes, e.g. provider a does need a fix in order make updates working again. I would see updating or improving documentation here. + +- **Minor** version should be updated if new features are implemented in existing providers or new provider get introduced. + +- **Major** version should be upgraded if we introduce breaking changes. + ## How to release a new image ### Prerequisite From c52de7d78a187800431d01555341b356623a287e Mon Sep 17 00:00:00 2001 From: Raffaele Di Fazio Date: Wed, 7 Apr 2021 08:41:15 +0200 Subject: [PATCH 103/175] Update docs/release.md Co-authored-by: Sean Malloy --- docs/release.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/release.md b/docs/release.md index 6595ca070..dcfe0de5d 100644 --- a/docs/release.md +++ b/docs/release.md @@ -6,7 +6,7 @@ Currently we don't release regularly. Whenever we think it makes sense to releas ## Versioning convention -Those are the conventions that we will be using for releases following `0.7.6`: +These are the conventions that we will be using for releases following `0.7.6`: - **Patch** version should be updated if we need to merge bugfixes, e.g. provider a does need a fix in order make updates working again. I would see updating or improving documentation here. From 03c3c8fcb895166d6535d52bd0c2cfe52342dd14 Mon Sep 17 00:00:00 2001 From: "dan.simone@oracle.com" Date: Wed, 14 Apr 2021 13:21:03 -0700 Subject: [PATCH 104/175] Address remove comments --- source/ingress.go | 4 ++-- source/ingress_test.go | 4 ++-- source/source.go | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/source/ingress.go b/source/ingress.go index 85ab4d8b3..23bea7c29 100644 --- a/source/ingress.go +++ b/source/ingress.go @@ -297,10 +297,10 @@ func endpointsFromIngress(ing *v1beta1.Ingress, ignoreHostnameAnnotation bool, i // Include endpoints according to the hostname source annotation in our final list var endpoints []*endpoint.Endpoint - if strings.ToLower(hostnameSourceAnnotation) != IngressHostnameSourceAnnotationOnlyValue { + if strings.ToLower(hostnameSourceAnnotation) == IngressHostnameSourceDefinedHostsOnlyValue { endpoints = append(endpoints, definedHostsEndpoints...) } - if strings.ToLower(hostnameSourceAnnotation) != IngressHostnameSourceDefinedHostsOnlyValue { + if strings.ToLower(hostnameSourceAnnotation) == IngressHostnameSourceAnnotationOnlyValue { endpoints = append(endpoints, annotationEndpoints...) } return endpoints diff --git a/source/ingress_test.go b/source/ingress_test.go index 1f30e3037..0840e241b 100644 --- a/source/ingress_test.go +++ b/source/ingress_test.go @@ -268,10 +268,10 @@ func testEndpointsFromIngressHostnameSourceAnnotation(t *testing.T) { }, }, { - title: "Ingress-hostname-source=all, one rule.host, one annotation host", + title: "No ingress-hostname-source annotation, one rule.host, one annotation host", ingress: fakeIngress{ dnsnames: []string{"foo.bar"}, - annotations: map[string]string{hostnameAnnotationKey: "foo.baz", ingressHostnameSourceKey: "all"}, + annotations: map[string]string{hostnameAnnotationKey: "foo.baz"}, hostnames: []string{"lb.com"}, }, expected: []*endpoint.Endpoint{ diff --git a/source/source.go b/source/source.go index 0bf95383b..302002623 100644 --- a/source/source.go +++ b/source/source.go @@ -49,7 +49,6 @@ const ( // The annotation used to determine the source of hostnames for ingresses ingressHostnameSourceKey = "external-dns.alpha.kubernetes.io/ingress-hostname-source" // The value of the controller annotation so that we feel responsible - // The value of the controller annotation so that we feel responsible controllerAnnotationValue = "dns-controller" // The annotation used for defining the desired hostname internalHostnameAnnotationKey = "external-dns.alpha.kubernetes.io/internal-hostname" From 963282479e4d9a696decc93197c1fa78610e9677 Mon Sep 17 00:00:00 2001 From: "dan.simone@oracle.com" Date: Wed, 14 Apr 2021 13:26:34 -0700 Subject: [PATCH 105/175] Add clarifying comment about ingressHostnameSourceKey --- source/source.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/source.go b/source/source.go index 302002623..53e550e9f 100644 --- a/source/source.go +++ b/source/source.go @@ -46,7 +46,8 @@ const ( ttlAnnotationKey = "external-dns.alpha.kubernetes.io/ttl" // The annotation used for switching to the alias record types e. g. AWS Alias records instead of a normal CNAME aliasAnnotationKey = "external-dns.alpha.kubernetes.io/alias" - // The annotation used to determine the source of hostnames for ingresses + // The annotation used to determine the source of hostnames for ingresses. This is an optional field - all + // available hostname sources are used if not specified. ingressHostnameSourceKey = "external-dns.alpha.kubernetes.io/ingress-hostname-source" // The value of the controller annotation so that we feel responsible controllerAnnotationValue = "dns-controller" From 339af8ff4a6c5d9aa5176e2c1fa1143800264798 Mon Sep 17 00:00:00 2001 From: Vinny Sabatini Date: Fri, 16 Apr 2021 15:03:14 -0500 Subject: [PATCH 106/175] bluecat: allow setting tls verify Within the Bluecat config file, you can now set the `InsecureSkipVerify` for all API calls made to the Bluecat Gateway. This is controlled with by the boolean value of `skipTLSVerify`. If this is unset, TLS verification is enforced. --- provider/bluecat/bluecat.go | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/provider/bluecat/bluecat.go b/provider/bluecat/bluecat.go index 2205dcc0c..ed6860aec 100644 --- a/provider/bluecat/bluecat.go +++ b/provider/bluecat/bluecat.go @@ -44,6 +44,7 @@ type bluecatConfig struct { DNSConfiguration string `json:"dnsConfiguration"` View string `json:"dnsView"` RootZone string `json:"rootZone"` + SkipTLSVerify bool `json:"skipTLSVerify"` } // BluecatProvider implements the DNS provider for Bluecat DNS @@ -83,6 +84,7 @@ type GatewayClientConfig struct { DNSConfiguration string View string RootZone string + SkipTLSVerify bool } // BluecatZone defines a zone to hold records @@ -159,7 +161,7 @@ func NewBluecatProvider(configFile string, domainFilter endpoint.DomainFilter, z if err != nil { return nil, errors.Wrap(err, "failed to get API token from Bluecat Gateway") } - gatewayClient := NewGatewayClient(cookie, token, cfg.GatewayHost, cfg.DNSConfiguration, cfg.View, cfg.RootZone) + gatewayClient := NewGatewayClient(cookie, token, cfg.GatewayHost, cfg.DNSConfiguration, cfg.View, cfg.RootZone, cfg.SkipTLSVerify) provider := &BluecatProvider{ domainFilter: domainFilter, @@ -174,7 +176,7 @@ func NewBluecatProvider(configFile string, domainFilter endpoint.DomainFilter, z } // NewGatewayClient creates and returns a new Bluecat gateway client -func NewGatewayClient(cookie http.Cookie, token, gatewayHost, dnsConfiguration, view, rootZone string) GatewayClientConfig { +func NewGatewayClient(cookie http.Cookie, token, gatewayHost, dnsConfiguration, view, rootZone string, skipTLSVerify bool) GatewayClientConfig { // Right now the Bluecat gateway doesn't seem to have a way to get the root zone from the API. If the user // doesn't provide one via the config file we'll assume it's 'com' if rootZone == "" { @@ -187,6 +189,7 @@ func NewGatewayClient(cookie http.Cookie, token, gatewayHost, dnsConfiguration, DNSConfiguration: dnsConfiguration, View: view, RootZone: rootZone, + SkipTLSVerify: skipTLSVerify, } } @@ -525,7 +528,7 @@ func getBluecatGatewayToken(cfg bluecatConfig) (string, http.Cookie, error) { c := &http.Client{ Transport: &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // ignore self-signed SSL cert check + TLSClientConfig: &tls.Config{InsecureSkipVerify: cfg.SkipTLSVerify}, }} resp, err := c.Post(cfg.GatewayHost+"/rest_login", "application/json", bytes.NewBuffer(body)) @@ -559,7 +562,7 @@ func getBluecatGatewayToken(cfg bluecatConfig) (string, http.Cookie, error) { func (c GatewayClientConfig) getBluecatZones(zoneName string) ([]BluecatZone, error) { transportCfg := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + TLSClientConfig: &tls.Config{InsecureSkipVerify: c.SkipTLSVerify}, } client := &http.Client{ Transport: transportCfg, @@ -597,7 +600,7 @@ func (c GatewayClientConfig) getBluecatZones(zoneName string) ([]BluecatZone, er func (c GatewayClientConfig) getHostRecords(zone string, records *[]BluecatHostRecord) error { transportCfg := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + TLSClientConfig: &tls.Config{InsecureSkipVerify: c.SkipTLSVerify}, } client := &http.Client{ Transport: transportCfg, @@ -629,7 +632,7 @@ func (c GatewayClientConfig) getHostRecords(zone string, records *[]BluecatHostR func (c GatewayClientConfig) getCNAMERecords(zone string, records *[]BluecatCNAMERecord) error { transportCfg := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + TLSClientConfig: &tls.Config{InsecureSkipVerify: c.SkipTLSVerify}, } client := &http.Client{ Transport: transportCfg, @@ -661,7 +664,7 @@ func (c GatewayClientConfig) getCNAMERecords(zone string, records *[]BluecatCNAM func (c GatewayClientConfig) getTXTRecords(zone string, records *[]BluecatTXTRecord) error { transportCfg := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + TLSClientConfig: &tls.Config{InsecureSkipVerify: c.SkipTLSVerify}, } client := &http.Client{ Transport: transportCfg, @@ -695,7 +698,7 @@ func (c GatewayClientConfig) getTXTRecords(zone string, records *[]BluecatTXTRec func (c GatewayClientConfig) getHostRecord(name string, record *BluecatHostRecord) error { transportCfg := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + TLSClientConfig: &tls.Config{InsecureSkipVerify: c.SkipTLSVerify}, } client := &http.Client{ Transport: transportCfg, @@ -723,7 +726,7 @@ func (c GatewayClientConfig) getHostRecord(name string, record *BluecatHostRecor func (c GatewayClientConfig) getCNAMERecord(name string, record *BluecatCNAMERecord) error { transportCfg := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + TLSClientConfig: &tls.Config{InsecureSkipVerify: c.SkipTLSVerify}, } client := &http.Client{ Transport: transportCfg, @@ -751,7 +754,7 @@ func (c GatewayClientConfig) getCNAMERecord(name string, record *BluecatCNAMERec func (c GatewayClientConfig) getTXTRecord(name string, record *BluecatTXTRecord) error { transportCfg := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + TLSClientConfig: &tls.Config{InsecureSkipVerify: c.SkipTLSVerify}, } client := &http.Client{ Transport: transportCfg, @@ -780,7 +783,7 @@ func (c GatewayClientConfig) getTXTRecord(name string, record *BluecatTXTRecord) func (c GatewayClientConfig) createHostRecord(zone string, req *bluecatCreateHostRecordRequest) (res interface{}, err error) { transportCfg := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + TLSClientConfig: &tls.Config{InsecureSkipVerify: c.SkipTLSVerify}, } client := &http.Client{ Transport: transportCfg, @@ -804,7 +807,7 @@ func (c GatewayClientConfig) createHostRecord(zone string, req *bluecatCreateHos func (c GatewayClientConfig) createCNAMERecord(zone string, req *bluecatCreateCNAMERecordRequest) (res interface{}, err error) { transportCfg := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + TLSClientConfig: &tls.Config{InsecureSkipVerify: c.SkipTLSVerify}, } client := &http.Client{ Transport: transportCfg, @@ -830,7 +833,7 @@ func (c GatewayClientConfig) createCNAMERecord(zone string, req *bluecatCreateCN func (c GatewayClientConfig) createTXTRecord(zone string, req *bluecatCreateTXTRecordRequest) (interface{}, error) { transportCfg := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + TLSClientConfig: &tls.Config{InsecureSkipVerify: c.SkipTLSVerify}, } client := &http.Client{ Transport: transportCfg, @@ -855,7 +858,7 @@ func (c GatewayClientConfig) createTXTRecord(zone string, req *bluecatCreateTXTR func (c GatewayClientConfig) deleteHostRecord(name string) (err error) { transportCfg := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + TLSClientConfig: &tls.Config{InsecureSkipVerify: c.SkipTLSVerify}, } client := &http.Client{ Transport: transportCfg, @@ -879,7 +882,7 @@ func (c GatewayClientConfig) deleteHostRecord(name string) (err error) { func (c GatewayClientConfig) deleteCNAMERecord(name string) (err error) { transportCfg := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + TLSClientConfig: &tls.Config{InsecureSkipVerify: c.SkipTLSVerify}, } client := &http.Client{ Transport: transportCfg, @@ -903,7 +906,7 @@ func (c GatewayClientConfig) deleteCNAMERecord(name string) (err error) { func (c GatewayClientConfig) deleteTXTRecord(name string) error { transportCfg := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //ignore self-signed SSL cert check + TLSClientConfig: &tls.Config{InsecureSkipVerify: c.SkipTLSVerify}, } client := &http.Client{ Transport: transportCfg, From 3a1a01b72ef4a9868bb7fff61761d867dd9c47ae Mon Sep 17 00:00:00 2001 From: Vinny Sabatini Date: Fri, 16 Apr 2021 16:05:56 -0500 Subject: [PATCH 107/175] bluecat: update docs for provider Add docs for skipping TLS verification --- docs/tutorials/bluecat.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/tutorials/bluecat.md b/docs/tutorials/bluecat.md index b2150b9b7..6a3b5ff20 100644 --- a/docs/tutorials/bluecat.md +++ b/docs/tutorials/bluecat.md @@ -3,6 +3,20 @@ ## Prerequisites Install the BlueCat Gateway product and deploy the [community gateway workflows](https://github.com/bluecatlabs/gateway-workflows). +## Configuration Options + +The options for configuring the Bluecat Provider are available through the json file provided to External-DNS via the flag `--bluecat-config-file`. + +| Key | Required | +| ----------------- | ------------------ | +| gatewayHost | Yes | +| gatewayUsername | Yes | +| gatewayPassword | Yes | +| dnsConfiguration | Yes | +| dnsView | Yes | +| rootZone | Yes | +| skipTLSVerify | No (default false) | + ## Deploy Setup configuration file as k8s `Secret`. ``` @@ -10,10 +24,11 @@ cat << EOF > ~/bluecat.json { "gatewayHost": "https://bluecatgw.example.com", "gatewayUsername": "user", - "GatewayPassword": "pass", + "gatewayPassword": "pass", "dnsConfiguration": "Example", "dnsView": "Internal", - "rootZone": "example.com" + "rootZone": "example.com", + "skipTLSVerify": false } EOF kubectl create secret generic bluecatconfig --from-file ~/bluecat.json -n bluecat-example From 099ce03057e7d24f56f13be8869b53e0cd645434 Mon Sep 17 00:00:00 2001 From: Vinny Sabatini Date: Fri, 16 Apr 2021 16:07:17 -0500 Subject: [PATCH 108/175] add bluecat label to bluecat provider changes --- .github/labeler.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/labeler.yml b/.github/labeler.yml index f831d8422..a306ee035 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -11,6 +11,9 @@ provider/aws: provider/aws* # Add 'provider/azure' in file which starts with azure provider/azure: provider/azure* +# Add 'provider/bluecat' in file which starts with bluecat +provider/bluecat: provider/bluecat* + # Add 'provider/cloudflare' in file which starts with cloudflare provider/cloudflare: provider/cloudflare* From 73c6fc9dafbefb78b6c01b0c2d770f791cbe63dd Mon Sep 17 00:00:00 2001 From: pg2000 Date: Sun, 18 Apr 2021 09:36:54 +0200 Subject: [PATCH 109/175] feat: add move from dynectsoap to dynsoap --- provider/dyn/soap/client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/provider/dyn/soap/client.go b/provider/dyn/soap/client.go index 4ec11c904..23186dfb2 100644 --- a/provider/dyn/soap/client.go +++ b/provider/dyn/soap/client.go @@ -23,7 +23,7 @@ import ( "github.com/hooklift/gowsdl/soap" ) -// Returns a Dynect Client with a configured http.Client +// NewDynectClient returns a client with a configured http.Client // The default settings for the http.client are a timeout of // 10 seconds and reading proxy variables from http.ProxyFromEnvironment func NewDynectClient(url string) Dynect { @@ -37,7 +37,7 @@ func NewDynectClient(url string) Dynect { return NewDynect(soapClient) } -// Returns a Dynect Client without a configured http.Client +// NewCustomDynectClient returns a client without a configured http.Client func NewCustomDynectClient(url string, client http.Client) Dynect { soapClient := soap.NewClient(url, soap.WithHTTPClient(&client)) return NewDynect(soapClient) From 201699a85c465e5e188e0e322efae45e19d180e9 Mon Sep 17 00:00:00 2001 From: Vinny Sabatini Date: Mon, 19 Apr 2021 22:24:36 -0500 Subject: [PATCH 110/175] bluecat: allow setting TTL on cname and host records The TTL can now be set for CName and Host records for the Bluecat provider. You can not set the TTL of TXT records because that is not currently implemented in the Bluecat Gateway --- provider/bluecat/bluecat.go | 35 ++++++++++++++++++++++------ provider/bluecat/bluecat_test.go | 40 ++++++++++++++++++-------------- 2 files changed, 50 insertions(+), 25 deletions(-) diff --git a/provider/bluecat/bluecat.go b/provider/bluecat/bluecat.go index ed6860aec..31d080745 100644 --- a/provider/bluecat/bluecat.go +++ b/provider/bluecat/bluecat.go @@ -210,9 +210,21 @@ func (p *BluecatProvider) Records(ctx context.Context) (endpoints []*endpoint.En for _, rec := range resH { propMap := splitProperties(rec.Properties) ips := strings.Split(propMap["addresses"], ",") - for _, ip := range ips { - ep := endpoint.NewEndpoint(propMap["absoluteName"], endpoint.RecordTypeA, ip) - endpoints = append(endpoints, ep) + if _, ok := propMap["ttl"]; ok { + ttl, err := strconv.Atoi(propMap["ttl"]) + if err != nil { + return nil, errors.Wrapf(err, "could not parse ttl '%d' as int for host record %v", ttl, rec.Name) + } + + for _, ip := range ips { + ep := endpoint.NewEndpointWithTTL(propMap["absoluteName"], endpoint.RecordTypeA, endpoint.TTL(ttl), ip) + endpoints = append(endpoints, ep) + } + } else { + for _, ip := range ips { + ep := endpoint.NewEndpoint(propMap["absoluteName"], endpoint.RecordTypeA, ip) + endpoints = append(endpoints, ep) + } } } @@ -223,7 +235,15 @@ func (p *BluecatProvider) Records(ctx context.Context) (endpoints []*endpoint.En } for _, rec := range resC { propMap := splitProperties(rec.Properties) - endpoints = append(endpoints, endpoint.NewEndpoint(propMap["absoluteName"], endpoint.RecordTypeCNAME, propMap["linkedRecordName"])) + if _, ok := propMap["ttl"]; ok { + ttl, err := strconv.Atoi(propMap["ttl"]) + if err != nil { + return nil, errors.Wrapf(err, "could not parse ttl '%d' as int for CNAME record %v", ttl, rec.Name) + } + endpoints = append(endpoints, endpoint.NewEndpointWithTTL(propMap["absoluteName"], endpoint.RecordTypeCNAME, endpoint.TTL(ttl), propMap["linkedRecordName"])) + } else { + endpoints = append(endpoints, endpoint.NewEndpoint(propMap["absoluteName"], endpoint.RecordTypeCNAME, propMap["linkedRecordName"])) + } } var resT []BluecatTXTRecord @@ -455,11 +475,10 @@ func (p *BluecatProvider) recordSet(ep *endpoint.Endpoint, getObject bool) (reco switch ep.RecordType { case endpoint.RecordTypeA: var res []BluecatHostRecord - // TODO Allow configurable properties/ttl obj := bluecatCreateHostRecordRequest{ AbsoluteName: ep.DNSName, IP4Address: ep.Targets[0], - TTL: 0, + TTL: int(ep.RecordTTL), Properties: "", } if getObject { @@ -479,7 +498,7 @@ func (p *BluecatProvider) recordSet(ep *endpoint.Endpoint, getObject bool) (reco obj := bluecatCreateCNAMERecordRequest{ AbsoluteName: ep.DNSName, LinkedRecord: ep.Targets[0], - TTL: 0, + TTL: int(ep.RecordTTL), Properties: "", } if getObject { @@ -496,6 +515,8 @@ func (p *BluecatProvider) recordSet(ep *endpoint.Endpoint, getObject bool) (reco } case endpoint.RecordTypeTXT: var res []BluecatTXTRecord + // TODO: Allow setting TTL + // This is not implemented in the Bluecat Gateway obj := bluecatCreateTXTRecordRequest{ AbsoluteName: ep.DNSName, Text: ep.Targets[0], diff --git a/provider/bluecat/bluecat_test.go b/provider/bluecat/bluecat_test.go index 1ec751d70..a94ba4834 100644 --- a/provider/bluecat/bluecat_test.go +++ b/provider/bluecat/bluecat_test.go @@ -127,8 +127,8 @@ func createMockBluecatZone(fqdn string) BluecatZone { } } -func createMockBluecatHostRecord(fqdn, target string) BluecatHostRecord { - props := "absoluteName=" + fqdn + "|addresses=" + target + "|" +func createMockBluecatHostRecord(fqdn, target string, ttl int) BluecatHostRecord { + props := "absoluteName=" + fqdn + "|addresses=" + target + "|ttl=" + fmt.Sprint(ttl) + "|" nameParts := strings.Split(fqdn, ".") return BluecatHostRecord{ Name: nameParts[0], @@ -137,8 +137,8 @@ func createMockBluecatHostRecord(fqdn, target string) BluecatHostRecord { } } -func createMockBluecatCNAME(alias, target string) BluecatCNAMERecord { - props := "absoluteName=" + alias + "|linkedRecordName=" + target + "|" +func createMockBluecatCNAME(alias, target string, ttl int) BluecatCNAMERecord { + props := "absoluteName=" + alias + "|linkedRecordName=" + target + "|ttl=" + fmt.Sprint(ttl) + "|" nameParts := strings.Split(alias, ".") return BluecatCNAMERecord{ Name: nameParts[0], @@ -175,21 +175,25 @@ var tests = bluecatTestData{ DNSName: "example.com", RecordType: endpoint.RecordTypeA, Targets: endpoint.Targets{"123.123.123.122"}, + RecordTTL: endpoint.TTL(30), }, { DNSName: "nginx.example.com", RecordType: endpoint.RecordTypeA, Targets: endpoint.Targets{"123.123.123.123"}, + RecordTTL: endpoint.TTL(30), }, { DNSName: "whitespace.example.com", RecordType: endpoint.RecordTypeA, Targets: endpoint.Targets{"123.123.123.124"}, + RecordTTL: endpoint.TTL(30), }, { DNSName: "hack.example.com", RecordType: endpoint.RecordTypeCNAME, Targets: endpoint.Targets{"bluecatnetworks.com"}, + RecordTTL: endpoint.TTL(30), }, { DNSName: "abc.example.com", @@ -206,12 +210,12 @@ func TestBluecatRecords(t *testing.T) { createMockBluecatZone("example.com"), }, mockBluecatHosts: &[]BluecatHostRecord{ - createMockBluecatHostRecord("example.com", "123.123.123.122"), - createMockBluecatHostRecord("nginx.example.com", "123.123.123.123"), - createMockBluecatHostRecord("whitespace.example.com", "123.123.123.124"), + createMockBluecatHostRecord("example.com", "123.123.123.122", 30), + createMockBluecatHostRecord("nginx.example.com", "123.123.123.123", 30), + createMockBluecatHostRecord("whitespace.example.com", "123.123.123.124", 30), }, mockBluecatCNAMEs: &[]BluecatCNAMERecord{ - createMockBluecatCNAME("hack.example.com", "bluecatnetworks.com"), + createMockBluecatCNAME("hack.example.com", "bluecatnetworks.com", 30), }, mockBluecatTXTs: &[]BluecatTXTRecord{ createMockBluecatTXT("abc.example.com", "hello"), @@ -264,12 +268,12 @@ func TestBluecatApplyChangesDelete(t *testing.T) { createMockBluecatZone("example.com"), }, mockBluecatHosts: &[]BluecatHostRecord{ - createMockBluecatHostRecord("example.com", "123.123.123.122"), - createMockBluecatHostRecord("nginx.example.com", "123.123.123.123"), - createMockBluecatHostRecord("whitespace.example.com", "123.123.123.124"), + createMockBluecatHostRecord("example.com", "123.123.123.122", 30), + createMockBluecatHostRecord("nginx.example.com", "123.123.123.123", 30), + createMockBluecatHostRecord("whitespace.example.com", "123.123.123.124", 30), }, mockBluecatCNAMEs: &[]BluecatCNAMERecord{ - createMockBluecatCNAME("hack.example.com", "bluecatnetworks.com"), + createMockBluecatCNAME("hack.example.com", "bluecatnetworks.com", 30), }, mockBluecatTXTs: &[]BluecatTXTRecord{ createMockBluecatTXT("abc.example.com", "hello"), @@ -308,12 +312,12 @@ func TestBluecatRecordset(t *testing.T) { createMockBluecatZone("example.com"), }, mockBluecatHosts: &[]BluecatHostRecord{ - createMockBluecatHostRecord("example.com", "123.123.123.122"), - createMockBluecatHostRecord("nginx.example.com", "123.123.123.123"), - createMockBluecatHostRecord("whitespace.example.com", "123.123.123.124"), + createMockBluecatHostRecord("example.com", "123.123.123.122", 30), + createMockBluecatHostRecord("nginx.example.com", "123.123.123.123", 30), + createMockBluecatHostRecord("whitespace.example.com", "123.123.123.124", 30), }, mockBluecatCNAMEs: &[]BluecatCNAMERecord{ - createMockBluecatCNAME("hack.example.com", "bluecatnetworks.com"), + createMockBluecatCNAME("hack.example.com", "bluecatnetworks.com", 30), }, mockBluecatTXTs: &[]BluecatTXTRecord{ createMockBluecatTXT("abc.example.com", "hello"), @@ -351,7 +355,7 @@ func TestBluecatRecordset(t *testing.T) { IP4Address: testHostEndpoint.Targets[0], } hostRecords := []BluecatHostRecord{ - createMockBluecatHostRecord("whitespace.example.com", "123.123.123.124"), + createMockBluecatHostRecord("whitespace.example.com", "123.123.123.124", 30), } hostExpected := bluecatRecordSet{ obj: &hostObj, @@ -371,7 +375,7 @@ func TestBluecatRecordset(t *testing.T) { LinkedRecord: testCnameEndpoint.Targets[0], } cnameRecords := []BluecatCNAMERecord{ - createMockBluecatCNAME("hack.example.com", "bluecatnetworks.com"), + createMockBluecatCNAME("hack.example.com", "bluecatnetworks.com", 30), } cnameExpected := bluecatRecordSet{ obj: &cnameObj, From 17fb8813d0aacffec3d6da3f3073faf670bcbe02 Mon Sep 17 00:00:00 2001 From: Thibault Jamet Date: Fri, 12 Mar 2021 14:19:39 +0100 Subject: [PATCH 111/175] Reduce AWS Route53 API calls Currently, planning instructs to create all records even those which does not match any zone. Later, those records will be checked towards the existing records and filtered whether they match or not a hosted zone. This causes a problem, at least in the specific case of the Route53 implementation as it always calls the ApplyChanges method, which in its turn always retrieves all records in all zones. This causes high pressure on Route53 APIs, for non-necessary actions. By being able to filter all unmanaged records from the plan, we can prevent from calling ApplyChanges when nothing has to be done and hence prevent an unnecessary listing of records. By doing so, the rate of API calls to AWS Route53 is expected to be reduced by 2 --- controller/controller.go | 29 ++++-- controller/controller_test.go | 176 ++++++++++++++++++++++++++++++++++ endpoint/domain_filter.go | 38 ++++++++ plan/plan.go | 19 +++- provider/aws/aws.go | 15 +++ provider/aws/aws_test.go | 23 +++++ provider/provider.go | 5 + registry/aws_sd_registry.go | 4 + registry/noop.go | 4 + registry/registry.go | 1 + registry/txt.go | 4 + 11 files changed, 309 insertions(+), 9 deletions(-) diff --git a/controller/controller.go b/controller/controller.go index 4353fe44f..2b9a633f0 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -72,6 +72,14 @@ var ( Help: "Timestamp of last successful sync with the DNS provider", }, ) + controllerNoChangesTotal = prometheus.NewCounter( + prometheus.CounterOpts{ + Namespace: "external_dns", + Subsystem: "controller", + Name: "no_op_runs_total", + Help: "Number of reconcile loops ending up with no changes on the DNS provider side.", + }, + ) deprecatedRegistryErrors = prometheus.NewCounter( prometheus.CounterOpts{ Subsystem: "registry", @@ -96,6 +104,7 @@ func init() { prometheus.MustRegister(lastSyncTimestamp) prometheus.MustRegister(deprecatedRegistryErrors) prometheus.MustRegister(deprecatedSourceErrors) + prometheus.MustRegister(controllerNoChangesTotal) } // Controller is responsible for orchestrating the different components. @@ -112,7 +121,7 @@ type Controller struct { // The interval between individual synchronizations Interval time.Duration // The DomainFilter defines which DNS records to keep or exclude - DomainFilter endpoint.DomainFilter + DomainFilter endpoint.DomainFilterInterface // The nextRunAt used for throttling and batching reconciliation nextRunAt time.Time // The nextRunAtMux is for atomic updating of nextRunAt @@ -144,23 +153,29 @@ func (c *Controller) RunOnce(ctx context.Context) error { sourceEndpointsTotal.Set(float64(len(endpoints))) endpoints = c.Registry.AdjustEndpoints(endpoints) + //filter := plan := &plan.Plan{ Policies: []plan.Policy{c.Policy}, Current: records, Desired: endpoints, - DomainFilter: c.DomainFilter, + DomainFilter: endpoint.MatchAllDomainFilters{c.DomainFilter, c.Registry.GetDomainFilter()}, PropertyComparator: c.Registry.PropertyValuesEqual, ManagedRecords: []string{endpoint.RecordTypeA, endpoint.RecordTypeCNAME}, } plan = plan.Calculate() - err = c.Registry.ApplyChanges(ctx, plan.Changes) - if err != nil { - registryErrorsTotal.Inc() - deprecatedRegistryErrors.Inc() - return err + if plan.Changes.HasChanges() { + err = c.Registry.ApplyChanges(ctx, plan.Changes) + if err != nil { + registryErrorsTotal.Inc() + deprecatedRegistryErrors.Inc() + return err + } + } else { + controllerNoChangesTotal.Inc() + log.Info("All records are already up to date") } lastSyncTimestamp.SetToCurrentTime() diff --git a/controller/controller_test.go b/controller/controller_test.go index 8c042d085..89ac590f0 100644 --- a/controller/controller_test.go +++ b/controller/controller_test.go @@ -40,6 +40,30 @@ type mockProvider struct { ExpectChanges *plan.Changes } +type filteredMockProvider struct { + provider.BaseProvider + domainFilter endpoint.DomainFilterInterface + RecordsStore []*endpoint.Endpoint + RecordsCallCount int + ApplyChangesCalls []*plan.Changes +} + +func (p *filteredMockProvider) GetDomainFilter() endpoint.DomainFilterInterface { + return p.domainFilter +} + +// Records returns the desired mock endpoints. +func (p *filteredMockProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error) { + p.RecordsCallCount++ + return p.RecordsStore, nil +} + +// ApplyChanges stores all calls for later check +func (p *filteredMockProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error { + p.ApplyChangesCalls = append(p.ApplyChangesCalls, changes) + return nil +} + // Records returns the desired mock endpoints. func (p *mockProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error) { return p.RecordsStore, nil @@ -192,3 +216,155 @@ func TestShouldRunOnce(t *testing.T) { // But not two times assert.False(t, ctrl.ShouldRunOnce(now)) } + +func testControllerFiltersDomains(t *testing.T, configuredEndpoints []*endpoint.Endpoint, domainFilter endpoint.DomainFilterInterface, providerEndpoints []*endpoint.Endpoint, expectedChanges []*plan.Changes) { + t.Helper() + source := new(testutils.MockSource) + source.On("Endpoints").Return(configuredEndpoints, nil) + + // Fake some existing records in our DNS provider and validate some desired changes. + provider := &filteredMockProvider{ + RecordsStore: providerEndpoints, + } + r, err := registry.NewNoopRegistry(provider) + + require.NoError(t, err) + + ctrl := &Controller{ + Source: source, + Registry: r, + Policy: &plan.SyncPolicy{}, + DomainFilter: domainFilter, + } + + assert.NoError(t, ctrl.RunOnce(context.Background())) + assert.Equal(t, 1, provider.RecordsCallCount) + require.Len(t, provider.ApplyChangesCalls, len(expectedChanges)) + for i, change := range expectedChanges { + assert.Equal(t, *change, *provider.ApplyChangesCalls[i]) + } +} + +func TestControllerSkipsEmptyChanges(t *testing.T) { + testControllerFiltersDomains( + t, + []*endpoint.Endpoint{ + { + DNSName: "create-record.other.tld", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"1.2.3.4"}, + }, + { + DNSName: "some-record.used.tld", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"8.8.8.8"}, + }, + }, + endpoint.NewDomainFilter([]string{"used.tld"}), + []*endpoint.Endpoint{ + { + DNSName: "some-record.used.tld", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"8.8.8.8"}, + }, + }, + []*plan.Changes{}, + ) +} + +func TestWhenNoFilterControllerConsidersAllComain(t *testing.T) { + testControllerFiltersDomains( + t, + []*endpoint.Endpoint{ + { + DNSName: "create-record.other.tld", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"1.2.3.4"}, + }, + { + DNSName: "some-record.used.tld", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"8.8.8.8"}, + }, + }, + nil, + []*endpoint.Endpoint{ + { + DNSName: "some-record.used.tld", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"8.8.8.8"}, + }, + }, + []*plan.Changes{ + { + Create: []*endpoint.Endpoint{ + { + DNSName: "create-record.other.tld", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"1.2.3.4"}, + }, + }, + }, + }, + ) +} + +func TestWhenMultipleControllerConsidersAllFilteredComain(t *testing.T) { + testControllerFiltersDomains( + t, + []*endpoint.Endpoint{ + { + DNSName: "create-record.other.tld", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"1.2.3.4"}, + }, + { + DNSName: "some-record.used.tld", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"1.1.1.1"}, + }, + { + DNSName: "create-record.unused.tld", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"1.2.3.4"}, + }, + }, + endpoint.NewDomainFilter([]string{"used.tld", "other.tld"}), + []*endpoint.Endpoint{ + { + DNSName: "some-record.used.tld", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"8.8.8.8"}, + }, + }, + []*plan.Changes{ + { + Create: []*endpoint.Endpoint{ + { + DNSName: "create-record.other.tld", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"1.2.3.4"}, + }, + }, + UpdateOld: []*endpoint.Endpoint{ + { + DNSName: "some-record.used.tld", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"8.8.8.8"}, + Labels: endpoint.Labels{}, + }, + }, + UpdateNew: []*endpoint.Endpoint{ + { + DNSName: "some-record.used.tld", + RecordType: endpoint.RecordTypeA, + Targets: endpoint.Targets{"1.1.1.1"}, + Labels: endpoint.Labels{ + "owner": "", + }, + }, + }, + }, + }, + ) +} diff --git a/endpoint/domain_filter.go b/endpoint/domain_filter.go index 91445e862..dcec5ba09 100644 --- a/endpoint/domain_filter.go +++ b/endpoint/domain_filter.go @@ -21,6 +21,44 @@ import ( "strings" ) +// DomainFilterInterface defines the interface to select matching domains for a specific provider or runtime +type DomainFilterInterface interface { + Match(domain string) bool + IsConfigured() bool +} + +type MatchAllDomainFilters []DomainFilterInterface + +func (f MatchAllDomainFilters) Match(domain string) bool { + if !f.IsConfigured() { + return true + } + for _, filter := range f { + if filter == nil { + continue + } + if filter.IsConfigured() && !filter.Match(domain) { + return false + } + } + return true +} + +func (f MatchAllDomainFilters) IsConfigured() bool { + if f == nil { + return false + } + for _, filter := range f { + if filter == nil { + continue + } + if filter.IsConfigured() { + return true + } + } + return len(f) > 0 +} + // DomainFilter holds a lists of valid domain names type DomainFilter struct { // Filters define what domains to match diff --git a/plan/plan.go b/plan/plan.go index 3ae346fcc..30ee39931 100644 --- a/plan/plan.go +++ b/plan/plan.go @@ -21,6 +21,9 @@ import ( "strconv" "strings" + "github.com/google/go-cmp/cmp" + log "github.com/sirupsen/logrus" + "sigs.k8s.io/external-dns/endpoint" ) @@ -40,7 +43,7 @@ type Plan struct { // Populated after calling Calculate() Changes *Changes // DomainFilter matches DNS names - DomainFilter endpoint.DomainFilter + DomainFilter endpoint.DomainFilterInterface // Property comparator compares custom properties of providers PropertyComparator PropertyComparator // DNS record types that will be considered for management @@ -115,12 +118,23 @@ func (t planTable) addCandidate(e *endpoint.Endpoint) { t.rows[dnsName][e.SetIdentifier].candidates = append(t.rows[dnsName][e.SetIdentifier].candidates, e) } +func (c *Changes) HasChanges() bool { + if len(c.Create) > 0 || len(c.Delete) > 0 { + return true + } + return !cmp.Equal(c.UpdateNew, c.UpdateOld) +} + // Calculate computes the actions needed to move current state towards desired // state. It then passes those changes to the current policy for further // processing. It returns a copy of Plan with the changes populated. func (p *Plan) Calculate() *Plan { t := newPlanTable() + if p.DomainFilter == nil { + p.DomainFilter = endpoint.MatchAllDomainFilters(nil) + } + for _, current := range filterRecordsForPlan(p.Current, p.DomainFilter, p.ManagedRecords) { t.addCurrent(current) } @@ -227,12 +241,13 @@ func (p *Plan) shouldUpdateProviderSpecific(desired, current *endpoint.Endpoint) // Per RFC 1034, CNAME records conflict with all other records - it is the // only record with this property. The behavior of the planner may need to be // made more sophisticated to codify this. -func filterRecordsForPlan(records []*endpoint.Endpoint, domainFilter endpoint.DomainFilter, managedRecords []string) []*endpoint.Endpoint { +func filterRecordsForPlan(records []*endpoint.Endpoint, domainFilter endpoint.DomainFilterInterface, managedRecords []string) []*endpoint.Endpoint { filtered := []*endpoint.Endpoint{} for _, record := range records { // Ignore records that do not match the domain filter provided if !domainFilter.Match(record.DNSName) { + log.Debugf("ignoring record %s that does not match domain filter", record.DNSName) continue } if isManagedRecord(record.RecordType, managedRecords) { diff --git a/provider/aws/aws.go b/provider/aws/aws.go index 2fb253e85..51bce1f43 100644 --- a/provider/aws/aws.go +++ b/provider/aws/aws.go @@ -465,6 +465,21 @@ func (p *AWSProvider) createUpdateChanges(newEndpoints, oldEndpoints []*endpoint return combined } +// GetDomainFilter generates a filter to exclude any domain that is not controlled by the provider +func (p *AWSProvider) GetDomainFilter() endpoint.DomainFilterInterface { + zones, err := p.Zones(context.Background()) + if err != nil { + log.Errorf("failed to list zones: %v", err) + return &endpoint.DomainFilter{} + } + zoneNames := []string(nil) + for _, z := range zones { + zoneNames = append(zoneNames, aws.StringValue(z.Name), "."+aws.StringValue(z.Name)) + } + log.Infof("Applying provider record filter for domains: %v", zoneNames) + return endpoint.NewDomainFilter(zoneNames) +} + // ApplyChanges applies a given set of changes in a given zone. func (p *AWSProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error { zones, err := p.Zones(ctx) diff --git a/provider/aws/aws_test.go b/provider/aws/aws_test.go index 563914c47..1eb810573 100644 --- a/provider/aws/aws_test.go +++ b/provider/aws/aws_test.go @@ -313,6 +313,29 @@ func TestAWSZones(t *testing.T) { } } +func TestAWSRecordsFilter(t *testing.T) { + provider, _ := newAWSProvider(t, endpoint.DomainFilter{}, provider.ZoneIDFilter{}, provider.ZoneTypeFilter{}, false, false, nil) + domainFilter := provider.GetDomainFilter() + assert.NotNil(t, domainFilter) + require.IsType(t, endpoint.DomainFilter{}, domainFilter) + count := 0 + filters := domainFilter.(endpoint.DomainFilter).Filters + for _, tld := range []string{ + "zone-4.ext-dns-test-3.teapot.zalan.do", + ".zone-4.ext-dns-test-3.teapot.zalan.do", + "zone-2.ext-dns-test-2.teapot.zalan.do", + ".zone-2.ext-dns-test-2.teapot.zalan.do", + "zone-3.ext-dns-test-2.teapot.zalan.do", + ".zone-3.ext-dns-test-2.teapot.zalan.do", + "zone-4.ext-dns-test-3.teapot.zalan.do", + ".zone-4.ext-dns-test-3.teapot.zalan.do", + } { + assert.Contains(t, filters, tld) + count++ + } + assert.Len(t, filters, count) +} + func TestAWSRecords(t *testing.T) { provider, _ := newAWSProvider(t, endpoint.NewDomainFilter([]string{"ext-dns-test-2.teapot.zalan.do."}), provider.NewZoneIDFilter([]string{}), provider.NewZoneTypeFilter(""), false, false, []*endpoint.Endpoint{ endpoint.NewEndpointWithTTL("list-test.zone-1.ext-dns-test-2.teapot.zalan.do", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4"), diff --git a/provider/provider.go b/provider/provider.go index c0c66cff0..ff9c40210 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -31,6 +31,7 @@ type Provider interface { ApplyChanges(ctx context.Context, changes *plan.Changes) error PropertyValuesEqual(name string, previous string, current string) bool AdjustEndpoints(endpoints []*endpoint.Endpoint) []*endpoint.Endpoint + GetDomainFilter() endpoint.DomainFilterInterface } type BaseProvider struct { @@ -44,6 +45,10 @@ func (b BaseProvider) PropertyValuesEqual(name, previous, current string) bool { return previous == current } +func (b BaseProvider) GetDomainFilter() endpoint.DomainFilterInterface { + return endpoint.DomainFilter{} +} + type contextKey struct { name string } diff --git a/registry/aws_sd_registry.go b/registry/aws_sd_registry.go index e08537419..9a87da07f 100644 --- a/registry/aws_sd_registry.go +++ b/registry/aws_sd_registry.go @@ -42,6 +42,10 @@ func NewAWSSDRegistry(provider provider.Provider, ownerID string) (*AWSSDRegistr }, nil } +func (sdr *AWSSDRegistry) GetDomainFilter() endpoint.DomainFilterInterface { + return sdr.provider.GetDomainFilter() +} + // Records calls AWS SD API and expects AWS SD provider to provider Owner/Resource information as a serialized // value in the AWSSDDescriptionLabel value in the Labels map func (sdr *AWSSDRegistry) Records(ctx context.Context) ([]*endpoint.Endpoint, error) { diff --git a/registry/noop.go b/registry/noop.go index 34c2b4610..73257730c 100644 --- a/registry/noop.go +++ b/registry/noop.go @@ -36,6 +36,10 @@ func NewNoopRegistry(provider provider.Provider) (*NoopRegistry, error) { }, nil } +func (im *NoopRegistry) GetDomainFilter() endpoint.DomainFilterInterface { + return im.provider.GetDomainFilter() +} + // Records returns the current records from the dns provider func (im *NoopRegistry) Records(ctx context.Context) ([]*endpoint.Endpoint, error) { return im.provider.Records(ctx) diff --git a/registry/registry.go b/registry/registry.go index 3367355d5..d80890b0c 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -34,6 +34,7 @@ type Registry interface { ApplyChanges(ctx context.Context, changes *plan.Changes) error PropertyValuesEqual(attribute string, previous string, current string) bool AdjustEndpoints(endpoints []*endpoint.Endpoint) []*endpoint.Endpoint + GetDomainFilter() endpoint.DomainFilterInterface } //TODO(ideahitme): consider moving this to Plan diff --git a/registry/txt.go b/registry/txt.go index eb58fc6af..42944615c 100644 --- a/registry/txt.go +++ b/registry/txt.go @@ -68,6 +68,10 @@ func NewTXTRegistry(provider provider.Provider, txtPrefix, txtSuffix, ownerID st }, nil } +func (im *TXTRegistry) GetDomainFilter() endpoint.DomainFilterInterface { + return im.provider.GetDomainFilter() +} + // Records returns the current records from the registry excluding TXT Records // If TXT records was created previously to indicate ownership its corresponding value // will be added to the endpoints Labels map From 9116ae6eded4d894c627a50bbe5df907c8cf4d46 Mon Sep 17 00:00:00 2001 From: Daniel Kravetz Date: Fri, 30 Apr 2021 10:46:07 +0200 Subject: [PATCH 112/175] Provide example of multiple values for "in" filter --- docs/faq.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/faq.md b/docs/faq.md index 9c9173bb6..e11632f8e 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -257,6 +257,9 @@ an instance of a ingress controller. Let's assume you have two ingress controlle then you can start two ExternalDNS providers one with `--annotation-filter=kubernetes.io/ingress.class in (nginx-internal)` and one with `--annotation-filter=kubernetes.io/ingress.class in (nginx-external)`. +If you need to search for multiple values of said annotation, you can provide a comma separated list, like so: +`--annotation-filter=kubernetes.io/ingress.class in (nginx-internal, alb-ingress-internal)`. + Beware when using multiple sources, e.g. `--source=service --source=ingress`, `--annotation-filter` will filter every given source objects. If you need to filter only one specific source you have to run a separated external dns service containing only the wanted `--source` and `--annotation-filter`. From 736972e011e1ceb86177f02973ffd35cf8aa6f53 Mon Sep 17 00:00:00 2001 From: Raffaele Di Fazio Date: Sun, 2 May 2021 14:40:12 +0000 Subject: [PATCH 113/175] pull golang Signed-off-by: GitHub --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 493ee0b6e..a971469ae 100644 --- a/Makefile +++ b/Makefile @@ -105,6 +105,7 @@ build.push/multiarch: image="$(IMAGE):$(VERSION)-$${arch}" ;\ # pre-pull due to https://github.com/kubernetes-sigs/cluster-addons/pull/84/files ;\ docker pull $${arch}/alpine:3.13 ;\ + docker pull golang:1.16 ;\ DOCKER_BUILDKIT=1 docker build --rm --tag $${image} --build-arg VERSION="$(VERSION)" --build-arg ARCH="$${arch}" . ;\ docker push $${image} ;\ arch_specific_tags+=( "--amend $${image}" ) ;\ From 0f64927359d50b28aeb057addfdae21764ad2c07 Mon Sep 17 00:00:00 2001 From: Raffaele Di Fazio Date: Mon, 3 May 2021 17:05:48 +0200 Subject: [PATCH 114/175] bumps CI timeout --- cloudbuild.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudbuild.yaml b/cloudbuild.yaml index 523f7783b..c6629fd0c 100644 --- a/cloudbuild.yaml +++ b/cloudbuild.yaml @@ -1,5 +1,5 @@ # See https://cloud.google.com/cloud-build/docs/build-config -timeout: 3000s +timeout: 5000s options: substitution_option: ALLOW_LOOSE steps: From 2287fbb9d67ac2ca1c5ed577def1cc3ddf679e77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20St=C3=A4hlin?= Date: Mon, 3 May 2021 19:56:39 +0200 Subject: [PATCH 115/175] Keep copied structs to module --- provider/gandi/client.go | 40 ++++++++++++++++++------------------ provider/gandi/gandi_test.go | 12 +++++------ 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/provider/gandi/client.go b/provider/gandi/client.go index 93e31e5ee..a5e55334f 100644 --- a/provider/gandi/client.go +++ b/provider/gandi/client.go @@ -22,31 +22,31 @@ type DomainClientAdapter interface { ListDomains() (domains []domain.ListResponse, err error) } -type DomainClient struct { +type domainClient struct { Client *domain.Domain } -func (p *DomainClient) ListDomains() (domains []domain.ListResponse, err error) { +func (p *domainClient) ListDomains() (domains []domain.ListResponse, err error) { return p.Client.ListDomains() } func NewDomainClient(client *domain.Domain) DomainClientAdapter { - return &DomainClient{client} + return &domainClient{client} } -// StandardResponse copied from go-gandi/internal/gandi.go -type StandardResponse struct { +// standardResponse copied from go-gandi/internal/gandi.go +type standardResponse struct { Code int `json:"code,omitempty"` Message string `json:"message,omitempty"` UUID string `json:"uuid,omitempty"` Object string `json:"object,omitempty"` Cause string `json:"cause,omitempty"` Status string `json:"status,omitempty"` - Errors []StandardError `json:"errors,omitempty"` + Errors []standardError `json:"errors,omitempty"` } -// StandardError copied from go-gandi/internal/gandi.go -type StandardError struct { +// standardError copied from go-gandi/internal/gandi.go +type standardError struct { Location string `json:"location"` Name string `json:"name"` Description string `json:"description"` @@ -54,9 +54,9 @@ type StandardError struct { type LiveDNSClientAdapter interface { GetDomainRecords(fqdn string) (records []livedns.DomainRecord, err error) - CreateDomainRecord(fqdn, name, recordtype string, ttl int, values []string) (response StandardResponse, err error) + CreateDomainRecord(fqdn, name, recordtype string, ttl int, values []string) (response standardResponse, err error) DeleteDomainRecord(fqdn, name, recordtype string) (err error) - UpdateDomainRecordByNameAndType(fqdn, name, recordtype string, ttl int, values []string) (response StandardResponse, err error) + UpdateDomainRecordByNameAndType(fqdn, name, recordtype string, ttl int, values []string) (response standardResponse, err error) } type LiveDNSClient struct { @@ -71,18 +71,18 @@ func (p *LiveDNSClient) GetDomainRecords(fqdn string) (records []livedns.DomainR return p.Client.GetDomainRecords(fqdn) } -func (p *LiveDNSClient) CreateDomainRecord(fqdn, name, recordtype string, ttl int, values []string) (response StandardResponse, err error) { +func (p *LiveDNSClient) CreateDomainRecord(fqdn, name, recordtype string, ttl int, values []string) (response standardResponse, err error) { res, err := p.Client.CreateDomainRecord(fqdn, name, recordtype, ttl, values) if err != nil { - return StandardResponse{}, err + return standardResponse{}, err } // response needs to be copied as the Standard* structs are internal - var errors []StandardError + var errors []standardError for _, e := range res.Errors { - errors = append(errors, StandardError(e)) + errors = append(errors, standardError(e)) } - return StandardResponse{ + return standardResponse{ Code: res.Code, Message: res.Message, UUID: res.UUID, @@ -97,18 +97,18 @@ func (p *LiveDNSClient) DeleteDomainRecord(fqdn, name, recordtype string) (err e return p.Client.DeleteDomainRecord(fqdn, name, recordtype) } -func (p *LiveDNSClient) UpdateDomainRecordByNameAndType(fqdn, name, recordtype string, ttl int, values []string) (response StandardResponse, err error) { +func (p *LiveDNSClient) UpdateDomainRecordByNameAndType(fqdn, name, recordtype string, ttl int, values []string) (response standardResponse, err error) { res, err := p.Client.UpdateDomainRecordByNameAndType(fqdn, name, recordtype, ttl, values) if err != nil { - return StandardResponse{}, err + return standardResponse{}, err } // response needs to be copied as the Standard* structs are internal - var errors []StandardError + var errors []standardError for _, e := range res.Errors { - errors = append(errors, StandardError(e)) + errors = append(errors, standardError(e)) } - return StandardResponse{ + return standardResponse{ Code: res.Code, Message: res.Message, UUID: res.UUID, diff --git a/provider/gandi/gandi_test.go b/provider/gandi/gandi_test.go index 8b372ac7b..67b603af7 100644 --- a/provider/gandi/gandi_test.go +++ b/provider/gandi/gandi_test.go @@ -102,7 +102,7 @@ func (m *mockGandiClient) GetDomainRecords(fqdn string) (records []livedns.Domai return m.RecordsToReturn, err } -func (m *mockGandiClient) CreateDomainRecord(fqdn, name, recordtype string, ttl int, values []string) (response StandardResponse, err error) { +func (m *mockGandiClient) CreateDomainRecord(fqdn, name, recordtype string, ttl int, values []string) (response standardResponse, err error) { m.Actions = append(m.Actions, MockAction{ Name: "CreateDomainRecord", FQDN: fqdn, @@ -114,10 +114,10 @@ func (m *mockGandiClient) CreateDomainRecord(fqdn, name, recordtype string, ttl }, }) if m.FunctionToFail == "CreateDomainRecord" { - return StandardResponse{}, fmt.Errorf("injected error") + return standardResponse{}, fmt.Errorf("injected error") } - return StandardResponse{}, nil + return standardResponse{}, nil } func (m *mockGandiClient) DeleteDomainRecord(fqdn, name, recordtype string) (err error) { @@ -137,7 +137,7 @@ func (m *mockGandiClient) DeleteDomainRecord(fqdn, name, recordtype string) (err return nil } -func (m *mockGandiClient) UpdateDomainRecordByNameAndType(fqdn, name, recordtype string, ttl int, values []string) (response StandardResponse, err error) { +func (m *mockGandiClient) UpdateDomainRecordByNameAndType(fqdn, name, recordtype string, ttl int, values []string) (response standardResponse, err error) { m.Actions = append(m.Actions, MockAction{ Name: "UpdateDomainRecordByNameAndType", FQDN: fqdn, @@ -150,10 +150,10 @@ func (m *mockGandiClient) UpdateDomainRecordByNameAndType(fqdn, name, recordtype }) if m.FunctionToFail == "UpdateDomainRecordByNameAndType" { - return StandardResponse{}, fmt.Errorf("injected error") + return standardResponse{}, fmt.Errorf("injected error") } - return StandardResponse{}, nil + return standardResponse{}, nil } func (m *mockGandiClient) ListDomains() (domains []domain.ListResponse, err error) { From 20adda5330bb2b2fe4488d947ca209e8e37509d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20St=C3=A4hlin?= Date: Mon, 3 May 2021 20:07:42 +0200 Subject: [PATCH 116/175] Use constants in tests for uris --- provider/gandi/gandi_test.go | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/provider/gandi/gandi_test.go b/provider/gandi/gandi_test.go index 67b603af7..64be77116 100644 --- a/provider/gandi/gandi_test.go +++ b/provider/gandi/gandi_test.go @@ -62,27 +62,31 @@ func mockGandiClientNewWithFailure(functionToFail string) *mockGandiClient { } } +const domainUriPrefix = "https://api.gandi.net/v5/domain/domains/" +const exampleDotComUri = domainUriPrefix + "example.com" +const exampleDotNetUri = domainUriPrefix + "example.net" + func testRecords() []livedns.DomainRecord { return []livedns.DomainRecord{ { RrsetType: endpoint.RecordTypeCNAME, RrsetTTL: 600, RrsetName: "@", - RrsetHref: "https://api.gandi.net/v5/domain/domains/example.com/records/%40/A", + RrsetHref: exampleDotComUri + "/records/%40/A", RrsetValues: []string{"192.168.0.1"}, }, { RrsetType: endpoint.RecordTypeCNAME, RrsetTTL: 600, RrsetName: "www", - RrsetHref: "https://api.gandi.net/v5/domain/domains/example.com/records/www/CNAME", + RrsetHref: exampleDotComUri + "/records/www/CNAME", RrsetValues: []string{"lb.example.com"}, }, { RrsetType: endpoint.RecordTypeA, RrsetTTL: 600, RrsetName: "test", - RrsetHref: "https://api.gandi.net/v5/domain/domains/example.com/records/test/A", + RrsetHref: exampleDotComUri + "/records/test/A", RrsetValues: []string{"192.168.0.2"}, }, } @@ -169,7 +173,7 @@ func (m *mockGandiClient) ListDomains() (domains []domain.ListResponse, err erro { FQDN: "example.com", FQDNUnicode: "example.com", - Href: "https://api.gandi.net/v5/domain/domains/example.com", + Href: exampleDotComUri, ID: "b3e9c271-1c29-4441-97d9-bc021a7ac7c3", NameServer: &domain.NameServerConfig{ Current: gandiLiveDNSProvider, @@ -179,7 +183,7 @@ func (m *mockGandiClient) ListDomains() (domains []domain.ListResponse, err erro { FQDN: "example.net", FQDNUnicode: "example.net", - Href: "https://api.gandi.net/v5/domain/domains/example.net", + Href: exampleDotNetUri, ID: "dc78c1d8-6143-4edb-93bc-3a20d8bc3570", NameServer: &domain.NameServerConfig{ Current: "other", @@ -221,7 +225,7 @@ func TestGandiProvider_TestData(t *testing.T) { { FQDN: "example.com", FQDNUnicode: "example.com", - Href: "https://api.gandi.net/v5/domain/domains/example.com", + Href: exampleDotComUri, ID: "b3e9c271-1c29-4441-97d9-bc021a7ac7c3", NameServer: &domain.NameServerConfig{ Current: gandiLiveDNSProvider, @@ -231,7 +235,7 @@ func TestGandiProvider_TestData(t *testing.T) { { FQDN: "example.net", FQDNUnicode: "example.net", - Href: "https://api.gandi.net/v5/domain/domains/example.net", + Href: exampleDotNetUri, ID: "dc78c1d8-6143-4edb-93bc-3a20d8bc3570", NameServer: &domain.NameServerConfig{ Current: "other", @@ -255,21 +259,21 @@ func TestGandiProvider_TestData(t *testing.T) { RrsetType: endpoint.RecordTypeCNAME, RrsetTTL: 600, RrsetName: "@", - RrsetHref: "https://api.gandi.net/v5/domain/domains/example.com/records/%40/A", + RrsetHref: exampleDotComUri + "/records/%40/A", RrsetValues: []string{"192.168.0.1"}, }, { RrsetType: endpoint.RecordTypeCNAME, RrsetTTL: 600, RrsetName: "www", - RrsetHref: "https://api.gandi.net/v5/domain/domains/example.com/records/www/CNAME", + RrsetHref: exampleDotComUri + "/records/www/CNAME", RrsetValues: []string{"lb.example.com"}, }, { RrsetType: endpoint.RecordTypeA, RrsetTTL: 600, RrsetName: "test", - RrsetHref: "https://api.gandi.net/v5/domain/domains/example.com/records/test/A", + RrsetHref: exampleDotComUri + "/records/test/A", RrsetValues: []string{"192.168.0.2"}, }, } From 0eebf53c95430ed1ef3315a917c02e60247744be Mon Sep 17 00:00:00 2001 From: Thibault Jamet Date: Wed, 5 May 2021 16:32:09 +0200 Subject: [PATCH 117/175] Update controller/controller.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nick Jüttner --- controller/controller.go | 1 - 1 file changed, 1 deletion(-) diff --git a/controller/controller.go b/controller/controller.go index 2b9a633f0..6769103dd 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -153,7 +153,6 @@ func (c *Controller) RunOnce(ctx context.Context) error { sourceEndpointsTotal.Set(float64(len(endpoints))) endpoints = c.Registry.AdjustEndpoints(endpoints) - //filter := plan := &plan.Plan{ Policies: []plan.Policy{c.Policy}, From 560933d23b95fef380c79359ea0db9b449c68b10 Mon Sep 17 00:00:00 2001 From: Sean Malloy Date: Wed, 5 May 2021 23:30:47 -0500 Subject: [PATCH 118/175] bluecat: support getting credentials from environment variables Adds support for getting BlueCat API credentials from environment variables BLUECAT_USERNAME and BLUECAT_PASSWORD. Providing credentails using the BlueCat JSON configuration file is still supported. Credentials from environment variables take precedence over credentials provided in the JSON configuration file. Using environment variables avoids having to store credentials as k8s secrets. --- provider/bluecat/bluecat.go | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/provider/bluecat/bluecat.go b/provider/bluecat/bluecat.go index 31d080745..88caf717e 100644 --- a/provider/bluecat/bluecat.go +++ b/provider/bluecat/bluecat.go @@ -26,6 +26,7 @@ import ( "io" "io/ioutil" "net/http" + "os" "strconv" "strings" @@ -39,8 +40,8 @@ import ( type bluecatConfig struct { GatewayHost string `json:"gatewayHost"` - GatewayUsername string `json:"gatewayUsername"` - GatewayPassword string `json:"gatewayPassword"` + GatewayUsername string `json:"gatewayUsername,omitempty"` + GatewayPassword string `json:"gatewayPassword,omitempty"` DNSConfiguration string `json:"dnsConfiguration"` View string `json:"dnsView"` RootZone string `json:"rootZone"` @@ -539,9 +540,25 @@ func (p *BluecatProvider) recordSet(ep *endpoint.Endpoint, getObject bool) (reco // getBluecatGatewayToken retrieves a Bluecat Gateway API token. func getBluecatGatewayToken(cfg bluecatConfig) (string, http.Cookie, error) { + var username string + if cfg.GatewayUsername != "" { + username = cfg.GatewayUsername + } + if v, ok := os.LookupEnv("BLUECAT_USERNAME"); ok { + username = v + } + + var password string + if cfg.GatewayPassword != "" { + password = cfg.GatewayPassword + } + if v, ok := os.LookupEnv("BLUECAT_PASSWORD"); ok { + password = v + } + body, err := json.Marshal(map[string]string{ - "username": cfg.GatewayUsername, - "password": cfg.GatewayPassword, + "username": username, + "password": password, }) if err != nil { return "", http.Cookie{}, errors.Wrap(err, "could not unmarshal credentials for bluecat gateway config") From c31d816e0b873c940ebcd7576eb075df91231175 Mon Sep 17 00:00:00 2001 From: Raffaele Di Fazio Date: Thu, 6 May 2021 14:38:58 +0200 Subject: [PATCH 119/175] Update kustomization.yaml --- kustomize/kustomization.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kustomize/kustomization.yaml b/kustomize/kustomization.yaml index 960456772..ed5dd8058 100644 --- a/kustomize/kustomization.yaml +++ b/kustomize/kustomization.yaml @@ -3,7 +3,7 @@ kind: Kustomization images: - name: k8s.gcr.io/external-dns/external-dns - newTag: v0.7.6 + newTag: v0.8.0 resources: - ./external-dns-deployment.yaml From 73e2694dc62c9f809ca086277dabcaa6ca3efb2a Mon Sep 17 00:00:00 2001 From: Sean Malloy Date: Thu, 6 May 2021 22:05:32 -0500 Subject: [PATCH 120/175] docs: update bluecat tutorial * Updated with v0.8.0 details * Document getting credentials via environment variables --- README.md | 1 + docs/tutorials/bluecat.md | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 0d27eb7f0..11d285aeb 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,7 @@ The following tutorials are provided: * [Azure DNS](docs/tutorials/azure.md) * [Azure Private DNS](docs/tutorials/azure-private-dns.md) * [Cloudflare](docs/tutorials/cloudflare.md) +* [BlueCat](docs/tutorials/bluecat.md) * [CoreDNS](docs/tutorials/coredns.md) * [DigitalOcean](docs/tutorials/digitalocean.md) * [Hetzner](docs/tutorials/hetzner.md) diff --git a/docs/tutorials/bluecat.md b/docs/tutorials/bluecat.md index 6a3b5ff20..4046bdc04 100644 --- a/docs/tutorials/bluecat.md +++ b/docs/tutorials/bluecat.md @@ -1,17 +1,20 @@ # Setting up external-dns for BlueCat +The first external-dns release with with BlueCat provider support is v0.8.0. + ## Prerequisites Install the BlueCat Gateway product and deploy the [community gateway workflows](https://github.com/bluecatlabs/gateway-workflows). ## Configuration Options -The options for configuring the Bluecat Provider are available through the json file provided to External-DNS via the flag `--bluecat-config-file`. +The options for configuring the Bluecat Provider are available through the json file provided to External-DNS via the flag `--bluecat-config-file`. The +BlueCat Gateway username and password can be supplied using the configuration file or environment variables `BLUECAT_USERNAME` and `BLUECAT_PASSWORD`. | Key | Required | | ----------------- | ------------------ | | gatewayHost | Yes | -| gatewayUsername | Yes | -| gatewayPassword | Yes | +| gatewayUsername | No | +| gatewayPassword | No | | dnsConfiguration | Yes | | dnsView | Yes | | rootZone | Yes | @@ -34,19 +37,20 @@ EOF kubectl create secret generic bluecatconfig --from-file ~/bluecat.json -n bluecat-example ``` -Setup up deployment/service account: +Setup up namespace, deployment, and service account: ``` +kubectl create namespace bluecat-example +cat << EOF > ~/bluecat.yml +--- apiVersion: v1 kind: ServiceAccount metadata: name: external-dns - namespace: bluecat-example --- apiVersion: apps/v1 kind: Deployment metadata: name: external-dns - namespace: bluecat-example spec: selector: matchLabels: @@ -65,7 +69,7 @@ spec: secretName: bluecatconfig containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:$TAG # no released versions include the bluecat provider yet + image: k8s.gcr.io/external-dns/external-dns:v0.8.0 volumeMounts: - name: bluecatconfig mountPath: "/etc/external-dns/" @@ -76,4 +80,6 @@ spec: - --provider=bluecat - --txt-owner-id=bluecat-example - --bluecat-config-file=/etc/external-dns/bluecat.json +EOF +kubectl apply -f ~/bluecat.yml -n bluecat-example ``` From 026fa1c4d28bd83ccaec11875497b67927eff46a Mon Sep 17 00:00:00 2001 From: SimonGurney Date: Fri, 14 May 2021 16:38:09 +0100 Subject: [PATCH 121/175] Updated k8s manifest for Azure DNS provider #2082 As detailed in #2082, following the tutorial does not work because the default TXT register is not configured with a prefix and therefore CNAME records can not be updated / deleted once added. --- docs/tutorials/azure.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/tutorials/azure.md b/docs/tutorials/azure.md index 102699bfc..e544510da 100644 --- a/docs/tutorials/azure.md +++ b/docs/tutorials/azure.md @@ -268,6 +268,7 @@ spec: - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. - --provider=azure - --azure-resource-group=externaldns # (optional) use the DNS zones from the tutorial's resource group + - --txt-prefix=externaldns- volumeMounts: - name: azure-config-file mountPath: /etc/kubernetes From 8a6608551c76baa83aff88e917bb7731fb0cfbe4 Mon Sep 17 00:00:00 2001 From: fboltz Date: Fri, 14 May 2021 19:34:58 +0200 Subject: [PATCH 122/175] FEAT: Support DryRun --- provider/godaddy/godaddy.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/provider/godaddy/godaddy.go b/provider/godaddy/godaddy.go index fcfc5ccce..b276dc502 100644 --- a/provider/godaddy/godaddy.go +++ b/provider/godaddy/godaddy.go @@ -40,8 +40,6 @@ const ( var ( // ErrRecordToMutateNotFound when ApplyChange has to update/delete and didn't found the record in the existing zone (Change with no record ID) ErrRecordToMutateNotFound = errors.New("record to mutate not found in current zone") - // ErrNoDryRun No dry run support for the moment - ErrNoDryRun = errors.New("dry run not supported") ) type gdClient interface { @@ -130,11 +128,6 @@ func NewGoDaddyProvider(ctx context.Context, domainFilter endpoint.DomainFilter, return nil, err } - // TODO: Add Dry Run support - if dryRun { - return nil, ErrNoDryRun - } - return &GDProvider{ client: client, domainFilter: domainFilter, From d944cd530e1c4ef54a43b5fe28c54798e1f0c690 Mon Sep 17 00:00:00 2001 From: fboltz Date: Fri, 14 May 2021 19:35:16 +0200 Subject: [PATCH 123/175] FEAT: Declare error response model --- provider/godaddy/client.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/provider/godaddy/client.go b/provider/godaddy/client.go index ffed0ed2c..335994129 100644 --- a/provider/godaddy/client.go +++ b/provider/godaddy/client.go @@ -77,6 +77,29 @@ type Client struct { Timeout time.Duration } +// GDErrorField describe the error reason +type GDErrorField struct { + Code *string `json:"code,omitempty"` + Message *string `json:"message,omitempty"` + Path *string `json:"path,omitempty"` + PathRelated *string `json:"pathRelated,omitempty"` +} + +// GDErrorResponse is the body response when an API call fails +type GDErrorResponse struct { + Code string `json:"code"` + Fields []GDErrorField `json:"fields,omitempty"` + Message string `json:"message,omitempty"` +} + +func (r GDErrorResponse) String() string { + if b, err := json.Marshal(r); err == nil { + return string(b) + } + + return "" +} + // NewClient represents a new client to call the API func NewClient(useOTE bool, apiKey, apiSecret string) (*Client, error) { var endpoint string From ca9deae788ec751fa81742ccd93c9a6ffd3f9a44 Mon Sep 17 00:00:00 2001 From: fboltz Date: Fri, 14 May 2021 19:35:56 +0200 Subject: [PATCH 124/175] FEAT: Use the new Delete GoDaddy API --- provider/godaddy/godaddy.go | 140 ++++++++++++++++++++----------- provider/godaddy/godaddy_test.go | 84 ++++++++++++++++++- 2 files changed, 174 insertions(+), 50 deletions(-) diff --git a/provider/godaddy/godaddy.go b/provider/godaddy/godaddy.go index b276dc502..efe7cb718 100644 --- a/provider/godaddy/godaddy.go +++ b/provider/godaddy/godaddy.go @@ -32,11 +32,17 @@ import ( const ( gdMinimalTTL = 600 - gdCreate = iota - gdUpdate - gdDelete + gdCreate = 0 + gdUpdate = 1 + gdDelete = 2 ) +var actionNames = []string{ + "create", + "update", + "delete", +} + var ( // ErrRecordToMutateNotFound when ApplyChange has to update/delete and didn't found the record in the existing zone (Change with no record ID) ErrRecordToMutateNotFound = errors.New("record to mutate not found in current zone") @@ -77,6 +83,17 @@ type gdRecordField struct { Service *string `json:"service,omitempty"` } +type gdUpdateRecordField struct { + Data string `json:"data"` + Name string `json:"name"` + TTL int64 `json:"ttl"` + Port *int `json:"port,omitempty"` + Priority *int `json:"priority,omitempty"` + Weight *int64 `json:"weight,omitempty"` + Protocol *string `json:"protocol,omitempty"` + Service *string `json:"service,omitempty"` +} + type gdRecords struct { records []gdRecordField changed bool @@ -310,14 +327,6 @@ func (p *GDProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error) return endpoints, nil } -func (p *GDProvider) flushRecords(patch bool, zoneRecord *gdRecords) error { - if patch { - return p.client.Patch(fmt.Sprintf("/v1/domains/%s/records", zoneRecord.zone), zoneRecord.records, nil) - } - - return p.client.Put(fmt.Sprintf("/v1/domains/%s/records", zoneRecord.zone), zoneRecord.records, nil) -} - func (p *GDProvider) appendChange(action int, endpoints []*endpoint.Endpoint, allChanges []gdEndpoint) []gdEndpoint { for _, e := range endpoints { allChanges = append(allChanges, gdEndpoint{ @@ -329,15 +338,10 @@ func (p *GDProvider) appendChange(action int, endpoints []*endpoint.Endpoint, al return allChanges } -func (p *GDProvider) changeAllRecords(patch bool, endpoints []gdEndpoint, zoneRecords []*gdRecords) error { +func (p *GDProvider) changeAllRecords(endpoints []gdEndpoint, zoneRecords []*gdRecords) error { zoneNameIDMapper := gdZoneIDName{} for _, zoneRecord := range zoneRecords { - if patch { - zoneRecord.changed = false - zoneRecord.records = nil - } - zoneNameIDMapper.add(zoneRecord.zone, zoneRecord) } @@ -366,7 +370,15 @@ func (p *GDProvider) changeAllRecords(patch bool, endpoints []gdEndpoint, zoneRe change.TTL = maxOf(gdMinimalTTL, int64(e.endpoint.RecordTTL)) } - zoneRecord.applyChange(e.action, change) + if p.DryRun { + log.Infof("DryRun: Apply change %s on record %s", actionNames[e.action], change) + } else { + if err := zoneRecord.applyChange(e.action, p.client, change); err != nil { + log.Errorf("Unable to apply change %s on record %s, %v", actionNames[e.action], change, err) + + return err + } + } } } } @@ -401,15 +413,54 @@ func (p *GDProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) er log.Infof("GoDaddy: %d changes will be done", len(allChanges)) - patch := len(changes.UpdateOld)+len(changes.Delete) == 0 - - if err = p.changeAllRecords(patch, allChanges, changedZoneRecords); err != nil { + if err = p.changeAllRecords(allChanges, changedZoneRecords); err != nil { return err } - for _, record := range changedZoneRecords { - if record.changed { - if err = p.flushRecords(patch, record); err != nil { + return nil +} + +func (p *gdRecords) addRecord(client gdClient, change gdRecordField) error { + var response GDErrorResponse + + log.Debugf("GoDaddy: Add an entry %s to zone %s", change.String(), p.zone) + + p.records = append(p.records, change) + p.changed = true + + if err := client.Patch(fmt.Sprintf("/v1/domains/%s/records", p.zone), []gdRecordField{change}, &response); err != nil { + log.Errorf("Add record %s.%s of type %s failed: %v", change.Name, p.zone, change.Type, response) + + return err + } + + return nil +} + +func (p *gdRecords) updateRecord(client gdClient, change gdRecordField) error { + log.Debugf("GoDaddy: Update an entry %s to zone %s", change.String(), p.zone) + + for index, record := range p.records { + if record.Type == change.Type && record.Name == change.Name { + var response GDErrorResponse + + p.records[index] = change + p.changed = true + + changed := []gdUpdateRecordField{{ + Data: change.Data, + Name: change.Name, + TTL: change.TTL, + Port: change.Port, + Priority: change.Priority, + Weight: change.Weight, + Protocol: change.Protocol, + Service: change.Service, + }} + + if err := client.Patch(fmt.Sprintf("/v1/domains/%s/records/%s", p.zone, change.Type), changed, &response); err != nil { + log.Errorf("Update record %s.%s of type %s failed: %v", change.Name, p.zone, change.Type, response) + return err } } @@ -418,27 +469,8 @@ func (p *GDProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) er return nil } -func (p *gdRecords) addRecord(change gdRecordField) { - log.Debugf("GoDaddy: Add an entry %s to zone %s", change.String(), p.zone) - - p.records = append(p.records, change) - p.changed = true -} - -func (p *gdRecords) updateRecord(change gdRecordField) { - log.Debugf("GoDaddy: Update an entry %s to zone %s", change.String(), p.zone) - - for index, record := range p.records { - if record.Type == change.Type && record.Name == change.Name { - p.records[index] = change - p.changed = true - break - } - } -} - // Remove one record from the record list -func (p *gdRecords) deleteRecord(change gdRecordField) { +func (p *gdRecords) deleteRecord(client gdClient, change gdRecordField) error { log.Debugf("GoDaddy: Delete an entry %s to zone %s", change.String(), p.zone) deleteIndex := -1 @@ -451,24 +483,36 @@ func (p *gdRecords) deleteRecord(change gdRecordField) { } if deleteIndex >= 0 { + var response GDErrorResponse + p.records[deleteIndex] = p.records[len(p.records)-1] p.records = p.records[:len(p.records)-1] p.changed = true + + if err := client.Delete(fmt.Sprintf("/v1/domains/%s/records/%s/%s", p.zone, change.Type, change.Name), &response); err != nil { + log.Errorf("Delete record %s.%s of type %s failed: %v", change.Name, p.zone, change.Type, response) + + return err + } } else { log.Warnf("GoDaddy: record in zone %s not found %s to delete", p.zone, change.String()) } + + return nil } -func (p *gdRecords) applyChange(action int, change gdRecordField) { +func (p *gdRecords) applyChange(action int, client gdClient, change gdRecordField) error { switch action { case gdCreate: - p.addRecord(change) + return p.addRecord(client, change) case gdUpdate: - p.updateRecord(change) + return p.updateRecord(client, change) case gdDelete: - p.deleteRecord(change) + return p.deleteRecord(client, change) } + + return nil } func (c gdRecordField) String() string { diff --git a/provider/godaddy/godaddy_test.go b/provider/godaddy/godaddy_test.go index 2e9b07342..31e6796a9 100644 --- a/provider/godaddy/godaddy_test.go +++ b/provider/godaddy/godaddy_test.go @@ -19,6 +19,7 @@ package godaddy import ( "context" "encoding/json" + "errors" "sort" "testing" @@ -360,8 +361,8 @@ func TestGoDaddyChange(t *testing.T) { }, }, nil).Once() - // Update domain - client.On("Put", "/v1/domains/example.net/records", []gdRecordField{ + // Add entry + client.On("Patch", "/v1/domains/example.net/records", []gdRecordField{ { Name: "@", Type: "A", @@ -370,7 +371,86 @@ func TestGoDaddyChange(t *testing.T) { }, }).Return(nil, nil).Once() + // Delete entry + client.On("Delete", "/v1/domains/example.net/records/A/godaddy").Return(nil, nil).Once() + assert.NoError(provider.ApplyChanges(context.TODO(), &changes)) client.AssertExpectations(t) } + +var ( + status404 string = "404" + notfound string = "Record not found" +) + +func TestGoDaddyErrorResponse(t *testing.T) { + assert := assert.New(t) + client := newMockGoDaddyClient(t) + provider := &GDProvider{ + client: client, + } + + changes := plan.Changes{ + Create: []*endpoint.Endpoint{ + { + DNSName: ".example.net", + RecordType: "A", + RecordTTL: gdMinimalTTL, + Targets: []string{ + "203.0.113.42", + }, + }, + }, + Delete: []*endpoint.Endpoint{ + { + DNSName: "godaddy.example.net", + RecordType: "A", + Targets: []string{ + "203.0.113.43", + }, + }, + }, + } + + // Fetch domains + client.On("Get", "/v1/domains?statuses=ACTIVE").Return([]gdZone{ + { + Domain: zoneNameExampleNet, + }, + }, nil).Once() + + // Fetch record + client.On("Get", "/v1/domains/example.net/records").Return([]gdRecordField{ + { + Name: "godaddy", + Type: "A", + TTL: gdMinimalTTL, + Data: "203.0.113.43", + }, + }, nil).Once() + + // Add entry + client.On("Patch", "/v1/domains/example.net/records", []gdRecordField{ + { + Name: "@", + Type: "A", + TTL: gdMinimalTTL, + Data: "203.0.113.42", + }, + }).Return(nil, nil).Once() + + // Delete entry + client.On("Delete", "/v1/domains/example.net/records/A/godaddy").Return(GDErrorResponse{ + Code: status404, + Message: notfound, + Fields: []GDErrorField{{ + Code: &status404, + Message: ¬found, + }}, + }, errors.New(notfound)).Once() + + assert.Error(provider.ApplyChanges(context.TODO(), &changes)) + + client.AssertExpectations(t) +} From 67108a217d761a175466fd9996f4f4f30b8e3aac Mon Sep 17 00:00:00 2001 From: fboltz Date: Sat, 15 May 2021 11:43:46 +0200 Subject: [PATCH 125/175] Delete record first and create record in last. Updated record was lost --- provider/godaddy/godaddy.go | 6 +++--- provider/godaddy/godaddy_test.go | 10 ---------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/provider/godaddy/godaddy.go b/provider/godaddy/godaddy.go index efe7cb718..7afa9eebe 100644 --- a/provider/godaddy/godaddy.go +++ b/provider/godaddy/godaddy.go @@ -406,10 +406,10 @@ func (p *GDProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) er allChanges := make([]gdEndpoint, 0, countTargets(changes)) - allChanges = p.appendChange(gdCreate, changes.Create, allChanges) - allChanges = p.appendChange(gdCreate, changes.UpdateNew, allChanges) - allChanges = p.appendChange(gdDelete, changes.UpdateOld, allChanges) allChanges = p.appendChange(gdDelete, changes.Delete, allChanges) + allChanges = p.appendChange(gdDelete, changes.UpdateOld, allChanges) + allChanges = p.appendChange(gdCreate, changes.UpdateNew, allChanges) + allChanges = p.appendChange(gdCreate, changes.Create, allChanges) log.Infof("GoDaddy: %d changes will be done", len(allChanges)) diff --git a/provider/godaddy/godaddy_test.go b/provider/godaddy/godaddy_test.go index 31e6796a9..370585e66 100644 --- a/provider/godaddy/godaddy_test.go +++ b/provider/godaddy/godaddy_test.go @@ -430,16 +430,6 @@ func TestGoDaddyErrorResponse(t *testing.T) { }, }, nil).Once() - // Add entry - client.On("Patch", "/v1/domains/example.net/records", []gdRecordField{ - { - Name: "@", - Type: "A", - TTL: gdMinimalTTL, - Data: "203.0.113.42", - }, - }).Return(nil, nil).Once() - // Delete entry client.On("Delete", "/v1/domains/example.net/records/A/godaddy").Return(GDErrorResponse{ Code: status404, From 1c35d74521b1997c32bd49f313e2573d5651cbe6 Mon Sep 17 00:00:00 2001 From: fboltz Date: Sat, 15 May 2021 11:44:11 +0200 Subject: [PATCH 126/175] Support dry run mode --- provider/godaddy/godaddy.go | 49 +++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/provider/godaddy/godaddy.go b/provider/godaddy/godaddy.go index 7afa9eebe..734e16aa8 100644 --- a/provider/godaddy/godaddy.go +++ b/provider/godaddy/godaddy.go @@ -18,6 +18,7 @@ package godaddy import ( "context" + "encoding/json" "errors" "fmt" "strings" @@ -370,14 +371,10 @@ func (p *GDProvider) changeAllRecords(endpoints []gdEndpoint, zoneRecords []*gdR change.TTL = maxOf(gdMinimalTTL, int64(e.endpoint.RecordTTL)) } - if p.DryRun { - log.Infof("DryRun: Apply change %s on record %s", actionNames[e.action], change) - } else { - if err := zoneRecord.applyChange(e.action, p.client, change); err != nil { - log.Errorf("Unable to apply change %s on record %s, %v", actionNames[e.action], change, err) + if err := zoneRecord.applyChange(e.action, p.client, change, p.DryRun); err != nil { + log.Errorf("Unable to apply change %s on record %s, %v", actionNames[e.action], change, err) - return err - } + return err } } } @@ -420,7 +417,7 @@ func (p *GDProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) er return nil } -func (p *gdRecords) addRecord(client gdClient, change gdRecordField) error { +func (p *gdRecords) addRecord(client gdClient, change gdRecordField, dryRun bool) error { var response GDErrorResponse log.Debugf("GoDaddy: Add an entry %s to zone %s", change.String(), p.zone) @@ -428,8 +425,10 @@ func (p *gdRecords) addRecord(client gdClient, change gdRecordField) error { p.records = append(p.records, change) p.changed = true - if err := client.Patch(fmt.Sprintf("/v1/domains/%s/records", p.zone), []gdRecordField{change}, &response); err != nil { - log.Errorf("Add record %s.%s of type %s failed: %v", change.Name, p.zone, change.Type, response) + if dryRun { + log.Infof("[DryRun] - Add record %s.%s of type %s %s", change.Name, p.zone, change.Type, toString(change)) + } else if err := client.Patch(fmt.Sprintf("/v1/domains/%s/records", p.zone), []gdRecordField{change}, &response); err != nil { + log.Errorf("Add record %s.%s of type %s failed: %s", change.Name, p.zone, change.Type, response) return err } @@ -437,7 +436,7 @@ func (p *gdRecords) addRecord(client gdClient, change gdRecordField) error { return nil } -func (p *gdRecords) updateRecord(client gdClient, change gdRecordField) error { +func (p *gdRecords) updateRecord(client gdClient, change gdRecordField, dryRun bool) error { log.Debugf("GoDaddy: Update an entry %s to zone %s", change.String(), p.zone) for index, record := range p.records { @@ -458,7 +457,9 @@ func (p *gdRecords) updateRecord(client gdClient, change gdRecordField) error { Service: change.Service, }} - if err := client.Patch(fmt.Sprintf("/v1/domains/%s/records/%s", p.zone, change.Type), changed, &response); err != nil { + if dryRun { + log.Infof("[DryRun] - Update record %s.%s of type %s %s", change.Name, p.zone, change.Type, toString(changed)) + } else if err := client.Patch(fmt.Sprintf("/v1/domains/%s/records/%s", p.zone, change.Type), changed, &response); err != nil { log.Errorf("Update record %s.%s of type %s failed: %v", change.Name, p.zone, change.Type, response) return err @@ -470,7 +471,7 @@ func (p *gdRecords) updateRecord(client gdClient, change gdRecordField) error { } // Remove one record from the record list -func (p *gdRecords) deleteRecord(client gdClient, change gdRecordField) error { +func (p *gdRecords) deleteRecord(client gdClient, change gdRecordField, dryRun bool) error { log.Debugf("GoDaddy: Delete an entry %s to zone %s", change.String(), p.zone) deleteIndex := -1 @@ -490,7 +491,9 @@ func (p *gdRecords) deleteRecord(client gdClient, change gdRecordField) error { p.records = p.records[:len(p.records)-1] p.changed = true - if err := client.Delete(fmt.Sprintf("/v1/domains/%s/records/%s/%s", p.zone, change.Type, change.Name), &response); err != nil { + if dryRun { + log.Infof("[DryRun] - Delete record %s.%s of type %s %s", change.Name, p.zone, change.Type, toString(change)) + } else if err := client.Delete(fmt.Sprintf("/v1/domains/%s/records/%s/%s", p.zone, change.Type, change.Name), &response); err != nil { log.Errorf("Delete record %s.%s of type %s failed: %v", change.Name, p.zone, change.Type, response) return err @@ -502,14 +505,14 @@ func (p *gdRecords) deleteRecord(client gdClient, change gdRecordField) error { return nil } -func (p *gdRecords) applyChange(action int, client gdClient, change gdRecordField) error { +func (p *gdRecords) applyChange(action int, client gdClient, change gdRecordField, dryRun bool) error { switch action { case gdCreate: - return p.addRecord(client, change) + return p.addRecord(client, change, dryRun) case gdUpdate: - return p.updateRecord(client, change) + return p.updateRecord(client, change, dryRun) case gdDelete: - return p.deleteRecord(client, change) + return p.deleteRecord(client, change, dryRun) } return nil @@ -543,3 +546,13 @@ func maxOf(vars ...int64) int64 { return max } + +func toString(obj interface{}) string { + b, e := json.MarshalIndent(obj, "", " ") + + if e != nil { + return fmt.Sprintf("<%v>", e) + } + + return string(b) +} From 01f008ab1a72324a2e6c2961c3725960c99a14e1 Mon Sep 17 00:00:00 2001 From: Arvin Amirian Date: Tue, 18 May 2021 11:13:56 -0400 Subject: [PATCH 127/175] Updatiing Infoblox go api version to v1.1.1 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 81bc35fd7..869796480 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/gophercloud/gophercloud v0.1.0 github.com/gorilla/mux v1.7.4 // indirect github.com/hooklift/gowsdl v0.4.0 - github.com/infobloxopen/infoblox-go-client v0.0.0-20180606155407-61dc5f9b0a65 + github.com/infobloxopen/infoblox-go-client v1.1.1 github.com/linki/instrumented_http v0.2.0 github.com/linode/linodego v0.19.0 github.com/maxatome/go-testdeep v1.4.0 diff --git a/go.sum b/go.sum index 3bc25ce4f..fc43d9554 100644 --- a/go.sum +++ b/go.sum @@ -498,8 +498,8 @@ github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/infobloxopen/infoblox-go-client v0.0.0-20180606155407-61dc5f9b0a65 h1:FP5rOFP4ifbtFIjFHJmwhFrsbDyONILK/FNntl/Pou8= -github.com/infobloxopen/infoblox-go-client v0.0.0-20180606155407-61dc5f9b0a65/go.mod h1:BXiw7S2b9qJoM8MS40vfgCNB2NLHGusk1DtO16BD9zI= +github.com/infobloxopen/infoblox-go-client v1.1.1 h1:728A6LbLjptj/7kZjHyIxQnm768PWHfGFm0HH8FnbtU= +github.com/infobloxopen/infoblox-go-client v1.1.1/go.mod h1:BXiw7S2b9qJoM8MS40vfgCNB2NLHGusk1DtO16BD9zI= github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= From 0b370ac6baab099504bb8449ba9fe192a7638cc9 Mon Sep 17 00:00:00 2001 From: Artem Voronin Date: Thu, 20 May 2021 15:12:42 +0300 Subject: [PATCH 128/175] Fixed registry aws-sd nil labels --- registry/aws_sd_registry.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/registry/aws_sd_registry.go b/registry/aws_sd_registry.go index e08537419..453febfd3 100644 --- a/registry/aws_sd_registry.go +++ b/registry/aws_sd_registry.go @@ -83,6 +83,9 @@ func (sdr *AWSSDRegistry) ApplyChanges(ctx context.Context, changes *plan.Change func (sdr *AWSSDRegistry) updateLabels(endpoints []*endpoint.Endpoint) { for _, ep := range endpoints { + if ep.Labels == nil { + ep.Labels = make(map[string]string) + } ep.Labels[endpoint.OwnerLabelKey] = sdr.ownerID ep.Labels[endpoint.AWSSDDescriptionLabel] = ep.Labels.Serialize(false) } From 9c0bd8dd43f8169d3c024f6225d973ca615674ad Mon Sep 17 00:00:00 2001 From: DOliana Date: Thu, 20 May 2021 20:53:50 +0200 Subject: [PATCH 129/175] Update azure.md updated version of external-dns, added notes for MSI permissions and which roles can be used, fixed mounting of config-file-secret --- docs/tutorials/azure.md | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/docs/tutorials/azure.md b/docs/tutorials/azure.md index 102699bfc..947a657b4 100644 --- a/docs/tutorials/azure.md +++ b/docs/tutorials/azure.md @@ -61,7 +61,7 @@ The `resourceGroup` is the Resource Group created in a previous step. The `aadClientID` and `aaClientSecret` are associated with the Service Principal, that you need to create next. ### Creating service principal -A Service Principal with a minimum access level of `contributor` to the DNS zone(s) and `reader` to the resource group containing the Azure DNS zone(s) is necessary for ExternalDNS to be able to edit DNS records. However, other more permissive access levels will work too (e.g. `contributor` to the resource group or the whole subscription). +A Service Principal with a minimum access level of `DNS Zone Contributor` or `Contributor` to the DNS zone(s) and `Reader` to the resource group containing the Azure DNS zone(s) is necessary for ExternalDNS to be able to edit DNS records. However, other more permissive access levels will work too (e.g. `Contributor` to the resource group or the whole subscription). This is an Azure CLI example on how to query the Azure API for the information required for the Resource Group and DNS zone you would have already created in previous steps. @@ -136,7 +136,7 @@ $ kubectl create secret generic azure-config-file --from-file=/local/path/to/azu ### Azure Managed Service Identity (MSI) -If [Azure Managed Service Identity (MSI)](https://docs.microsoft.com/en-us/azure/active-directory/managed-service-identity/overview) is enabled for virtual machines, then there is no need to create separate service principal. +If [Azure Managed Service Identity (MSI)](https://docs.microsoft.com/en-us/azure/active-directory/managed-service-identity/overview) is enabled for virtual machines, then there is no need to create separate service principal. Note that when granting access the kubeletidentity must be used, not the MSI used for the cluster (it usually has a name in the format -). The contents of `azure.json` should be similar to this: @@ -191,7 +191,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.6 + image: k8s.gcr.io/external-dns/external-dns:v0.8.0 args: - --source=service - --source=ingress @@ -206,6 +206,9 @@ spec: - name: azure-config-file secret: secretName: azure-config-file + items: + - key: externaldns-config.json + path: azure.json ``` ### Manifest (for clusters with RBAC enabled, cluster access) @@ -261,7 +264,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.6 + image: k8s.gcr.io/external-dns/external-dns:v0.8.0 args: - --source=service - --source=ingress @@ -276,6 +279,9 @@ spec: - name: azure-config-file secret: secretName: azure-config-file + items: + - key: externaldns-config.json + path: azure.json ``` ### Manifest (for clusters with RBAC enabled, namespace access) @@ -331,7 +337,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.6 + image: k8s.gcr.io/external-dns/external-dns:v0.8.0 args: - --source=service - --source=ingress @@ -346,6 +352,9 @@ spec: - name: azure-config-file secret: secretName: azure-config-file + items: + - key: externaldns-config.json + path: azure.json ``` Create the deployment for ExternalDNS: From 2476e77541dbd67a8b1fe8edd965fd3c71266995 Mon Sep 17 00:00:00 2001 From: Bogdan Date: Wed, 19 May 2021 15:58:22 +0200 Subject: [PATCH 130/175] Add the --default-targets flag This is a useful feature in environments with public global WAN address(es) --- main.go | 3 ++- pkg/apis/externaldns/types.go | 3 +++ source/multi_source.go | 13 ++++++++---- source/multi_source_test.go | 39 +++++++++++++++++++++++++++++++++-- source/store.go | 1 + 5 files changed, 52 insertions(+), 7 deletions(-) diff --git a/main.go b/main.go index 1a6f7cf65..1eaaf872b 100644 --- a/main.go +++ b/main.go @@ -124,6 +124,7 @@ func main() { GlooNamespace: cfg.GlooNamespace, SkipperRouteGroupVersion: cfg.SkipperRouteGroupVersion, RequestTimeout: cfg.RequestTimeout, + DefaultTargets: cfg.DefaultTargets, } // Lookup all the selected sources by names and pass them the desired configuration. @@ -143,7 +144,7 @@ func main() { } // Combine multiple sources into a single, deduplicated source. - endpointsSource := source.NewDedupSource(source.NewMultiSource(sources)) + endpointsSource := source.NewDedupSource(source.NewMultiSource(sources, sourceCfg.DefaultTargets)) // RegexDomainFilter overrides DomainFilter var domainFilter endpoint.DomainFilter diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 8655dc480..68f58a427 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -45,6 +45,7 @@ type Config struct { APIServerURL string KubeConfig string RequestTimeout time.Duration + DefaultTargets []string ContourLoadBalancerService string GlooNamespace string SkipperRouteGroupVersion string @@ -173,6 +174,7 @@ var defaultConfig = &Config{ APIServerURL: "", KubeConfig: "", RequestTimeout: time.Second * 30, + DefaultTargets: []string{}, ContourLoadBalancerService: "heptio-contour/contour", GlooNamespace: "gloo-system", SkipperRouteGroupVersion: "zalando.org/v1", @@ -365,6 +367,7 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("crd-source-kind", "Kind of the CRD for the crd source in API group and version specified by crd-source-apiversion").Default(defaultConfig.CRDSourceKind).StringVar(&cfg.CRDSourceKind) app.Flag("service-type-filter", "The service types to take care about (default: all, expected: ClusterIP, NodePort, LoadBalancer or ExternalName)").StringsVar(&cfg.ServiceTypeFilter) app.Flag("managed-record-types", "Comma separated list of record types to manage (default: A, CNAME) (supported records: CNAME, A, NS").Default("A", "CNAME").StringsVar(&cfg.ManagedDNSRecordTypes) + app.Flag("default-targets", "Set globally default IP address that will apply as a target instead of source addresses. Specify multiple times for multiple targets (optional)").StringsVar(&cfg.DefaultTargets) // Flags related to providers app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, aws-sd, godaddy, google, azure, azure-dns, azure-private-dns, bluecat, cloudflare, rcodezero, digitalocean, hetzner, dnsimple, akamai, infoblox, dyn, designate, coredns, skydns, inmemory, ovh, pdns, oci, exoscale, linode, rfc2136, ns1, transip, vinyldns, rdns, scaleway, vultr, ultradns)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "aws-sd", "google", "azure", "azure-dns", "hetzner", "azure-private-dns", "alibabacloud", "cloudflare", "rcodezero", "digitalocean", "dnsimple", "akamai", "infoblox", "dyn", "designate", "coredns", "skydns", "inmemory", "ovh", "pdns", "oci", "exoscale", "linode", "rfc2136", "ns1", "transip", "vinyldns", "rdns", "scaleway", "vultr", "ultradns", "godaddy", "bluecat") diff --git a/source/multi_source.go b/source/multi_source.go index 28744863f..9cba23663 100644 --- a/source/multi_source.go +++ b/source/multi_source.go @@ -24,7 +24,8 @@ import ( // multiSource is a Source that merges the endpoints of its nested Sources. type multiSource struct { - children []Source + children []Source + defaultTargets []string } // Endpoints collects endpoints of all nested Sources and returns them in a single slice. @@ -36,7 +37,11 @@ func (ms *multiSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, err if err != nil { return nil, err } - + if len(ms.defaultTargets) > 0 { + for i := range endpoints { + endpoints[i].Targets = ms.defaultTargets + } + } result = append(result, endpoints...) } @@ -50,6 +55,6 @@ func (ms *multiSource) AddEventHandler(ctx context.Context, handler func()) { } // NewMultiSource creates a new multiSource. -func NewMultiSource(children []Source) Source { - return &multiSource{children: children} +func NewMultiSource(children []Source, defaultTargets []string) Source { + return &multiSource{children: children, defaultTargets: defaultTargets} } diff --git a/source/multi_source_test.go b/source/multi_source_test.go index 7c579a55c..d299deedb 100644 --- a/source/multi_source_test.go +++ b/source/multi_source_test.go @@ -32,6 +32,7 @@ func TestMultiSource(t *testing.T) { t.Run("Interface", testMultiSourceImplementsSource) t.Run("Endpoints", testMultiSourceEndpoints) t.Run("EndpointsWithError", testMultiSourceEndpointsWithError) + t.Run("EndpointsDefaultTargets", testMultiSourceEndpointsDefaultTargets) } // testMultiSourceImplementsSource tests that multiSource is a valid Source. @@ -83,7 +84,7 @@ func testMultiSourceEndpoints(t *testing.T) { } // Create our object under test and get the endpoints. - source := NewMultiSource(sources) + source := NewMultiSource(sources, nil) // Get endpoints from the source. endpoints, err := source.Endpoints(context.Background()) @@ -110,7 +111,7 @@ func testMultiSourceEndpointsWithError(t *testing.T) { src.On("Endpoints").Return(nil, errSomeError) // Create our object under test and get the endpoints. - source := NewMultiSource([]Source{src}) + source := NewMultiSource([]Source{src}, nil) // Get endpoints from our source. _, err := source.Endpoints(context.Background()) @@ -119,3 +120,37 @@ func testMultiSourceEndpointsWithError(t *testing.T) { // Validate that the nested source was called. src.AssertExpectations(t) } + +func testMultiSourceEndpointsDefaultTargets(t *testing.T) { + // Create the expected default targets + defaultTargets := []string{"127.0.0.1", "127.0.0.2"} + + // Create the expected endpoints + expectedEndpoints := []*endpoint.Endpoint{ + {DNSName: "foo", Targets: defaultTargets}, + {DNSName: "bar", Targets: defaultTargets}, + } + + // Create the source endpoints with different targets + sourceEndpoints := []*endpoint.Endpoint{ + {DNSName: "foo", Targets: endpoint.Targets{"8.8.8.8"}}, + {DNSName: "bar", Targets: endpoint.Targets{"8.8.4.4"}}, + } + + // Create a mocked source returning source targets + src := new(testutils.MockSource) + src.On("Endpoints").Return(sourceEndpoints, nil) + + // Create our object under test with non-empty defaultTargets and get the endpoints. + source := NewMultiSource([]Source{src}, defaultTargets) + + // Get endpoints from our source. + endpoints, err := source.Endpoints(context.Background()) + require.NoError(t, err) + + // Validate returned endpoints against desired endpoints. + validateEndpoints(t, endpoints, expectedEndpoints) + + // Validate that the nested sources were called. + src.AssertExpectations(t) +} diff --git a/source/store.go b/source/store.go index 8bff6a056..4f9169f4b 100644 --- a/source/store.go +++ b/source/store.go @@ -64,6 +64,7 @@ type Config struct { GlooNamespace string SkipperRouteGroupVersion string RequestTimeout time.Duration + DefaultTargets []string } // ClientGenerator provides clients From 98171abe967188b6c6d3b32c2e15fbd795fde54e Mon Sep 17 00:00:00 2001 From: Eugene Venter Date: Wed, 26 May 2021 11:47:57 +1200 Subject: [PATCH 131/175] domain_filter_test.go: TestDomainFilterMatch ensure all tests are run Don't skip the whole test on first "exclusion" encountered in test data. Rather log a message and continue, as there could be more valid test data. --- endpoint/domain_filter_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/endpoint/domain_filter_test.go b/endpoint/domain_filter_test.go index 0e1440642..f13870106 100644 --- a/endpoint/domain_filter_test.go +++ b/endpoint/domain_filter_test.go @@ -262,7 +262,8 @@ var regexDomainFilterTests = []regexDomainFilterTest{ func TestDomainFilterMatch(t *testing.T) { for i, tt := range domainFilterTests { if len(tt.exclusions) > 0 { - t.Skip("NewDomainFilter() doesn't support exclusions") + t.Logf("NewDomainFilter() doesn't support exclusions - skipping test %+v", tt) + continue } domainFilter := NewDomainFilter(tt.domainFilter) for _, domain := range tt.domains { From bd83a472e8966c609a56e9c3ae13c3dfe0c2634e Mon Sep 17 00:00:00 2001 From: Eugene Venter Date: Wed, 26 May 2021 11:52:50 +1200 Subject: [PATCH 132/175] domain_filter_test.go: amend exclusion test data so all relevant tests get run in TestDomainFilterMatch --- endpoint/domain_filter_test.go | 40 +++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/endpoint/domain_filter_test.go b/endpoint/domain_filter_test.go index f13870106..2cb8f0412 100644 --- a/endpoint/domain_filter_test.go +++ b/endpoint/domain_filter_test.go @@ -40,121 +40,121 @@ type regexDomainFilterTest struct { var domainFilterTests = []domainFilterTest{ { []string{"google.com.", "exaring.de", "inovex.de"}, - []string{""}, + []string{}, []string{"google.com", "exaring.de", "inovex.de"}, true, }, { []string{"google.com.", "exaring.de", "inovex.de"}, - []string{""}, + []string{}, []string{"google.com", "exaring.de", "inovex.de"}, true, }, { []string{"google.com.", "exaring.de.", "inovex.de"}, - []string{""}, + []string{}, []string{"google.com", "exaring.de", "inovex.de"}, true, }, { []string{"foo.org. "}, - []string{""}, + []string{}, []string{"foo.org"}, true, }, { []string{" foo.org"}, - []string{""}, + []string{}, []string{"foo.org"}, true, }, { []string{"foo.org."}, - []string{""}, + []string{}, []string{"foo.org"}, true, }, { []string{"foo.org."}, - []string{""}, + []string{}, []string{"baz.org"}, false, }, { []string{"baz.foo.org."}, - []string{""}, + []string{}, []string{"foo.org"}, false, }, { []string{"", "foo.org."}, - []string{""}, + []string{}, []string{"foo.org"}, true, }, { []string{"", "foo.org."}, - []string{""}, + []string{}, []string{}, true, }, { []string{""}, - []string{""}, + []string{}, []string{"foo.org"}, true, }, { []string{""}, - []string{""}, + []string{}, []string{}, true, }, { []string{" "}, - []string{""}, + []string{}, []string{}, true, }, { []string{"bar.sub.example.org"}, - []string{""}, + []string{}, []string{"foo.bar.sub.example.org"}, true, }, { []string{"example.org"}, - []string{""}, + []string{}, []string{"anexample.org", "test.anexample.org"}, false, }, { []string{".example.org"}, - []string{""}, + []string{}, []string{"anexample.org", "test.anexample.org"}, false, }, { []string{".example.org"}, - []string{""}, + []string{}, []string{"example.org"}, false, }, { []string{".example.org"}, - []string{""}, + []string{}, []string{"test.example.org"}, true, }, { []string{"anexample.org"}, - []string{""}, + []string{}, []string{"example.org", "test.example.org"}, false, }, { []string{".org"}, - []string{""}, + []string{}, []string{"example.org", "test.example.org", "foo.test.example.org"}, true, }, From d228a99ac80e37892c7fa4a3e47a0bd31cb78e0e Mon Sep 17 00:00:00 2001 From: Eugene Venter Date: Wed, 26 May 2021 11:53:59 +1200 Subject: [PATCH 133/175] domain_filter_test.go: generate empty string exclusions if no exclusions for TestDomainFilterWithExclusions --- endpoint/domain_filter_test.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/endpoint/domain_filter_test.go b/endpoint/domain_filter_test.go index 2cb8f0412..ecf8ca318 100644 --- a/endpoint/domain_filter_test.go +++ b/endpoint/domain_filter_test.go @@ -275,6 +275,9 @@ func TestDomainFilterMatch(t *testing.T) { func TestDomainFilterWithExclusions(t *testing.T) { for i, tt := range domainFilterTests { + if len(tt.exclusions) == 0 { + tt.exclusions = append(tt.exclusions, "") + } domainFilter := NewDomainFilterWithExclusions(tt.domainFilter, tt.exclusions) for _, domain := range tt.domains { assert.Equal(t, tt.expected, domainFilter.Match(domain), "should not fail: %v in test-case #%v", domain, i) @@ -308,6 +311,10 @@ func TestPrepareFiltersStripsWhitespaceAndDotSuffix(t *testing.T) { input []string output []string }{ + { + []string{}, + []string{}, + }, { []string{""}, []string{""}, From 8676dda63fe58e1816d48ca8e895c1f3bf2e637b Mon Sep 17 00:00:00 2001 From: Kyle Michel Date: Wed, 26 May 2021 16:16:35 -0400 Subject: [PATCH 134/175] Add support for Kong's TCPIngress with a load balancer --- docs/tutorials/kong.md | 96 +++++++ pkg/apis/externaldns/types.go | 2 +- source/kong_tcpingress.go | 456 +++++++++++++++++++++++++++++++++ source/kong_tcpingress_test.go | 253 ++++++++++++++++++ source/store.go | 10 + source/store_test.go | 7 +- 6 files changed, 821 insertions(+), 3 deletions(-) create mode 100644 docs/tutorials/kong.md create mode 100644 source/kong_tcpingress.go create mode 100644 source/kong_tcpingress_test.go diff --git a/docs/tutorials/kong.md b/docs/tutorials/kong.md new file mode 100644 index 000000000..aa396f8ae --- /dev/null +++ b/docs/tutorials/kong.md @@ -0,0 +1,96 @@ +# Configuring ExternalDNS to use the Kong TCPIngress Source +This tutorial describes how to configure ExternalDNS to use the Kong TCPIngress source. +It is meant to supplement the other provider-specific setup tutorials. + +### Manifest (for clusters without RBAC enabled) +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: external-dns +spec: + strategy: + type: Recreate + selector: + matchLabels: + app: external-dns + template: + metadata: + labels: + app: external-dns + spec: + containers: + - name: external-dns + # update this to the desired external-dns version + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 + args: + - --source=kong-tcpingress + - --provider=aws + - --registry=txt + - --txt-owner-id=my-identifier +``` + +### Manifest (for clusters with RBAC enabled) +Could be changed if you have mulitple sources + +```yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: external-dns +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: external-dns +rules: +- apiGroups: [""] + resources: ["services","endpoints","pods"] + verbs: ["get","watch","list"] +- apiGroups: [""] + resources: ["nodes"] + verbs: ["list","watch"] +- apiGroups: ["configuration.konghq.com"] + resources: ["tcpingresses"] + verbs: ["get","watch","list"] +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: external-dns-viewer +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: external-dns +subjects: +- kind: ServiceAccount + name: external-dns + namespace: default +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: external-dns +spec: + strategy: + type: Recreate + selector: + matchLabels: + app: external-dns + template: + metadata: + labels: + app: external-dns + spec: + serviceAccountName: external-dns + containers: + - name: external-dns + # update this to the desired external-dns version + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 + args: + - --source=kong-tcpingress + - --provider=aws + - --registry=txt + - --txt-owner-id=my-identifier +``` + diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 8655dc480..00ca338de 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -348,7 +348,7 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("skipper-routegroup-groupversion", "The resource version for skipper routegroup").Default(source.DefaultRoutegroupVersion).StringVar(&cfg.SkipperRouteGroupVersion) // Flags related to processing sources - app.Flag("source", "The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress, node, fake, connector, istio-gateway, istio-virtualservice, cloudfoundry, contour-ingressroute, contour-httpproxy, gloo-proxy, crd, empty, skipper-routegroup, openshift-route, ambassador-host)").Required().PlaceHolder("source").EnumsVar(&cfg.Sources, "service", "ingress", "node", "pod", "istio-gateway", "istio-virtualservice", "cloudfoundry", "contour-ingressroute", "contour-httpproxy", "gloo-proxy", "fake", "connector", "crd", "empty", "skipper-routegroup", "openshift-route", "ambassador-host") + app.Flag("source", "The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress, node, fake, connector, istio-gateway, istio-virtualservice, cloudfoundry, contour-ingressroute, contour-httpproxy, gloo-proxy, crd, empty, skipper-routegroup, openshift-route, ambassador-host, kong-tcpingress)").Required().PlaceHolder("source").EnumsVar(&cfg.Sources, "service", "ingress", "node", "pod", "istio-gateway", "istio-virtualservice", "cloudfoundry", "contour-ingressroute", "contour-httpproxy", "gloo-proxy", "fake", "connector", "crd", "empty", "skipper-routegroup", "openshift-route", "ambassador-host", "kong-tcpingress") app.Flag("namespace", "Limit sources of endpoints to a specific namespace (default: all namespaces)").Default(defaultConfig.Namespace).StringVar(&cfg.Namespace) app.Flag("annotation-filter", "Filter sources managed by external-dns via annotation using label selector semantics (default: all sources)").Default(defaultConfig.AnnotationFilter).StringVar(&cfg.AnnotationFilter) app.Flag("label-filter", "Filter sources managed by external-dns via label selector when listing all resources; currently only supported by source CRD").Default(defaultConfig.LabelFilter).StringVar(&cfg.LabelFilter) diff --git a/source/kong_tcpingress.go b/source/kong_tcpingress.go new file mode 100644 index 000000000..639a3f283 --- /dev/null +++ b/source/kong_tcpingress.go @@ -0,0 +1,456 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package source + +import ( + "context" + "fmt" + "sort" + "time" + + //kongv1beta1 "github.com/kong/kubernetes-ingress-controller/pkg/apis/configuration/v1beta1" + "github.com/pkg/errors" + log "github.com/sirupsen/logrus" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/dynamic/dynamicinformer" + "k8s.io/client-go/informers" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/tools/cache" + + "sigs.k8s.io/external-dns/endpoint" +) + +var kongGroupdVersionResource = schema.GroupVersionResource{ + Group: "configuration.konghq.com", + Version: "v1beta1", + Resource: "tcpingresses", +} + +// kongTCPIngressSource is an implementation of Source for Kong TCPIngress objects. +type kongTCPIngressSource struct { + annotationFilter string + dynamicKubeClient dynamic.Interface + kongTCPIngressInformer informers.GenericInformer + kubeClient kubernetes.Interface + namespace string + unstructuredConverter *unstructuredConverter +} + +// NewKongTCPIngressSource creates a new kongTCPIngressSource with the given config. +func NewKongTCPIngressSource(dynamicKubeClient dynamic.Interface, kubeClient kubernetes.Interface, namespace string, annotationFilter string) (Source, error) { + var err error + + // Use shared informer to listen for add/update/delete of Host in the specified namespace. + // Set resync period to 0, to prevent processing when nothing has changed. + informerFactory := dynamicinformer.NewFilteredDynamicSharedInformerFactory(dynamicKubeClient, 0, namespace, nil) + kongTCPIngressInformer := informerFactory.ForResource(kongGroupdVersionResource) + + // Add default resource event handlers to properly initialize informer. + kongTCPIngressInformer.Informer().AddEventHandler( + cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + }, + }, + ) + + // TODO informer is not explicitly stopped since controller is not passing in its channel. + informerFactory.Start(wait.NeverStop) + + // wait for the local cache to be populated. + err = poll(time.Second, 60*time.Second, func() (bool, error) { + return kongTCPIngressInformer.Informer().HasSynced(), nil + }) + if err != nil { + return nil, errors.Wrapf(err, "failed to sync cache") + } + + uc, err := newKongUnstructuredConverter() + if err != nil { + return nil, errors.Wrapf(err, "failed to setup Unstructured Converter") + } + + return &kongTCPIngressSource{ + annotationFilter: annotationFilter, + dynamicKubeClient: dynamicKubeClient, + kongTCPIngressInformer: kongTCPIngressInformer, + kubeClient: kubeClient, + namespace: namespace, + unstructuredConverter: uc, + }, nil +} + +// Endpoints returns endpoint objects for each host-target combination that should be processed. +// Retrieves all TCPIngresses in the source's namespace(s). +func (sc *kongTCPIngressSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error) { + tis, err := sc.kongTCPIngressInformer.Lister().ByNamespace(sc.namespace).List(labels.Everything()) + if err != nil { + return nil, err + } + + var tcpIngresses []*TCPIngress + for _, tcpIngressObj := range tis { + unstructuredHost, ok := tcpIngressObj.(*unstructured.Unstructured) + if !ok { + return nil, errors.New("could not convert") + } + + tcpIngress := &TCPIngress{} + err := sc.unstructuredConverter.scheme.Convert(unstructuredHost, tcpIngress, nil) + if err != nil { + return nil, err + } + tcpIngresses = append(tcpIngresses, tcpIngress) + } + + tcpIngresses, err = sc.filterByAnnotations(tcpIngresses) + if err != nil { + return nil, errors.Wrap(err, "failed to filter TCPIngresses") + } + + var endpoints []*endpoint.Endpoint + for _, tcpIngress := range tcpIngresses { + var targets endpoint.Targets + for _, lb := range tcpIngress.Status.LoadBalancer.Ingress { + if lb.IP != "" { + targets = append(targets, lb.IP) + } + if lb.Hostname != "" { + targets = append(targets, lb.Hostname) + } + } + + fullname := fmt.Sprintf("%s/%s", tcpIngress.Namespace, tcpIngress.Name) + + ingressEndpoints, err := sc.endpointsFromTCPIngress(tcpIngress, targets) + if err != nil { + return nil, err + } + if len(ingressEndpoints) == 0 { + log.Debugf("No endpoints could be generated from Host %s", fullname) + continue + } + + log.Debugf("Endpoints generated from TCPIngress: %s: %v", fullname, ingressEndpoints) + sc.setResourceLabel(tcpIngress, ingressEndpoints) + sc.setDualstackLabel(tcpIngress, ingressEndpoints) + endpoints = append(endpoints, ingressEndpoints...) + } + + for _, ep := range endpoints { + sort.Sort(ep.Targets) + } + + return endpoints, nil +} + +// filterByAnnotations filters a list of TCPIngresses by a given annotation selector. +func (sc *kongTCPIngressSource) filterByAnnotations(tcpIngresses []*TCPIngress) ([]*TCPIngress, error) { + labelSelector, err := metav1.ParseToLabelSelector(sc.annotationFilter) + if err != nil { + return nil, err + } + selector, err := metav1.LabelSelectorAsSelector(labelSelector) + if err != nil { + return nil, err + } + + // empty filter returns original list + if selector.Empty() { + return tcpIngresses, nil + } + + filteredList := []*TCPIngress{} + + for _, tcpIngress := range tcpIngresses { + // convert the TCPIngress's annotations to an equivalent label selector + annotations := labels.Set(tcpIngress.Annotations) + + // include TCPIngress if its annotations match the selector + if selector.Matches(annotations) { + filteredList = append(filteredList, tcpIngress) + } + } + + return filteredList, nil +} + +func (sc *kongTCPIngressSource) setResourceLabel(tcpIngress *TCPIngress, endpoints []*endpoint.Endpoint) { + for _, ep := range endpoints { + ep.Labels[endpoint.ResourceLabelKey] = fmt.Sprintf("tcpingress/%s/%s", tcpIngress.Namespace, tcpIngress.Name) + } +} + +func (sc *kongTCPIngressSource) setDualstackLabel(tcpIngress *TCPIngress, endpoints []*endpoint.Endpoint) { + val, ok := tcpIngress.Annotations[ALBDualstackAnnotationKey] + if ok && val == ALBDualstackAnnotationValue { + log.Debugf("Adding dualstack label to TCPIngress %s/%s.", tcpIngress.Namespace, tcpIngress.Name) + for _, ep := range endpoints { + ep.Labels[endpoint.DualstackLabelKey] = "true" + } + } +} + +// endpointsFromTCPIngress extracts the endpoints from a TCPIngress object +func (sc *kongTCPIngressSource) endpointsFromTCPIngress(tcpIngress *TCPIngress, targets endpoint.Targets) ([]*endpoint.Endpoint, error) { + var endpoints []*endpoint.Endpoint + + providerSpecific, setIdentifier := getProviderSpecificAnnotations(tcpIngress.Annotations) + + ttl, err := getTTLFromAnnotations(tcpIngress.Annotations) + if err != nil { + return nil, err + } + + hostnameList := getHostnamesFromAnnotations(tcpIngress.Annotations) + for _, hostname := range hostnameList { + endpoints = append(endpoints, endpointsForHostname(hostname, targets, ttl, providerSpecific, setIdentifier)...) + } + + if tcpIngress.Spec.Rules != nil { + for _, rule := range tcpIngress.Spec.Rules { + if rule.Host != "" { + endpoints = append(endpoints, endpointsForHostname(rule.Host, targets, ttl, providerSpecific, setIdentifier)...) + } + } + } + + return endpoints, nil +} + +func (sc *kongTCPIngressSource) AddEventHandler(ctx context.Context, handler func()) { + log.Debug("Adding event handler for TCPIngress") + + // Right now there is no way to remove event handler from informer, see: + // https://github.com/kubernetes/kubernetes/issues/79610 + sc.kongTCPIngressInformer.Informer().AddEventHandler( + cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + handler() + }, + UpdateFunc: func(old interface{}, new interface{}) { + handler() + }, + DeleteFunc: func(obj interface{}) { + handler() + }, + }, + ) +} + +// newUnstructuredConverter returns a new unstructuredConverter initialized +func newKongUnstructuredConverter() (*unstructuredConverter, error) { + uc := &unstructuredConverter{ + scheme: runtime.NewScheme(), + } + + // Add the core types we need + uc.scheme.AddKnownTypes(kongGroupdVersionResource.GroupVersion(), &TCPIngress{}, &TCPIngressList{}) + if err := scheme.AddToScheme(uc.scheme); err != nil { + return nil, err + } + + return uc, nil +} + +//Kong types based on https://github.com/Kong/kubernetes-ingress-controller/blob/v1.2.0/pkg/apis/configuration/v1beta1/types.go to facilitate testing +//When trying to import them from the Kong repo as a dependency it required upgrading the k8s.io/client-go and k8s.io/apimachinery which seemed +//cause several changes in how the mock clients were working that resulted in a bunch of failures in other tests +//If that is dealt with at some point the below can be removed and replaced with an actual import + +type TCPIngress struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec tcpIngressSpec `json:"spec,omitempty"` + Status tcpIngressStatus `json:"status,omitempty"` +} + +type TCPIngressList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []TCPIngress `json:"items"` +} + +type tcpIngressSpec struct { + Rules []tcpIngressRule `json:"rules,omitempty"` + TLS []tcpIngressTLS `json:"tls,omitempty"` +} + +type tcpIngressTLS struct { + Hosts []string `json:"hosts,omitempty"` + SecretName string `json:"secretName,omitempty"` +} + +type tcpIngressStatus struct { + LoadBalancer corev1.LoadBalancerStatus `json:"loadBalancer,omitempty"` +} + +type tcpIngressRule struct { + Host string `json:"host,omitempty"` + Port int `json:"port,omitempty"` + Backend tcpIngressBackend `json:"backend"` +} + +type tcpIngressBackend struct { + ServiceName string `json:"serviceName"` + ServicePort int `json:"servicePort"` +} + +func (in *tcpIngressBackend) DeepCopyInto(out *tcpIngressBackend) { + *out = *in +} + +func (in *tcpIngressBackend) DeepCopy() *tcpIngressBackend { + if in == nil { + return nil + } + out := new(tcpIngressBackend) + in.DeepCopyInto(out) + return out +} + +func (in *tcpIngressRule) DeepCopyInto(out *tcpIngressRule) { + *out = *in + out.Backend = in.Backend +} + +func (in *tcpIngressRule) DeepCopy() *tcpIngressRule { + if in == nil { + return nil + } + out := new(tcpIngressRule) + in.DeepCopyInto(out) + return out +} + +func (in *tcpIngressSpec) DeepCopyInto(out *tcpIngressSpec) { + *out = *in + if in.Rules != nil { + in, out := &in.Rules, &out.Rules + *out = make([]tcpIngressRule, len(*in)) + copy(*out, *in) + } + if in.TLS != nil { + in, out := &in.TLS, &out.TLS + *out = make([]tcpIngressTLS, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +func (in *tcpIngressSpec) DeepCopy() *tcpIngressSpec { + if in == nil { + return nil + } + out := new(tcpIngressSpec) + in.DeepCopyInto(out) + return out +} + +func (in *tcpIngressStatus) DeepCopyInto(out *tcpIngressStatus) { + *out = *in + in.LoadBalancer.DeepCopyInto(&out.LoadBalancer) +} + +func (in *tcpIngressStatus) DeepCopy() *tcpIngressStatus { + if in == nil { + return nil + } + out := new(tcpIngressStatus) + in.DeepCopyInto(out) + return out +} + +func (in *tcpIngressTLS) DeepCopyInto(out *tcpIngressTLS) { + *out = *in + if in.Hosts != nil { + in, out := &in.Hosts, &out.Hosts + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +func (in *tcpIngressTLS) DeepCopy() *tcpIngressTLS { + if in == nil { + return nil + } + out := new(tcpIngressTLS) + in.DeepCopyInto(out) + return out +} + +func (in *TCPIngress) DeepCopyInto(out *TCPIngress) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +func (in *TCPIngress) DeepCopy() *TCPIngress { + if in == nil { + return nil + } + out := new(TCPIngress) + in.DeepCopyInto(out) + return out +} + +func (in *TCPIngress) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +func (in *TCPIngressList) DeepCopyInto(out *TCPIngressList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TCPIngress, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +func (in *TCPIngressList) DeepCopy() *TCPIngressList { + if in == nil { + return nil + } + out := new(TCPIngressList) + in.DeepCopyInto(out) + return out +} + +func (in *TCPIngressList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} diff --git a/source/kong_tcpingress_test.go b/source/kong_tcpingress_test.go new file mode 100644 index 000000000..e53a9bda6 --- /dev/null +++ b/source/kong_tcpingress_test.go @@ -0,0 +1,253 @@ +/* +Copyright 2020n The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package source + +import ( + "context" + "encoding/json" + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + fakeDynamic "k8s.io/client-go/dynamic/fake" + fakeKube "k8s.io/client-go/kubernetes/fake" + "sigs.k8s.io/external-dns/endpoint" + "testing" +) + +// This is a compile-time validation that glooSource is a Source. +var _ Source = &kongTCPIngressSource{} + +const defaultKongNamespace = "kong" + +func TestKongTCPIngressEndpoints(t *testing.T) { + for _, ti := range []struct { + title string + tcpProxy TCPIngress + expected []*endpoint.Endpoint + }{ + { + title: "TCPIngress with hostname annotation", + tcpProxy: TCPIngress{ + TypeMeta: metav1.TypeMeta{ + APIVersion: kongGroupdVersionResource.GroupVersion().String(), + Kind: "TCPIngress", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "tcp-ingress-annotation", + Namespace: defaultKongNamespace, + Annotations: map[string]string{ + "external-dns.alpha.kubernetes.io/hostname": "a.example.com", + "kubernetes.io/ingress.class": "kong", + }, + }, + Spec: tcpIngressSpec{ + Rules: []tcpIngressRule{ + { + Port: 30000, + }, + { + Port: 30001, + }, + }, + }, + Status: tcpIngressStatus{ + LoadBalancer: corev1.LoadBalancerStatus{ + Ingress: []corev1.LoadBalancerIngress{ + { + Hostname: "a691234567a314e71861a4303f06a3bd-1291189659.us-east-1.elb.amazonaws.com", + }, + }, + }, + }, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "a.example.com", + Targets: []string{"a691234567a314e71861a4303f06a3bd-1291189659.us-east-1.elb.amazonaws.com"}, + RecordType: endpoint.RecordTypeCNAME, + RecordTTL: 0, + Labels: endpoint.Labels{ + "resource": "tcpingress/kong/tcp-ingress-annotation", + }, + ProviderSpecific: endpoint.ProviderSpecific{}, + }, + }, + }, + { + title: "TCPIngress using SNI", + tcpProxy: TCPIngress{ + TypeMeta: metav1.TypeMeta{ + APIVersion: kongGroupdVersionResource.GroupVersion().String(), + Kind: "TCPIngress", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "tcp-ingress-sni", + Namespace: defaultKongNamespace, + Annotations: map[string]string{ + "kubernetes.io/ingress.class": "kong", + }, + }, + Spec: tcpIngressSpec{ + Rules: []tcpIngressRule{ + { + Port: 30002, + Host: "b.example.com", + }, + { + Port: 30003, + Host: "c.example.com", + }, + }, + }, + Status: tcpIngressStatus{ + LoadBalancer: corev1.LoadBalancerStatus{ + Ingress: []corev1.LoadBalancerIngress{ + { + Hostname: "a123456769a314e71861a4303f06a3bd-1291189659.us-east-1.elb.amazonaws.com", + }, + }, + }, + }, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "b.example.com", + Targets: []string{"a123456769a314e71861a4303f06a3bd-1291189659.us-east-1.elb.amazonaws.com"}, + RecordType: endpoint.RecordTypeCNAME, + RecordTTL: 0, + Labels: endpoint.Labels{ + "resource": "tcpingress/kong/tcp-ingress-sni", + }, + ProviderSpecific: endpoint.ProviderSpecific{}, + }, + { + DNSName: "c.example.com", + Targets: []string{"a123456769a314e71861a4303f06a3bd-1291189659.us-east-1.elb.amazonaws.com"}, + RecordType: endpoint.RecordTypeCNAME, + Labels: endpoint.Labels{ + "resource": "tcpingress/kong/tcp-ingress-sni", + }, + ProviderSpecific: endpoint.ProviderSpecific{}, + }, + }, + }, + { + title: "TCPIngress with hostname annotation and using SNI", + tcpProxy: TCPIngress{ + TypeMeta: metav1.TypeMeta{ + APIVersion: kongGroupdVersionResource.GroupVersion().String(), + Kind: "TCPIngress", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "tcp-ingress-both", + Namespace: defaultKongNamespace, + Annotations: map[string]string{ + "external-dns.alpha.kubernetes.io/hostname": "d.example.com", + "kubernetes.io/ingress.class": "kong", + }, + }, + Spec: tcpIngressSpec{ + Rules: []tcpIngressRule{ + { + Port: 30004, + Host: "e.example.com", + }, + { + Port: 30005, + Host: "f.example.com", + }, + }, + }, + Status: tcpIngressStatus{ + LoadBalancer: corev1.LoadBalancerStatus{ + Ingress: []corev1.LoadBalancerIngress{ + { + Hostname: "a12e71861a4303f063456769a314a3bd-1291189659.us-east-1.elb.amazonaws.com", + }, + }, + }, + }, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "d.example.com", + Targets: []string{"a12e71861a4303f063456769a314a3bd-1291189659.us-east-1.elb.amazonaws.com"}, + RecordType: endpoint.RecordTypeCNAME, + RecordTTL: 0, + Labels: endpoint.Labels{ + "resource": "tcpingress/kong/tcp-ingress-both", + }, + ProviderSpecific: endpoint.ProviderSpecific{}, + }, + { + DNSName: "e.example.com", + Targets: []string{"a12e71861a4303f063456769a314a3bd-1291189659.us-east-1.elb.amazonaws.com"}, + RecordType: endpoint.RecordTypeCNAME, + RecordTTL: 0, + Labels: endpoint.Labels{ + "resource": "tcpingress/kong/tcp-ingress-both", + }, + ProviderSpecific: endpoint.ProviderSpecific{}, + }, + { + DNSName: "f.example.com", + Targets: []string{"a12e71861a4303f063456769a314a3bd-1291189659.us-east-1.elb.amazonaws.com"}, + RecordType: endpoint.RecordTypeCNAME, + RecordTTL: 0, + Labels: endpoint.Labels{ + "resource": "tcpingress/kong/tcp-ingress-both", + }, + ProviderSpecific: endpoint.ProviderSpecific{}, + }, + }, + }, + } { + t.Run(ti.title, func(t *testing.T) { + fakeKubernetesClient := fakeKube.NewSimpleClientset() + scheme := runtime.NewScheme() + scheme.AddKnownTypes(kongGroupdVersionResource.GroupVersion(), &TCPIngress{}, &TCPIngressList{}) + fakeDynamicClient := fakeDynamic.NewSimpleDynamicClient(scheme) + + tcpi := unstructured.Unstructured{} + + tcpIngressAsJSON, err := json.Marshal(ti.tcpProxy) + assert.NoError(t, err) + + assert.NoError(t, tcpi.UnmarshalJSON(tcpIngressAsJSON)) + + // Create proxy resources + _, err = fakeDynamicClient.Resource(kongGroupdVersionResource).Namespace(defaultKongNamespace).Create(context.Background(), &tcpi, metav1.CreateOptions{}) + assert.NoError(t, err) + + source, err := NewKongTCPIngressSource(fakeDynamicClient, fakeKubernetesClient, defaultKongNamespace, "kubernetes.io/ingress.class=kong") + assert.NoError(t, err) + assert.NotNil(t, source) + + count := &unstructured.UnstructuredList{} + for len(count.Items) < 1 { + count, _ = fakeDynamicClient.Resource(kongGroupdVersionResource).Namespace(defaultKongNamespace).List(context.Background(), metav1.ListOptions{}) + } + + endpoints, err := source.Endpoints(context.Background()) + assert.NoError(t, err) + assert.Len(t, endpoints, len(ti.expected)) + assert.Equal(t, endpoints, ti.expected) + }) + } +} diff --git a/source/store.go b/source/store.go index 8bff6a056..2c805fbeb 100644 --- a/source/store.go +++ b/source/store.go @@ -287,6 +287,16 @@ func BuildWithConfig(source string, p ClientGenerator, cfg *Config) (Source, err token = restConfig.BearerToken } return NewRouteGroupSource(cfg.RequestTimeout, token, tokenPath, apiServerURL, cfg.Namespace, cfg.AnnotationFilter, cfg.FQDNTemplate, cfg.SkipperRouteGroupVersion, cfg.CombineFQDNAndAnnotation, cfg.IgnoreHostnameAnnotation) + case "kong-tcpingress": + kubernetesClient, err := p.KubeClient() + if err != nil { + return nil, err + } + dynamicClient, err := p.DynamicKubernetesClient() + if err != nil { + return nil, err + } + return NewKongTCPIngressSource(dynamicClient, kubernetesClient, cfg.Namespace, cfg.AnnotationFilter) } return nil, ErrSourceNotFound } diff --git a/source/store_test.go b/source/store_test.go index e79c6772c..4fa787bbf 100644 --- a/source/store_test.go +++ b/source/store_test.go @@ -96,9 +96,9 @@ func (suite *ByNamesTestSuite) TestAllInitialized() { mockClientGenerator.On("IstioClient").Return(NewFakeConfigStore(), nil) mockClientGenerator.On("DynamicKubernetesClient").Return(fakeDynamic, nil) - sources, err := ByNames(mockClientGenerator, []string{"service", "ingress", "istio-gateway", "contour-ingressroute", "contour-httpproxy", "fake"}, minimalConfig) + sources, err := ByNames(mockClientGenerator, []string{"service", "ingress", "istio-gateway", "contour-ingressroute", "contour-httpproxy", "kong-tcpingress", "fake"}, minimalConfig) suite.NoError(err, "should not generate errors") - suite.Len(sources, 6, "should generate all six sources") + suite.Len(sources, 7, "should generate all six sources") } func (suite *ByNamesTestSuite) TestOnlyFake() { @@ -135,6 +135,9 @@ func (suite *ByNamesTestSuite) TestKubeClientFails() { _, err = ByNames(mockClientGenerator, []string{"contour-ingressroute"}, minimalConfig) suite.Error(err, "should return an error if kubernetes client cannot be created") + + _, err = ByNames(mockClientGenerator, []string{"kong-tcpingress"}, minimalConfig) + suite.Error(err, "should return an error if kubernetes client cannot be created") } func (suite *ByNamesTestSuite) TestIstioClientFails() { From 37654ebad98debff15972badbe694fadbc36f2b3 Mon Sep 17 00:00:00 2001 From: Frederic BOLTZ Date: Thu, 27 May 2021 10:53:59 +0200 Subject: [PATCH 135/175] Update provider/godaddy/godaddy.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Typo: rename e to err Co-authored-by: Nick Jüttner --- provider/godaddy/godaddy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/provider/godaddy/godaddy.go b/provider/godaddy/godaddy.go index 734e16aa8..3386811ce 100644 --- a/provider/godaddy/godaddy.go +++ b/provider/godaddy/godaddy.go @@ -548,7 +548,7 @@ func maxOf(vars ...int64) int64 { } func toString(obj interface{}) string { - b, e := json.MarshalIndent(obj, "", " ") + b, err := json.MarshalIndent(obj, "", " ") if e != nil { return fmt.Sprintf("<%v>", e) From d307a23f5af2dffe84b18a7ec0b4d4eaae82f83b Mon Sep 17 00:00:00 2001 From: Frederic BOLTZ Date: Thu, 27 May 2021 10:54:09 +0200 Subject: [PATCH 136/175] Update provider/godaddy/godaddy.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Typo: rename e to err Co-authored-by: Nick Jüttner --- provider/godaddy/godaddy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/provider/godaddy/godaddy.go b/provider/godaddy/godaddy.go index 3386811ce..5638576e3 100644 --- a/provider/godaddy/godaddy.go +++ b/provider/godaddy/godaddy.go @@ -550,7 +550,7 @@ func maxOf(vars ...int64) int64 { func toString(obj interface{}) string { b, err := json.MarshalIndent(obj, "", " ") - if e != nil { + if err != nil { return fmt.Sprintf("<%v>", e) } From 8763a504b0e84e7098b71a6f2bc41d210bf5db74 Mon Sep 17 00:00:00 2001 From: Frederic BOLTZ Date: Thu, 27 May 2021 10:54:19 +0200 Subject: [PATCH 137/175] Update provider/godaddy/godaddy.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Typo: rename e to err Co-authored-by: Nick Jüttner --- provider/godaddy/godaddy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/provider/godaddy/godaddy.go b/provider/godaddy/godaddy.go index 5638576e3..fcc7a2cbd 100644 --- a/provider/godaddy/godaddy.go +++ b/provider/godaddy/godaddy.go @@ -551,7 +551,7 @@ func toString(obj interface{}) string { b, err := json.MarshalIndent(obj, "", " ") if err != nil { - return fmt.Sprintf("<%v>", e) + return fmt.Sprintf("<%v>", err) } return string(b) From e2a8da45dadf1b28e5d8fd0ab903dc0d9a3ca0e7 Mon Sep 17 00:00:00 2001 From: fboltz Date: Thu, 27 May 2021 11:24:56 +0200 Subject: [PATCH 138/175] Replace string pointer by string value --- provider/godaddy/client.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/provider/godaddy/client.go b/provider/godaddy/client.go index 335994129..3631387b1 100644 --- a/provider/godaddy/client.go +++ b/provider/godaddy/client.go @@ -79,10 +79,10 @@ type Client struct { // GDErrorField describe the error reason type GDErrorField struct { - Code *string `json:"code,omitempty"` - Message *string `json:"message,omitempty"` - Path *string `json:"path,omitempty"` - PathRelated *string `json:"pathRelated,omitempty"` + Code string `json:"code,omitempty"` + Message string `json:"message,omitempty"` + Path string `json:"path,omitempty"` + PathRelated string `json:"pathRelated,omitempty"` } // GDErrorResponse is the body response when an API call fails From 9119f6903549b5153389e6ea379e5c5e09f7accd Mon Sep 17 00:00:00 2001 From: fboltz Date: Thu, 27 May 2021 11:25:43 +0200 Subject: [PATCH 139/175] Go daddy status code are not HTTP status code, don't be confused --- provider/godaddy/godaddy_test.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/provider/godaddy/godaddy_test.go b/provider/godaddy/godaddy_test.go index 370585e66..2ab9cead6 100644 --- a/provider/godaddy/godaddy_test.go +++ b/provider/godaddy/godaddy_test.go @@ -379,9 +379,11 @@ func TestGoDaddyChange(t *testing.T) { client.AssertExpectations(t) } -var ( - status404 string = "404" - notfound string = "Record not found" +const ( + operationFailedTestErrCode = "GD500" + operationFailedTestReason = "Could not apply request" + recordNotFoundErrCode = "GD404" + recordNotFoundReason = "The requested record is not found in DNS zone" ) func TestGoDaddyErrorResponse(t *testing.T) { @@ -432,13 +434,13 @@ func TestGoDaddyErrorResponse(t *testing.T) { // Delete entry client.On("Delete", "/v1/domains/example.net/records/A/godaddy").Return(GDErrorResponse{ - Code: status404, - Message: notfound, + Code: operationFailedTestErrCode, + Message: operationFailedTestReason, Fields: []GDErrorField{{ - Code: &status404, - Message: ¬found, + Code: recordNotFoundErrCode, + Message: recordNotFoundReason, }}, - }, errors.New(notfound)).Once() + }, errors.New(operationFailedTestReason)).Once() assert.Error(provider.ApplyChanges(context.TODO(), &changes)) From 539aa8980e5e155d50de5f50597498841e40b251 Mon Sep 17 00:00:00 2001 From: mmerrill3 Date: Wed, 26 May 2021 16:38:44 -0400 Subject: [PATCH 140/175] Adding ability to query Infoblox API using regex for fqdn (#2102) Signed-off-by: mmerrill3 --- docs/tutorials/infoblox.md | 8 ++++++++ main.go | 1 + pkg/apis/externaldns/types.go | 3 +++ provider/infoblox/infoblox.go | 31 ++++++++++++++++++++---------- provider/infoblox/infoblox_test.go | 26 +++++++++++++++++++++++-- 5 files changed, 57 insertions(+), 12 deletions(-) diff --git a/docs/tutorials/infoblox.md b/docs/tutorials/infoblox.md index f0b95d557..d7c4b0ad1 100644 --- a/docs/tutorials/infoblox.md +++ b/docs/tutorials/infoblox.md @@ -260,3 +260,11 @@ $ curl -kl \ -u ${WAPI_USERNAME}:${WAPI_PASSWORD} \ https://${GRID_HOST}:${WAPI_PORT}/wapi/v${WAPI_VERSION}/zone_auth?fqdn=example.com ``` + +## Ability to filter results from the zone auth API using a regular expression + +There is also the ability to filter results from the Infoblox zone_auth service based upon a regular expression. See the [Infoblox API document](https://www.infoblox.com/wp-content/uploads/infoblox-deployment-infoblox-rest-api.pdf) for examples. To use this feature for the zone_auth service, set the parameter infoblox-fqdn-regex for external-dns to a regular expression that makes sense for you. For instance, to only return hosted zones that start with staging in the test.com domain (like staging.beta.test.com, or staging.test.com), use the following command line option when starting external-dns + +``` +--infoblox-fqdn-regex=^staging.*test.com$ +``` diff --git a/main.go b/main.go index 1a6f7cf65..9e337edb2 100644 --- a/main.go +++ b/main.go @@ -240,6 +240,7 @@ func main() { View: cfg.InfobloxView, MaxResults: cfg.InfobloxMaxResults, DryRun: cfg.DryRun, + FQDNRexEx: cfg.InfobloxFQDNRegEx, }, ) case "dyn": diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 8655dc480..539958820 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -105,6 +105,7 @@ type Config struct { InfobloxSSLVerify bool InfobloxView string InfobloxMaxResults int + InfobloxFQDNRegEx string DynCustomerName string DynUsername string DynPassword string `secure:"yes"` @@ -228,6 +229,7 @@ var defaultConfig = &Config{ InfobloxSSLVerify: true, InfobloxView: "", InfobloxMaxResults: 0, + InfobloxFQDNRegEx: "", OCIConfigFile: "/etc/kubernetes/oci.yaml", InMemoryZones: []string{}, OVHEndpoint: "ovh-eu", @@ -410,6 +412,7 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("infoblox-ssl-verify", "When using the Infoblox provider, specify whether to verify the SSL certificate (default: true, disable with --no-infoblox-ssl-verify)").Default(strconv.FormatBool(defaultConfig.InfobloxSSLVerify)).BoolVar(&cfg.InfobloxSSLVerify) app.Flag("infoblox-view", "DNS view (default: \"\")").Default(defaultConfig.InfobloxView).StringVar(&cfg.InfobloxView) app.Flag("infoblox-max-results", "Add _max_results as query parameter to the URL on all API requests. The default is 0 which means _max_results is not set and the default of the server is used.").Default(strconv.Itoa(defaultConfig.InfobloxMaxResults)).IntVar(&cfg.InfobloxMaxResults) + app.Flag("infoblox-fqdn-regex", "Apply this regular expression as a filter for obtaining zone_auth objects. This is disabled by default.").Default(defaultConfig.InfobloxFQDNRegEx).StringVar(&cfg.InfobloxFQDNRegEx) app.Flag("dyn-customer-name", "When using the Dyn provider, specify the Customer Name").Default("").StringVar(&cfg.DynCustomerName) app.Flag("dyn-username", "When using the Dyn provider, specify the Username").Default("").StringVar(&cfg.DynUsername) app.Flag("dyn-password", "When using the Dyn provider, specify the password").Default("").StringVar(&cfg.DynPassword) diff --git a/provider/infoblox/infoblox.go b/provider/infoblox/infoblox.go index 0cf08969e..9c98adf2e 100644 --- a/provider/infoblox/infoblox.go +++ b/provider/infoblox/infoblox.go @@ -46,6 +46,7 @@ type InfobloxConfig struct { DryRun bool View string MaxResults int + FQDNRexEx string } // InfobloxProvider implements the DNS provider for Infoblox. @@ -56,6 +57,7 @@ type InfobloxProvider struct { zoneIDFilter provider.ZoneIDFilter view string dryRun bool + fqdnRegEx string } type infobloxRecordSet struct { @@ -63,28 +65,36 @@ type infobloxRecordSet struct { res interface{} } -// MaxResultsRequestBuilder implements a HttpRequestBuilder which sets the -// _max_results query parameter on all get requests -type MaxResultsRequestBuilder struct { +// ExtendedRequestBuilder implements a HttpRequestBuilder which sets +// additional query parameter on all get requests +type ExtendedRequestBuilder struct { + fqdnRegEx string maxResults int ibclient.WapiRequestBuilder } -// NewMaxResultsRequestBuilder returns a MaxResultsRequestBuilder which adds +// NewExtendedRequestBuilder returns a ExtendedRequestBuilder which adds // _max_results query parameter to all GET requests -func NewMaxResultsRequestBuilder(maxResults int) *MaxResultsRequestBuilder { - return &MaxResultsRequestBuilder{ +func NewExtendedRequestBuilder(maxResults int, fqdnRegEx string) *ExtendedRequestBuilder { + return &ExtendedRequestBuilder{ + fqdnRegEx: fqdnRegEx, maxResults: maxResults, } } // BuildRequest prepares the api request. it uses BuildRequest of // WapiRequestBuilder and then add the _max_requests parameter -func (mrb *MaxResultsRequestBuilder) BuildRequest(t ibclient.RequestType, obj ibclient.IBObject, ref string, queryParams ibclient.QueryParams) (req *http.Request, err error) { +func (mrb *ExtendedRequestBuilder) BuildRequest(t ibclient.RequestType, obj ibclient.IBObject, ref string, queryParams ibclient.QueryParams) (req *http.Request, err error) { req, err = mrb.WapiRequestBuilder.BuildRequest(t, obj, ref, queryParams) if req.Method == "GET" { query := req.URL.Query() - query.Set("_max_results", strconv.Itoa(mrb.maxResults)) + if mrb.maxResults > 0 { + query.Set("_max_results", strconv.Itoa(mrb.maxResults)) + } + _, ok := obj.(*ibclient.ZoneAuth) + if ok && t == ibclient.GET && mrb.fqdnRegEx != "" { + query.Set("fqdn~", mrb.fqdnRegEx) + } req.URL.RawQuery = query.Encode() } return @@ -110,9 +120,9 @@ func NewInfobloxProvider(infobloxConfig InfobloxConfig) (*InfobloxProvider, erro ) var requestBuilder ibclient.HttpRequestBuilder - if infobloxConfig.MaxResults != 0 { + if infobloxConfig.MaxResults != 0 || infobloxConfig.FQDNRexEx != "" { // use our own HttpRequestBuilder which sets _max_results parameter on GET requests - requestBuilder = NewMaxResultsRequestBuilder(infobloxConfig.MaxResults) + requestBuilder = NewExtendedRequestBuilder(infobloxConfig.MaxResults, infobloxConfig.FQDNRexEx) } else { // use the default HttpRequestBuilder of the infoblox client requestBuilder = &ibclient.WapiRequestBuilder{} @@ -132,6 +142,7 @@ func NewInfobloxProvider(infobloxConfig InfobloxConfig) (*InfobloxProvider, erro zoneIDFilter: infobloxConfig.ZoneIDFilter, dryRun: infobloxConfig.DryRun, view: infobloxConfig.View, + fqdnRegEx: infobloxConfig.FQDNRexEx, } return provider, nil diff --git a/provider/infoblox/infoblox_test.go b/provider/infoblox/infoblox_test.go index 6bccf7e38..a91e03664 100644 --- a/provider/infoblox/infoblox_test.go +++ b/provider/infoblox/infoblox_test.go @@ -533,7 +533,7 @@ func TestInfobloxZones(t *testing.T) { assert.Equal(t, provider.findZone(zones, "lvl2-2.lvl1-2.example.com").Fqdn, "example.com") } -func TestMaxResultsRequestBuilder(t *testing.T) { +func TestExtendedRequestFDQDRegExBuilder(t *testing.T) { hostConfig := ibclient.HostConfig{ Host: "localhost", Port: "8080", @@ -542,7 +542,29 @@ func TestMaxResultsRequestBuilder(t *testing.T) { Version: "2.3.1", } - requestBuilder := NewMaxResultsRequestBuilder(54321) + requestBuilder := NewExtendedRequestBuilder(0, "^staging.*test.com$") + requestBuilder.Init(hostConfig) + + obj := ibclient.NewZoneAuth(ibclient.ZoneAuth{}) + + req, _ := requestBuilder.BuildRequest(ibclient.GET, obj, "", ibclient.QueryParams{}) + + assert.True(t, req.URL.Query().Get("fqdn~") == "^staging.*test.com$") + + req, _ = requestBuilder.BuildRequest(ibclient.CREATE, obj, "", ibclient.QueryParams{}) + + assert.True(t, req.URL.Query().Get("fqdn~") == "") +} +func TestExtendedRequestMaxResultsBuilder(t *testing.T) { + hostConfig := ibclient.HostConfig{ + Host: "localhost", + Port: "8080", + Username: "user", + Password: "abcd", + Version: "2.3.1", + } + + requestBuilder := NewExtendedRequestBuilder(54321, "") requestBuilder.Init(hostConfig) obj := ibclient.NewRecordCNAME(ibclient.RecordCNAME{Zone: "foo.bar.com"}) From 249370ba85725e782b61e4a2b2fcd7f2e3c3e255 Mon Sep 17 00:00:00 2001 From: Eugene Venter Date: Wed, 26 May 2021 10:02:37 +1200 Subject: [PATCH 141/175] docs/tutorials/pdns.md: updates --- docs/tutorials/pdns.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/tutorials/pdns.md b/docs/tutorials/pdns.md index 492e00688..1a9352b75 100644 --- a/docs/tutorials/pdns.md +++ b/docs/tutorials/pdns.md @@ -54,13 +54,15 @@ spec: - --interval=30s ``` -#### Domain Filter (--domain-filter) -When the domain-filter argument is specified, external-dns will automatically create DNS records based on host names specified in ingress objects and services with the external-dns annotation that match the domain-filter argument in the external-dns deployment manifest. +#### Domain Filter (`--domain-filter`) +When the `--domain-filter` argument is specified, external-dns will only create DNS records for host names (specified in ingress objects and services with the external-dns annotation) related to zones that match the `--domain-filter` argument in the external-dns deployment manifest. eg. ```--domain-filter=example.org``` will allow for zone `example.org` and any zones in PowerDNS that ends in `.example.org`, including `an.example.org`, ie. the subdomains of example.org. eg. ```--domain-filter=.example.org``` will allow *only* zones that end in `.example.org`, ie. the subdomains of example.org but not the `example.org` zone itself. +The filter can also match parent zones. For example `--domain-filter=a.example.com` will allow for zone `example.com`. If you want to match parent zones, you cannot pre-pend your filter with a ".", eg. `--domain-filter=.example.com` will not attempt to match parent zones. + ## RBAC If your cluster is RBAC enabled, you also need to setup the following, before you can run external-dns: From fc37ff0f2c05776c378511deee11beead73fe3e8 Mon Sep 17 00:00:00 2001 From: Eugene Venter Date: Wed, 26 May 2021 13:46:06 +1200 Subject: [PATCH 142/175] endpoint/domain_filter.go: add MatchParent DomainFilter method --- endpoint/domain_filter.go | 25 +++++++++++++ endpoint/domain_filter_test.go | 66 ++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/endpoint/domain_filter.go b/endpoint/domain_filter.go index 91445e862..539bafd73 100644 --- a/endpoint/domain_filter.go +++ b/endpoint/domain_filter.go @@ -106,6 +106,31 @@ func matchRegex(regex *regexp.Regexp, negativeRegex *regexp.Regexp, domain strin return regex.MatchString(strippedDomain) } +// MatchParent checks wether DomainFilter matches a given parent domain. +func (df DomainFilter) MatchParent(domain string) bool { + if !df.IsConfigured() { + return true + } + + for _, filter := range df.Filters { + if strings.HasPrefix(filter, ".") { + // We don't check parents if the filter is prefixed with "." + continue + } + + if filter == "" { + return true + } + + strippedDomain := strings.ToLower(strings.TrimSuffix(domain, ".")) + if strings.HasSuffix(filter, "."+strippedDomain) && !matchFilter(df.exclude, domain, false) { + return true + } + } + + return false +} + // IsConfigured returns true if DomainFilter is configured, false otherwise func (df DomainFilter) IsConfigured() bool { if df.regex != nil && df.regex.String() != "" { diff --git a/endpoint/domain_filter_test.go b/endpoint/domain_filter_test.go index ecf8ca318..64647f71c 100644 --- a/endpoint/domain_filter_test.go +++ b/endpoint/domain_filter_test.go @@ -296,6 +296,72 @@ func TestDomainFilterMatchWithEmptyFilter(t *testing.T) { } } +func TestDomainFilterMatchParent(t *testing.T) { + parentMatchTests := []domainFilterTest{ + { + []string{"a.example.com."}, + []string{}, + []string{"example.com"}, + true, + }, + { + []string{" a.example.com "}, + []string{}, + []string{"example.com"}, + true, + }, + { + []string{""}, + []string{}, + []string{"example.com"}, + true, + }, + { + []string{".a.example.com."}, + []string{}, + []string{"example.com"}, + false, + }, + { + []string{"a.example.com.", "b.example.com"}, + []string{}, + []string{"example.com"}, + true, + }, + { + []string{"a.example.com"}, + []string{}, + []string{"b.example.com"}, + false, + }, + { + []string{"example.com"}, + []string{}, + []string{"example.com"}, + false, + }, + { + []string{"example.com"}, + []string{}, + []string{"anexample.com"}, + false, + }, + { + []string{""}, + []string{}, + []string{""}, + true, + }, + } + for i, tt := range parentMatchTests { + domainFilter := NewDomainFilterWithExclusions(tt.domainFilter, tt.exclusions) + for _, domain := range tt.domains { + assert.Equal(t, tt.expected, domainFilter.MatchParent(domain), "should not fail: %v in test-case #%v", domain, i) + assert.Equal(t, tt.expected, domainFilter.MatchParent(domain+"."), "should not fail: %v in test-case #%v", domain+".", i) + } + } +} + func TestRegexDomainFilter(t *testing.T) { for i, tt := range regexDomainFilterTests { domainFilter := NewRegexDomainFilter(tt.regex, tt.regexExclusion) From e32daefbbc2c5dd2de385b290a2db33493ff464c Mon Sep 17 00:00:00 2001 From: Eugene Venter Date: Wed, 26 May 2021 13:47:40 +1200 Subject: [PATCH 143/175] pdns: also match parent zones when partitioning zones --- provider/pdns/pdns.go | 2 +- provider/pdns/pdns_test.go | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/provider/pdns/pdns.go b/provider/pdns/pdns.go index a609b281e..cf8132b7f 100644 --- a/provider/pdns/pdns.go +++ b/provider/pdns/pdns.go @@ -166,7 +166,7 @@ func (c *PDNSAPIClient) ListZones() (zones []pgo.Zone, resp *http.Response, err func (c *PDNSAPIClient) PartitionZones(zones []pgo.Zone) (filteredZones []pgo.Zone, residualZones []pgo.Zone) { if c.domainFilter.IsConfigured() { for _, zone := range zones { - if c.domainFilter.Match(zone.Name) { + if c.domainFilter.Match(zone.Name) || c.domainFilter.MatchParent(zone.Name) { filteredZones = append(filteredZones, zone) } else { residualZones = append(residualZones, zone) diff --git a/provider/pdns/pdns_test.go b/provider/pdns/pdns_test.go index 4fc2dc61a..d9fd9b401 100644 --- a/provider/pdns/pdns_test.go +++ b/provider/pdns/pdns_test.go @@ -478,6 +478,12 @@ var ( }, } + DomainFilterChildListSingle = endpoint.DomainFilter{ + Filters: []string{ + "a.example.com", + }, + } + DomainFilterListMultiple = endpoint.DomainFilter{ Filters: []string{ "example.com", @@ -485,6 +491,13 @@ var ( }, } + DomainFilterChildListMultiple = endpoint.DomainFilter{ + Filters: []string{ + "a.example.com", + "c.example.com", + }, + } + DomainFilterListEmpty = endpoint.DomainFilter{ Filters: []string{}, } @@ -503,12 +516,26 @@ var ( domainFilter: DomainFilterListSingle, } + DomainFilterChildSingleClient = &PDNSAPIClient{ + dryRun: false, + authCtx: context.WithValue(context.Background(), pgo.ContextAPIKey, pgo.APIKey{Key: "TEST-API-KEY"}), + client: pgo.NewAPIClient(pgo.NewConfiguration()), + domainFilter: DomainFilterChildListSingle, + } + DomainFilterMultipleClient = &PDNSAPIClient{ dryRun: false, authCtx: context.WithValue(context.Background(), pgo.ContextAPIKey, pgo.APIKey{Key: "TEST-API-KEY"}), client: pgo.NewAPIClient(pgo.NewConfiguration()), domainFilter: DomainFilterListMultiple, } + + DomainFilterChildMultipleClient = &PDNSAPIClient{ + dryRun: false, + authCtx: context.WithValue(context.Background(), pgo.ContextAPIKey, pgo.APIKey{Key: "TEST-API-KEY"}), + client: pgo.NewAPIClient(pgo.NewConfiguration()), + domainFilter: DomainFilterChildListMultiple, + } ) /******************************************************************************/ @@ -1015,6 +1042,16 @@ func (suite *NewPDNSProviderTestSuite) TestPDNSClientPartitionZones() { filteredZones, residualZones = DomainFilterMultipleClient.PartitionZones(zoneList) assert.Equal(suite.T(), partitionResultFilteredMultipleFilter, filteredZones) assert.Equal(suite.T(), partitionResultResidualMultipleFilter, residualZones) + + // Check filtered, residual zones when a single child domain filter specified + filteredZones, residualZones = DomainFilterChildSingleClient.PartitionZones(zoneList) + assert.Equal(suite.T(), partitionResultFilteredSingleFilter, filteredZones) + assert.Equal(suite.T(), partitionResultResidualSingleFilter, residualZones) + + // Check filter, residual zones when multiple child domain filters specified + filteredZones, residualZones = DomainFilterChildMultipleClient.PartitionZones(zoneList) + assert.Equal(suite.T(), partitionResultFilteredMultipleFilter, filteredZones) + assert.Equal(suite.T(), partitionResultResidualMultipleFilter, residualZones) } func TestNewPDNSProviderTestSuite(t *testing.T) { From 74c9c7d3029036521ae896d83d85b3447c48e9dc Mon Sep 17 00:00:00 2001 From: Raffaele Di Fazio Date: Wed, 2 Jun 2021 09:24:43 +0200 Subject: [PATCH 144/175] updates readme to mention v0.8 release --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 11d285aeb..46cf77756 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,9 @@ The [FAQ](docs/faq.md) contains additional information and addresses several que To see ExternalDNS in action, have a look at this [video](https://www.youtube.com/watch?v=9HQ2XgL9YVI) or read this [blogpost](https://codemine.be/posts/20190125-devops-eks-externaldns/). -## The Latest Release: v0.7 +## The Latest Release: v0.8 -ExternalDNS' current release is `v0.7`. This version allows you to keep selected zones (via `--domain-filter`) synchronized with Ingresses and Services of `type=LoadBalancer` in various cloud providers: +ExternalDNS' current release is `v0.8`. This version allows you to keep selected zones (via `--domain-filter`) synchronized with Ingresses and Services of `type=LoadBalancer` in various cloud providers: * [Google Cloud DNS](https://cloud.google.com/dns/docs/) * [AWS Route 53](https://aws.amazon.com/route53/) * [AWS Cloud Map](https://docs.aws.amazon.com/cloud-map/) From 57597820cff93037495daa7a5af46076f8ca0c66 Mon Sep 17 00:00:00 2001 From: aSauerwein Date: Wed, 2 Jun 2021 11:19:43 +0200 Subject: [PATCH 145/175] Update rfc2136.md rfc2136-gss-tsig is needed for secure dynamic updates on windows --- docs/tutorials/rfc2136.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/tutorials/rfc2136.md b/docs/tutorials/rfc2136.md index 05d06d4a5..6289c5028 100644 --- a/docs/tutorials/rfc2136.md +++ b/docs/tutorials/rfc2136.md @@ -380,6 +380,7 @@ You'll want to configure `external-dns` similarly to the following: ```text ... - --provider=rfc2136 + - --rfc2136-gss-tsig - --rfc2136-host=dns-host.yourdomain.com - --rfc2136-port=53 - --rfc2136-zone=your-zone.com From ea9158cbf2e5b3cc2c5f89e3e3f1da6046253443 Mon Sep 17 00:00:00 2001 From: Artem Voronin Date: Wed, 2 Jun 2021 18:47:20 +0300 Subject: [PATCH 146/175] Fixed node nil labels map with aws-sd registry --- source/node.go | 1 + 1 file changed, 1 insertion(+) diff --git a/source/node.go b/source/node.go index 0ac6ea493..31f330043 100644 --- a/source/node.go +++ b/source/node.go @@ -151,6 +151,7 @@ func (ns *nodeSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, erro } ep.Targets = endpoint.Targets(addrs) + ep.Labels = endpoint.NewLabels() log.Debugf("adding endpoint %s", ep) if _, ok := endpoints[ep.DNSName]; ok { From 083e243eae663370ca662eeb01b094803631e0f7 Mon Sep 17 00:00:00 2001 From: Kundan Kumar Date: Thu, 3 Jun 2021 17:07:44 +0530 Subject: [PATCH 147/175] fix_2099 --- docs/tutorials/alibabacloud.md | 4 ++-- docs/tutorials/aws-sd.md | 4 ++-- docs/tutorials/aws.md | 4 ++-- docs/tutorials/azure-private-dns.md | 8 ++++---- docs/tutorials/azure.md | 8 ++++---- docs/tutorials/cloudflare.md | 4 ++-- docs/tutorials/contour.md | 4 ++-- docs/tutorials/coredns.md | 4 ++-- docs/tutorials/designate.md | 4 ++-- docs/tutorials/digitalocean.md | 4 ++-- docs/tutorials/dnsimple.md | 4 ++-- docs/tutorials/exoscale.md | 4 ++-- docs/tutorials/gke.md | 4 ++-- docs/tutorials/gloo-proxy.md | 4 ++-- docs/tutorials/godaddy.md | 4 ++-- docs/tutorials/hetzner.md | 4 ++-- docs/tutorials/hostport.md | 4 ++-- docs/tutorials/infoblox.md | 4 ++-- docs/tutorials/kube-ingress-aws.md | 2 +- docs/tutorials/linode.md | 4 ++-- docs/tutorials/nginx-ingress.md | 4 ++-- docs/tutorials/ns1.md | 4 ++-- docs/tutorials/openshift.md | 4 ++-- docs/tutorials/oracle.md | 4 ++-- docs/tutorials/ovh.md | 4 ++-- docs/tutorials/pdns.md | 4 ++-- docs/tutorials/rcodezero.md | 4 ++-- docs/tutorials/rdns.md | 4 ++-- docs/tutorials/rfc2136.md | 4 ++-- docs/tutorials/scaleway.md | 4 ++-- docs/tutorials/transip.md | 4 ++-- docs/tutorials/ultradns.md | 4 ++-- docs/tutorials/vinyldns.md | 4 ++-- docs/tutorials/vultr.md | 4 ++-- kustomize/external-dns-clusterrole.yaml | 2 +- kustomize/external-dns-clusterrolebinding.yaml | 2 +- 36 files changed, 73 insertions(+), 73 deletions(-) diff --git a/docs/tutorials/alibabacloud.md b/docs/tutorials/alibabacloud.md index de9ad9365..85ee20386 100644 --- a/docs/tutorials/alibabacloud.md +++ b/docs/tutorials/alibabacloud.md @@ -141,7 +141,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -156,7 +156,7 @@ rules: resources: ["nodes"] verbs: ["list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/aws-sd.md b/docs/tutorials/aws-sd.md index e75d363ad..0b6119817 100644 --- a/docs/tutorials/aws-sd.md +++ b/docs/tutorials/aws-sd.md @@ -102,7 +102,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -117,7 +117,7 @@ rules: resources: ["nodes"] verbs: ["list","watch"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/aws.md b/docs/tutorials/aws.md index 3d9d7ea51..75dfbfc6f 100644 --- a/docs/tutorials/aws.md +++ b/docs/tutorials/aws.md @@ -166,7 +166,7 @@ metadata: # Substitute your account ID and IAM service role name below. eks.amazonaws.com/role-arn: arn:aws:iam::ACCOUNT-ID:role/IAM-SERVICE-ROLE-NAME --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -181,7 +181,7 @@ rules: resources: ["nodes"] verbs: ["list","watch"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/azure-private-dns.md b/docs/tutorials/azure-private-dns.md index ea7cfb8de..a607da9bf 100644 --- a/docs/tutorials/azure-private-dns.md +++ b/docs/tutorials/azure-private-dns.md @@ -196,7 +196,7 @@ kind: ServiceAccount metadata: name: externaldns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: externaldns @@ -211,7 +211,7 @@ rules: resources: ["nodes"] verbs: ["get", "watch", "list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: externaldns-viewer @@ -271,7 +271,7 @@ kind: ServiceAccount metadata: name: externaldns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: externaldns @@ -283,7 +283,7 @@ rules: resources: ["ingresses"] verbs: ["get","watch","list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: externaldns diff --git a/docs/tutorials/azure.md b/docs/tutorials/azure.md index 947a657b4..ed91fc5a4 100644 --- a/docs/tutorials/azure.md +++ b/docs/tutorials/azure.md @@ -218,7 +218,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -233,7 +233,7 @@ rules: resources: ["nodes"] verbs: ["list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer @@ -295,7 +295,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: external-dns @@ -307,7 +307,7 @@ rules: resources: ["ingresses"] verbs: ["get","watch","list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: external-dns diff --git a/docs/tutorials/cloudflare.md b/docs/tutorials/cloudflare.md index 98580585c..ff2b2e008 100644 --- a/docs/tutorials/cloudflare.md +++ b/docs/tutorials/cloudflare.md @@ -72,7 +72,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -87,7 +87,7 @@ rules: resources: ["nodes"] verbs: ["list", "watch"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/contour.md b/docs/tutorials/contour.md index ed055b16d..9d66d8dfd 100644 --- a/docs/tutorials/contour.md +++ b/docs/tutorials/contour.md @@ -48,7 +48,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -71,7 +71,7 @@ rules: resources: ["httpproxies"] verbs: ["get","watch","list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/coredns.md b/docs/tutorials/coredns.md index b07edd930..5b2436322 100644 --- a/docs/tutorials/coredns.md +++ b/docs/tutorials/coredns.md @@ -122,7 +122,7 @@ spec: ```yaml --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -137,7 +137,7 @@ rules: resources: ["nodes"] verbs: ["list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/designate.md b/docs/tutorials/designate.md index 2871d2764..25f028aee 100644 --- a/docs/tutorials/designate.md +++ b/docs/tutorials/designate.md @@ -87,7 +87,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -105,7 +105,7 @@ rules: resources: ["nodes"] verbs: ["watch","list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/digitalocean.md b/docs/tutorials/digitalocean.md index cd1356fa8..a763ac798 100644 --- a/docs/tutorials/digitalocean.md +++ b/docs/tutorials/digitalocean.md @@ -60,7 +60,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -75,7 +75,7 @@ rules: resources: ["nodes"] verbs: ["list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/dnsimple.md b/docs/tutorials/dnsimple.md index 2b7113841..f532f8174 100644 --- a/docs/tutorials/dnsimple.md +++ b/docs/tutorials/dnsimple.md @@ -54,7 +54,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -69,7 +69,7 @@ rules: resources: ["nodes"] verbs: ["list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/exoscale.md b/docs/tutorials/exoscale.md index faf8b70eb..608e4b6e8 100644 --- a/docs/tutorials/exoscale.md +++ b/docs/tutorials/exoscale.md @@ -66,7 +66,7 @@ metadata: --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -83,7 +83,7 @@ rules: --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/gke.md b/docs/tutorials/gke.md index a573f9d51..83db6c1eb 100644 --- a/docs/tutorials/gke.md +++ b/docs/tutorials/gke.md @@ -70,7 +70,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -85,7 +85,7 @@ rules: resources: ["nodes"] verbs: ["get", "watch", "list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/gloo-proxy.md b/docs/tutorials/gloo-proxy.md index 4938feb21..63f285477 100644 --- a/docs/tutorials/gloo-proxy.md +++ b/docs/tutorials/gloo-proxy.md @@ -40,7 +40,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -58,7 +58,7 @@ rules: resources: ["virtualservices"] verbs: ["get", "list", "watch"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/godaddy.md b/docs/tutorials/godaddy.md index c6d24b46f..aa6936f56 100644 --- a/docs/tutorials/godaddy.md +++ b/docs/tutorials/godaddy.md @@ -63,7 +63,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -84,7 +84,7 @@ rules: resources: ["endpoints"] verbs: ["get","watch","list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/hetzner.md b/docs/tutorials/hetzner.md index 3cf647037..dbae14e98 100644 --- a/docs/tutorials/hetzner.md +++ b/docs/tutorials/hetzner.md @@ -60,7 +60,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -75,7 +75,7 @@ rules: resources: ["nodes"] verbs: ["list","watch"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/hostport.md b/docs/tutorials/hostport.md index 631b3374e..75512fdf4 100644 --- a/docs/tutorials/hostport.md +++ b/docs/tutorials/hostport.md @@ -50,7 +50,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -65,7 +65,7 @@ rules: resources: ["nodes"] verbs: ["list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/infoblox.md b/docs/tutorials/infoblox.md index f0b95d557..8c3b2bfbd 100644 --- a/docs/tutorials/infoblox.md +++ b/docs/tutorials/infoblox.md @@ -103,7 +103,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -118,7 +118,7 @@ rules: resources: ["nodes"] verbs: ["list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/kube-ingress-aws.md b/docs/tutorials/kube-ingress-aws.md index df63e9829..1b893eb0e 100644 --- a/docs/tutorials/kube-ingress-aws.md +++ b/docs/tutorials/kube-ingress-aws.md @@ -36,7 +36,7 @@ This depends on your RBAC policies, in case you use RBAC, you can use this for all 3 controllers: ```yaml -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: kube-ingress-aws-controller diff --git a/docs/tutorials/linode.md b/docs/tutorials/linode.md index ce975e609..db6d0ff03 100644 --- a/docs/tutorials/linode.md +++ b/docs/tutorials/linode.md @@ -59,7 +59,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -74,7 +74,7 @@ rules: resources: ["nodes"] verbs: ["list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/nginx-ingress.md b/docs/tutorials/nginx-ingress.md index 01e451dcf..842adb44e 100644 --- a/docs/tutorials/nginx-ingress.md +++ b/docs/tutorials/nginx-ingress.md @@ -227,7 +227,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -242,7 +242,7 @@ rules: resources: ["nodes"] verbs: ["list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/ns1.md b/docs/tutorials/ns1.md index 70cd1a1a8..d7eeece86 100644 --- a/docs/tutorials/ns1.md +++ b/docs/tutorials/ns1.md @@ -79,7 +79,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -94,7 +94,7 @@ rules: resources: ["nodes"] verbs: ["list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/openshift.md b/docs/tutorials/openshift.md index b685534fb..c90e029a0 100644 --- a/docs/tutorials/openshift.md +++ b/docs/tutorials/openshift.md @@ -43,7 +43,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -61,7 +61,7 @@ rules: resources: ["routes"] verbs: ["get","watch","list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/oracle.md b/docs/tutorials/oracle.md index 33a65e42a..0d9929648 100644 --- a/docs/tutorials/oracle.md +++ b/docs/tutorials/oracle.md @@ -47,7 +47,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -62,7 +62,7 @@ rules: resources: ["nodes"] verbs: ["list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/ovh.md b/docs/tutorials/ovh.md index a0132ab18..8482c2fa6 100644 --- a/docs/tutorials/ovh.md +++ b/docs/tutorials/ovh.md @@ -108,7 +108,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -129,7 +129,7 @@ rules: resources: ["endpoints"] verbs: ["get","watch","list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/pdns.md b/docs/tutorials/pdns.md index 492e00688..05ec534c6 100644 --- a/docs/tutorials/pdns.md +++ b/docs/tutorials/pdns.md @@ -70,7 +70,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -88,7 +88,7 @@ rules: resources: ["nodes"] verbs: ["list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/rcodezero.md b/docs/tutorials/rcodezero.md index ee669bca7..9cd988af9 100644 --- a/docs/tutorials/rcodezero.md +++ b/docs/tutorials/rcodezero.md @@ -74,7 +74,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -89,7 +89,7 @@ rules: resources: ["nodes"] verbs: ["list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/rdns.md b/docs/tutorials/rdns.md index cb2d2aede..6f57c0ed0 100644 --- a/docs/tutorials/rdns.md +++ b/docs/tutorials/rdns.md @@ -70,7 +70,7 @@ spec: ```yaml --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -85,7 +85,7 @@ rules: resources: ["nodes"] verbs: ["list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/rfc2136.md b/docs/tutorials/rfc2136.md index 05d06d4a5..7117f6bb2 100644 --- a/docs/tutorials/rfc2136.md +++ b/docs/tutorials/rfc2136.md @@ -154,7 +154,7 @@ metadata: labels: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -187,7 +187,7 @@ metadata: name: external-dns namespace: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/scaleway.md b/docs/tutorials/scaleway.md index 9c3c8c8b6..93f39cdd4 100644 --- a/docs/tutorials/scaleway.md +++ b/docs/tutorials/scaleway.md @@ -71,7 +71,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -86,7 +86,7 @@ rules: resources: ["nodes"] verbs: ["list","watch"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/transip.md b/docs/tutorials/transip.md index 62e48e591..56c90b9ed 100644 --- a/docs/tutorials/transip.md +++ b/docs/tutorials/transip.md @@ -61,7 +61,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -76,7 +76,7 @@ rules: resources: ["nodes"] verbs: ["watch", "list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/ultradns.md b/docs/tutorials/ultradns.md index 156f2a068..7b7312553 100644 --- a/docs/tutorials/ultradns.md +++ b/docs/tutorials/ultradns.md @@ -70,7 +70,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -85,7 +85,7 @@ rules: resources: ["nodes"] verbs: ["list","watch"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/vinyldns.md b/docs/tutorials/vinyldns.md index 3720a2594..800d2f86b 100644 --- a/docs/tutorials/vinyldns.md +++ b/docs/tutorials/vinyldns.md @@ -91,7 +91,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -106,7 +106,7 @@ rules: resources: ["nodes"] verbs: ["list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/docs/tutorials/vultr.md b/docs/tutorials/vultr.md index 6ccb7ec22..ca4b606c7 100644 --- a/docs/tutorials/vultr.md +++ b/docs/tutorials/vultr.md @@ -60,7 +60,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -75,7 +75,7 @@ rules: resources: ["nodes"] verbs: ["list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer diff --git a/kustomize/external-dns-clusterrole.yaml b/kustomize/external-dns-clusterrole.yaml index 3c2490aaf..2ca6ceed2 100644 --- a/kustomize/external-dns-clusterrole.yaml +++ b/kustomize/external-dns-clusterrole.yaml @@ -1,4 +1,4 @@ -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns diff --git a/kustomize/external-dns-clusterrolebinding.yaml b/kustomize/external-dns-clusterrolebinding.yaml index 3d08f8059..f50cfba77 100644 --- a/kustomize/external-dns-clusterrolebinding.yaml +++ b/kustomize/external-dns-clusterrolebinding.yaml @@ -1,4 +1,4 @@ -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer From efe799e2156e43d6640067880323049a3f0aa28f Mon Sep 17 00:00:00 2001 From: David Dymko Date: Fri, 4 Jun 2021 16:12:27 -0400 Subject: [PATCH 148/175] update vultr to use API v2 --- go.mod | 4 +- go.sum | 19 ++--- main.go | 2 +- provider/vultr/vultr.go | 155 +++++++++++++++++++---------------- provider/vultr/vultr_test.go | 113 +++++++++++++++---------- 5 files changed, 164 insertions(+), 129 deletions(-) diff --git a/go.mod b/go.mod index 869796480..c38789288 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/fatih/structs v1.1.0 // indirect github.com/ffledgling/pdns-go v0.0.0-20180219074714-524e7daccd99 github.com/golang/sync v0.0.0-20180314180146-1d60e4601c6f - github.com/google/go-cmp v0.4.1 + github.com/google/go-cmp v0.5.2 github.com/gophercloud/gophercloud v0.1.0 github.com/gorilla/mux v1.7.4 // indirect github.com/hooklift/gowsdl v0.4.0 @@ -53,7 +53,7 @@ require ( github.com/transip/gotransip/v6 v6.6.0 github.com/ultradns/ultradns-sdk-go v0.0.0-20200616202852-e62052662f60 github.com/vinyldns/go-vinyldns v0.0.0-20200211145900-fe8a3d82e556 - github.com/vultr/govultr v0.4.2 + github.com/vultr/govultr/v2 v2.5.1 go.etcd.io/etcd v0.5.0-alpha.5.0.20200401174654-e694b7bb0875 go.uber.org/ratelimit v0.1.0 golang.org/x/net v0.0.0-20201224014010-6772e930b67b diff --git a/go.sum b/go.sum index fc43d9554..5b613c00e 100644 --- a/go.sum +++ b/go.sum @@ -390,10 +390,11 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1 h1:/exdXoGamhu5ONeUJH0deniYLWYvQwW66yvlfiiKTu0= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= +github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= @@ -464,8 +465,8 @@ github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1: github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= -github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM= -github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4= +github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= @@ -639,7 +640,6 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/nesv/go-dynect v0.6.0 h1:Ow/DiSm4LAISwnFku/FITSQHnU6pBvhQMsUE5Gu6Oq4= @@ -870,8 +870,8 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= github.com/vinyldns/go-vinyldns v0.0.0-20200211145900-fe8a3d82e556 h1:UbVjBjgJUYGD8MlobEdOR+yTeNqaNa2Gf1/nskVNCSE= github.com/vinyldns/go-vinyldns v0.0.0-20200211145900-fe8a3d82e556/go.mod h1:RWc47jtnVuQv6+lY3c768WtXCas/Xi+U5UFc5xULmYg= -github.com/vultr/govultr v0.4.2 h1:9i8xKZ+xp6vwZ9raqHoBLzhB4wCnMj7nOQTj5YIRLWY= -github.com/vultr/govultr v0.4.2/go.mod h1:TUuUizMOFc7z+PNMssb6iGjKjQfpw5arIaOLfocVudQ= +github.com/vultr/govultr/v2 v2.5.1 h1:Bh3G7nqHs0Gv7OQRExfYFppbuscwVKFDK05b8XBYYnQ= +github.com/vultr/govultr/v2 v2.5.1/go.mod h1:BvOhVe6/ZpjwcoL6/unkdQshmbS9VGbowI4QT+3DGVU= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= @@ -1006,7 +1006,6 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -1064,11 +1063,9 @@ golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/main.go b/main.go index 1a6f7cf65..bc6905956 100644 --- a/main.go +++ b/main.go @@ -207,7 +207,7 @@ func main() { case "vinyldns": p, err = vinyldns.NewVinylDNSProvider(domainFilter, zoneIDFilter, cfg.DryRun) case "vultr": - p, err = vultr.NewVultrProvider(domainFilter, cfg.DryRun) + p, err = vultr.NewVultrProvider(ctx, domainFilter, cfg.DryRun) case "ultradns": p, err = ultradns.NewUltraDNSProvider(domainFilter, cfg.DryRun) case "cloudflare": diff --git a/provider/vultr/vultr.go b/provider/vultr/vultr.go index 8f25367d5..e9d5187c2 100644 --- a/provider/vultr/vultr.go +++ b/provider/vultr/vultr.go @@ -20,11 +20,11 @@ import ( "context" "fmt" "os" - "strconv" "strings" log "github.com/sirupsen/logrus" - "github.com/vultr/govultr" + "github.com/vultr/govultr/v2" + "golang.org/x/oauth2" "sigs.k8s.io/external-dns/endpoint" "sigs.k8s.io/external-dns/plan" @@ -51,30 +51,33 @@ type VultrProvider struct { type VultrChanges struct { Action string - ResourceRecordSet govultr.DNSRecord + ResourceRecordSet *govultr.DomainRecordReq } // NewVultrProvider initializes a new Vultr BNS based provider -func NewVultrProvider(domainFilter endpoint.DomainFilter, dryRun bool) (*VultrProvider, error) { +func NewVultrProvider(ctx context.Context, domainFilter endpoint.DomainFilter, dryRun bool) (*VultrProvider, error) { apiKey, ok := os.LookupEnv("VULTR_API_KEY") if !ok { return nil, fmt.Errorf("no token found") } - client := govultr.NewClient(nil, apiKey) + oauthClient := oauth2.NewClient(ctx, oauth2.StaticTokenSource(&oauth2.Token{ + AccessToken: apiKey, + })) + client := govultr.NewClient(oauthClient) client.SetUserAgent(fmt.Sprintf("ExternalDNS/%s", client.UserAgent)) - provider := &VultrProvider{ + p := &VultrProvider{ client: *client, domainFilter: domainFilter, DryRun: dryRun, } - return provider, nil + return p, nil } // Zones returns list of hosted zones -func (p *VultrProvider) Zones(ctx context.Context) ([]govultr.DNSDomain, error) { +func (p *VultrProvider) Zones(ctx context.Context) ([]govultr.Domain, error) { zones, err := p.fetchZones(ctx) if err != nil { return nil, err @@ -108,34 +111,58 @@ func (p *VultrProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, erro name = zone.Domain } - endPointTTL := endpoint.NewEndpointWithTTL(name, r.Type, endpoint.TTL(r.TTL), r.Data) - endpoints = append(endpoints, endPointTTL) + endpoints = append(endpoints, endpoint.NewEndpointWithTTL(name, r.Type, endpoint.TTL(r.TTL), r.Data)) } } } + return endpoints, nil } -func (p *VultrProvider) fetchRecords(ctx context.Context, domain string) ([]govultr.DNSRecord, error) { - records, err := p.client.DNSRecord.List(ctx, domain) - if err != nil { - return nil, err +func (p *VultrProvider) fetchRecords(ctx context.Context, domain string) ([]govultr.DomainRecord, error) { + var allRecords []govultr.DomainRecord + listOptions := &govultr.ListOptions{} + + for { + records, meta, err := p.client.DomainRecord.List(ctx, domain, listOptions) + if err != nil { + return nil, err + } + + allRecords = append(allRecords, records...) + + if meta.Links.Next == "" { + break + } else { + listOptions.Cursor = meta.Links.Next + continue + } } - return records, nil + return allRecords, nil } -func (p *VultrProvider) fetchZones(ctx context.Context) ([]govultr.DNSDomain, error) { - var zones []govultr.DNSDomain +func (p *VultrProvider) fetchZones(ctx context.Context) ([]govultr.Domain, error) { + var zones []govultr.Domain + listOptions := &govultr.ListOptions{} - allZones, err := p.client.DNSDomain.List(ctx) - if err != nil { - return nil, err - } + for { + allZones, meta, err := p.client.Domain.List(ctx, listOptions) + if err != nil { + return nil, err + } - for _, zone := range allZones { - if p.domainFilter.Match(zone.Domain) { - zones = append(zones, zone) + for _, zone := range allZones { + if p.domainFilter.Match(zone.Domain) { + zones = append(zones, zone) + } + } + + if meta.Links.Next == "" { + break + } else { + listOptions.Cursor = meta.Links.Next + continue } } @@ -153,24 +180,21 @@ func (p *VultrProvider) submitChanges(ctx context.Context, changes []*VultrChang return err } - zoneChanges := seperateChangesByZone(zones, changes) + zoneChanges := separateChangesByZone(zones, changes) for zoneName, changes := range zoneChanges { for _, change := range changes { log.WithFields(log.Fields{ - "record": change.ResourceRecordSet.Name, - "type": change.ResourceRecordSet.Type, - "ttl": change.ResourceRecordSet.TTL, - "priority": change.ResourceRecordSet.Priority, - "action": change.Action, - "zone": zoneName, + "record": change.ResourceRecordSet.Name, + "type": change.ResourceRecordSet.Type, + "ttl": change.ResourceRecordSet.TTL, + "action": change.Action, + "zone": zoneName, }).Info("Changing record.") switch change.Action { case vultrCreate: - priority := getPriority(change.ResourceRecordSet.Priority) - err = p.client.DNSRecord.Create(ctx, zoneName, change.ResourceRecordSet.Type, change.ResourceRecordSet.Name, change.ResourceRecordSet.Data, change.ResourceRecordSet.TTL, priority) - if err != nil { + if _, err := p.client.DomainRecord.Create(ctx, zoneName, change.ResourceRecordSet); err != nil { return err } case vultrDelete: @@ -179,8 +203,7 @@ func (p *VultrProvider) submitChanges(ctx context.Context, changes []*VultrChang return err } - err = p.client.DNSRecord.Delete(ctx, zoneName, strconv.Itoa(id)) - if err != nil { + if err := p.client.DomainRecord.Delete(ctx, zoneName, id); err != nil { return err } case vultrUpdate: @@ -188,17 +211,7 @@ func (p *VultrProvider) submitChanges(ctx context.Context, changes []*VultrChang if err != nil { return err } - - record := &govultr.DNSRecord{ - RecordID: id, - Type: change.ResourceRecordSet.Type, - Name: change.ResourceRecordSet.Name, - Data: change.ResourceRecordSet.Data, - TTL: change.ResourceRecordSet.TTL, - } - - err = p.client.DNSRecord.Update(ctx, zoneName, record) - if err != nil { + if err := p.client.DomainRecord.Update(ctx, zoneName, id, change.ResourceRecordSet); err != nil { return err } } @@ -228,19 +241,20 @@ func newVultrChanges(action string, endpoints []*endpoint.Endpoint) []*VultrChan change := &VultrChanges{ Action: action, - ResourceRecordSet: govultr.DNSRecord{ + ResourceRecordSet: &govultr.DomainRecordReq{ Type: e.RecordType, Name: e.DNSName, Data: e.Targets[0], TTL: ttl, }, } + changes = append(changes, change) } return changes } -func seperateChangesByZone(zones []govultr.DNSDomain, changes []*VultrChanges) map[string][]*VultrChanges { +func separateChangesByZone(zones []govultr.Domain, changes []*VultrChanges) map[string][]*VultrChanges { change := make(map[string][]*VultrChanges) zoneNameID := provider.ZoneIDName{} @@ -260,30 +274,31 @@ func seperateChangesByZone(zones []govultr.DNSDomain, changes []*VultrChanges) m return change } -func (p *VultrProvider) getRecordID(ctx context.Context, zone string, record govultr.DNSRecord) (recordID int, err error) { - records, err := p.client.DNSRecord.List(ctx, zone) - if err != nil { - return 0, err - } - - for _, r := range records { - strippedName := strings.TrimSuffix(record.Name, "."+zone) - if record.Name == zone { - strippedName = "" +func (p *VultrProvider) getRecordID(ctx context.Context, zone string, record *govultr.DomainRecordReq) (recordID string, err error) { + listOptions := &govultr.ListOptions{} + for { + records, meta, err := p.client.DomainRecord.List(ctx, zone, listOptions) + if err != nil { + return "0", err } - if r.Name == strippedName && r.Type == record.Type { - return r.RecordID, nil + for _, r := range records { + strippedName := strings.TrimSuffix(record.Name, "."+zone) + if record.Name == zone { + strippedName = "" + } + + if r.Name == strippedName && r.Type == record.Type { + return r.ID, nil + } + } + if meta.Links.Next == "" { + break + } else { + listOptions.Cursor = meta.Links.Next + continue } } - return 0, fmt.Errorf("no record was found") -} - -func getPriority(priority *int) int { - p := 0 - if priority != nil { - p = *priority - } - return p + return "", fmt.Errorf("no record was found") } diff --git a/provider/vultr/vultr_test.go b/provider/vultr/vultr_test.go index 6487657b6..38bf05ba7 100644 --- a/provider/vultr/vultr_test.go +++ b/provider/vultr/vultr_test.go @@ -24,7 +24,8 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/vultr/govultr" + "github.com/vultr/govultr/v2" + "sigs.k8s.io/external-dns/endpoint" "sigs.k8s.io/external-dns/plan" ) @@ -33,63 +34,84 @@ type mockVultrDomain struct { client *govultr.Client } -func (m *mockVultrDomain) Create(ctx context.Context, domain, InstanceIP string) error { - return nil -} - -func (m *mockVultrDomain) Delete(ctx context.Context, domain string) error { - return nil -} - -func (m *mockVultrDomain) ToggleDNSSec(ctx context.Context, domain string, enabled bool) error { - return nil -} - -func (m *mockVultrDomain) DNSSecInfo(ctx context.Context, domain string) ([]string, error) { +func (m mockVultrDomain) Create(ctx context.Context, domainReq *govultr.DomainReq) (*govultr.Domain, error) { return nil, nil } -func (m *mockVultrDomain) List(ctx context.Context) ([]govultr.DNSDomain, error) { - return []govultr.DNSDomain{{Domain: "test.com"}}, nil -} - -func (m *mockVultrDomain) GetSoa(ctx context.Context, domain string) (*govultr.Soa, error) { +func (m mockVultrDomain) Get(ctx context.Context, domain string) (*govultr.Domain, error) { return nil, nil } -func (m *mockVultrDomain) UpdateSoa(ctx context.Context, domain, nsPrimary, email string) error { +func (m mockVultrDomain) Update(ctx context.Context, domain, dnsSec string) error { return nil } +func (m mockVultrDomain) Delete(ctx context.Context, domain string) error { + return nil +} + +func (m mockVultrDomain) List(ctx context.Context, options *govultr.ListOptions) ([]govultr.Domain, *govultr.Meta, error) { + return []govultr.Domain{{Domain: "test.com", DateCreated: "1234"}}, &govultr.Meta{ + Total: 1, + Links: &govultr.Links{ + Next: "", + Prev: "", + }, + }, nil +} + +func (m mockVultrDomain) GetSoa(ctx context.Context, domain string) (*govultr.Soa, error) { + return nil, nil +} + +func (m mockVultrDomain) UpdateSoa(ctx context.Context, domain string, soaReq *govultr.Soa) error { + return nil +} + +func (m mockVultrDomain) GetDNSSec(ctx context.Context, domain string) ([]string, error) { + return nil, nil +} + + type mockVultrRecord struct { client *govultr.Client } -func (m *mockVultrRecord) Create(ctx context.Context, domain, recordType, name, data string, ttl, priority int) error { +func (m mockVultrRecord) Create(ctx context.Context, domain string, domainRecordReq *govultr.DomainRecordReq) (*govultr.DomainRecord, error) { + return nil, nil +} + +func (m mockVultrRecord) Get(ctx context.Context, domain, recordID string) (*govultr.DomainRecord, error) { + return nil, nil +} + +func (m mockVultrRecord) Update(ctx context.Context, domain, recordID string, domainRecordReq *govultr.DomainRecordReq) error { return nil } -func (m *mockVultrRecord) Delete(ctx context.Context, domain, recordID string) error { +func (m mockVultrRecord) Delete(ctx context.Context, domain, recordID string) error { return nil } -func (m *mockVultrRecord) List(ctx context.Context, domain string) ([]govultr.DNSRecord, error) { - return []govultr.DNSRecord{{RecordID: 123, Type: "A", Name: "test", Data: "192.168.1.1", TTL: 300}}, nil -} - -func (m *mockVultrRecord) Update(ctx context.Context, domain string, dnsRecord *govultr.DNSRecord) error { - return nil +func (m mockVultrRecord) List(ctx context.Context, domain string, options *govultr.ListOptions) ([]govultr.DomainRecord, *govultr.Meta, error) { + return []govultr.DomainRecord{{ID: "123", Type: "A", Name: "test", Data: "192.168.1.1", TTL: 300}}, &govultr.Meta{ + Total: 1, + Links: &govultr.Links{ + Next: "", + Prev: "", + }, + }, nil } func TestNewVultrProvider(t *testing.T) { _ = os.Setenv("VULTR_API_KEY", "") - _, err := NewVultrProvider(endpoint.NewDomainFilter([]string{"test.vultr.com"}), true) + _, err := NewVultrProvider(context.Background(), endpoint.NewDomainFilter([]string{"test.vultr.com"}), true) if err != nil { t.Errorf("failed : %s", err) } _ = os.Unsetenv("VULTR_API_KEY") - _, err = NewVultrProvider(endpoint.NewDomainFilter([]string{"test.vultr.com"}), true) + _, err = NewVultrProvider(context.Background(), endpoint.NewDomainFilter([]string{"test.vultr.com"}), true) if err == nil { t.Errorf("expected to fail") } @@ -99,18 +121,21 @@ func TestVultrProvider_Zones(t *testing.T) { mocked := mockVultrDomain{nil} provider := &VultrProvider{ client: govultr.Client{ - DNSDomain: &mocked, + Domain: &mocked, }, } - expected, err := provider.client.DNSDomain.List(context.Background()) + expected, _, err := provider.client.Domain.List(context.Background(), nil) if err != nil { t.Fatal(err) } + + provider.Zones(context.Background()) zones, err := provider.Zones(context.Background()) if err != nil { t.Fatal(err) } + if !reflect.DeepEqual(expected, zones) { t.Fatal(err) } @@ -122,12 +147,12 @@ func TestVultrProvider_Records(t *testing.T) { provider := &VultrProvider{ client: govultr.Client{ - DNSRecord: &mocked, - DNSDomain: &mockedDomain, + DomainRecord: &mocked, + Domain: &mockedDomain, }, } - expected, _ := provider.client.DNSRecord.List(context.Background(), "test.com") + expected, _, _ := provider.client.DomainRecord.List(context.Background(), "test.com", nil) records, err := provider.Records(context.Background()) if err != nil { t.Fatal(err) @@ -138,7 +163,6 @@ func TestVultrProvider_Records(t *testing.T) { assert.Equal(t, v.RecordType, expected[0].Type) assert.Equal(t, int(v.RecordTTL), expected[0].TTL) } - } func TestVultrProvider_ApplyChanges(t *testing.T) { @@ -148,8 +172,8 @@ func TestVultrProvider_ApplyChanges(t *testing.T) { provider := &VultrProvider{ client: govultr.Client{ - DNSRecord: &mocked, - DNSDomain: &mockedDomain, + DomainRecord: &mocked, + Domain: &mockedDomain, }, } @@ -172,20 +196,19 @@ func TestVultrProvider_getRecordID(t *testing.T) { provider := &VultrProvider{ client: govultr.Client{ - DNSRecord: &mocked, - DNSDomain: &mockedDomain, + DomainRecord: &mocked, + Domain: &mockedDomain, }, } - record := govultr.DNSRecord{ - RecordID: 123, - Type: "A", - Name: "test.test.com", + record := &govultr.DomainRecordReq{ + Type: "A", + Name: "test.test.com", } id, err := provider.getRecordID(context.Background(), "test.com", record) if err != nil { t.Fatal(err) } - assert.Equal(t, id, record.RecordID) + assert.Equal(t, id, "123") } From 6ce7374fb854acd448a5b477a5a37478c30cbbb7 Mon Sep 17 00:00:00 2001 From: aSauerwein Date: Wed, 9 Jun 2021 10:32:05 +0200 Subject: [PATCH 149/175] Update docs/tutorials/rfc2136.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nick Jüttner --- docs/tutorials/rfc2136.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/rfc2136.md b/docs/tutorials/rfc2136.md index 6289c5028..bc60b03df 100644 --- a/docs/tutorials/rfc2136.md +++ b/docs/tutorials/rfc2136.md @@ -380,7 +380,7 @@ You'll want to configure `external-dns` similarly to the following: ```text ... - --provider=rfc2136 - - --rfc2136-gss-tsig + - --rfc2136-gss-tsig - --rfc2136-host=dns-host.yourdomain.com - --rfc2136-port=53 - --rfc2136-zone=your-zone.com From 450e8b64441b8a2c49ed812b7d722e344e4bbd2d Mon Sep 17 00:00:00 2001 From: Kyle Polansky Date: Thu, 17 Jun 2021 21:14:14 -0500 Subject: [PATCH 150/175] Update azure-private-dns tutorial image tag to v0.8.0 --- docs/tutorials/azure-private-dns.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/tutorials/azure-private-dns.md b/docs/tutorials/azure-private-dns.md index a607da9bf..fc515e9bb 100644 --- a/docs/tutorials/azure-private-dns.md +++ b/docs/tutorials/azure-private-dns.md @@ -171,7 +171,7 @@ spec: spec: containers: - name: externaldns - image: k8s.gcr.io/external-dns/external-dns:v0.7.6 + image: k8s.gcr.io/external-dns/external-dns:v0.8.0 args: - --source=service - --source=ingress @@ -242,7 +242,7 @@ spec: serviceAccountName: externaldns containers: - name: externaldns - image: k8s.gcr.io/external-dns/external-dns:v0.7.6 + image: k8s.gcr.io/external-dns/external-dns:v0.8.0 args: - --source=service - --source=ingress @@ -313,7 +313,7 @@ spec: serviceAccountName: externaldns containers: - name: externaldns - image: k8s.gcr.io/external-dns/external-dns:v0.7.6 + image: k8s.gcr.io/external-dns/external-dns:v0.8.0 args: - --source=service - --source=ingress From 2dc706bfb423688c6d4810ac021413c9cc9bfcaf Mon Sep 17 00:00:00 2001 From: Roeland van Batenburg Date: Fri, 18 Jun 2021 15:47:04 +0200 Subject: [PATCH 151/175] update for latest version --- docs/tutorials/gke.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/gke.md b/docs/tutorials/gke.md index 83db6c1eb..3cce864e3 100644 --- a/docs/tutorials/gke.md +++ b/docs/tutorials/gke.md @@ -116,7 +116,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.6 + image: k8s.gcr.io/external-dns/external-dns:v0.8.0 args: - --source=service - --source=ingress From 4a107529c552e58afd4bcb3233b33f21dedacf4f Mon Sep 17 00:00:00 2001 From: Roeland van Batenburg Date: Fri, 18 Jun 2021 16:31:54 +0200 Subject: [PATCH 152/175] replace all occurrences --- docs/tutorials/gke.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/gke.md b/docs/tutorials/gke.md index 3cce864e3..8c452cbd2 100644 --- a/docs/tutorials/gke.md +++ b/docs/tutorials/gke.md @@ -439,7 +439,7 @@ spec: - --google-project=zalando-external-dns-test - --registry=txt - --txt-owner-id=my-identifier - image: k8s.gcr.io/external-dns/external-dns:v0.7.6 + image: k8s.gcr.io/external-dns/external-dns:v0.8.0 name: external-dns securityContext: fsGroup: 65534 From 7a16ab46fa9cf714de1ef7de3180f76f81c53ba8 Mon Sep 17 00:00:00 2001 From: Ole Markus With Date: Wed, 31 Mar 2021 15:45:35 +0200 Subject: [PATCH 153/175] Add support for dns-controller compat mode for services --- pkg/apis/externaldns/types.go | 2 +- source/compatibility.go | 116 ++++++++++++++- source/service.go | 5 +- source/service_test.go | 261 +++++++++++++++++++++++++++++++++- 4 files changed, 376 insertions(+), 8 deletions(-) diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 8655dc480..6713d3f13 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -356,7 +356,7 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("combine-fqdn-annotation", "Combine FQDN template and Annotations instead of overwriting").BoolVar(&cfg.CombineFQDNAndAnnotation) app.Flag("ignore-hostname-annotation", "Ignore hostname annotation when generating DNS names, valid only when using fqdn-template is set (optional, default: false)").BoolVar(&cfg.IgnoreHostnameAnnotation) app.Flag("ignore-ingress-tls-spec", "Ignore tls spec section in ingresses resources, applicable only for ingress sources (optional, default: false)").BoolVar(&cfg.IgnoreIngressTLSSpec) - app.Flag("compatibility", "Process annotation semantics from legacy implementations (optional, options: mate, molecule)").Default(defaultConfig.Compatibility).EnumVar(&cfg.Compatibility, "", "mate", "molecule") + app.Flag("compatibility", "Process annotation semantics from legacy implementations (optional, options: mate, molecule)").Default(defaultConfig.Compatibility).EnumVar(&cfg.Compatibility, "", "mate", "molecule", "dns-controller") app.Flag("publish-internal-services", "Allow external-dns to publish DNS records for ClusterIP services (optional)").BoolVar(&cfg.PublishInternal) app.Flag("publish-host-ip", "Allow external-dns to publish host-ip for headless services (optional)").BoolVar(&cfg.PublishHostIP) app.Flag("always-publish-not-ready-addresses", "Always publish also not ready addresses for headless services (optional)").BoolVar(&cfg.AlwaysPublishNotReadyAddresses) diff --git a/source/compatibility.go b/source/compatibility.go index aa86c1c3f..ff7f7d8f5 100644 --- a/source/compatibility.go +++ b/source/compatibility.go @@ -20,6 +20,7 @@ import ( "strings" v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" "sigs.k8s.io/external-dns/endpoint" ) @@ -27,19 +28,25 @@ import ( const ( mateAnnotationKey = "zalando.org/dnsname" moleculeAnnotationKey = "domainName" + // dnsControllerHostnameAnnotationKey is the annotation used for defining the desired hostname when DNS controller compatibility mode + dnsControllerHostnameAnnotationKey = "dns.alpha.kubernetes.io/external" + // dnsControllerInternalHostnameAnnotationKey is the annotation used for defining the desired hostname when DNS controller compatibility mode + dnsControllerInternalHostnameAnnotationKey = "dns.alpha.kubernetes.io/internal" ) // legacyEndpointsFromService tries to retrieve Endpoints from Services // annotated with legacy annotations. -func legacyEndpointsFromService(svc *v1.Service, compatibility string) []*endpoint.Endpoint { - switch compatibility { +func legacyEndpointsFromService(svc *v1.Service, sc *serviceSource) ([]*endpoint.Endpoint, error) { + switch sc.compatibility { case "mate": - return legacyEndpointsFromMateService(svc) + return legacyEndpointsFromMateService(svc), nil case "molecule": - return legacyEndpointsFromMoleculeService(svc) + return legacyEndpointsFromMoleculeService(svc), nil + case "dns-controller": + return legacyEndpointsFromDNSControllerService(svc, sc) } - return []*endpoint.Endpoint{} + return []*endpoint.Endpoint{}, nil } // legacyEndpointsFromMateService tries to retrieve Endpoints from Services @@ -98,3 +105,102 @@ func legacyEndpointsFromMoleculeService(svc *v1.Service) []*endpoint.Endpoint { return endpoints } + +// legacyEndpointsFromDNSControllerService tries to retrieve Endpoints from Services +// annotated with DNS Controller's annotation semantics*. +func legacyEndpointsFromDNSControllerService(svc *v1.Service, sc *serviceSource) ([]*endpoint.Endpoint, error) { + switch svc.Spec.Type { + case v1.ServiceTypeNodePort: + return legacyEndpointsFromDNSControllerNodePortService(svc, sc) + case v1.ServiceTypeLoadBalancer: + return legacyEndpointsFromDNSControllerLoadBalancerService(svc), nil + } + + return []*endpoint.Endpoint{}, nil +} + +// legacyEndpointsFromDNSControllerNodePortService implements DNS controller's semantics for NodePort services. +// It will use node role label to check if the node has the "node" role. This means control plane nodes and other +// roles will not be used as targets. +func legacyEndpointsFromDNSControllerNodePortService(svc *v1.Service, sc *serviceSource) ([]*endpoint.Endpoint, error) { + var endpoints []*endpoint.Endpoint + + // Get the desired hostname of the service from the annotations. + hostnameAnnotation, isExternal := svc.Annotations[dnsControllerHostnameAnnotationKey] + internalHostnameAnnotation, isInternal := svc.Annotations[dnsControllerInternalHostnameAnnotationKey] + + if !isExternal && !isInternal { + return nil, nil + } + + // if both annotations are set, we just return empty, mimicking what dns-controller does + if isInternal && isExternal { + return nil, nil + } + + nodes, err := sc.nodeInformer.Lister().List(labels.Everything()) + if err != nil { + return nil, err + } + + var hostnameList []string + if isExternal { + hostnameList = strings.Split(strings.Replace(hostnameAnnotation, " ", "", -1), ",") + } else { + hostnameList = strings.Split(strings.Replace(internalHostnameAnnotation, " ", "", -1), ",") + } + + for _, hostname := range hostnameList { + for _, node := range nodes { + _, isNode := node.Labels["node-role.kubernetes.io/node"] + if !isNode { + continue + } + for _, address := range node.Status.Addresses { + if address.Type == v1.NodeExternalIP && isExternal { + endpoints = append(endpoints, endpoint.NewEndpoint(hostname, endpoint.RecordTypeA, address.Address)) + } + if address.Type == v1.NodeInternalIP && isInternal { + endpoints = append(endpoints, endpoint.NewEndpoint(hostname, endpoint.RecordTypeA, address.Address)) + } + } + } + } + return endpoints, nil +} + +// legacyEndpointsFromDNSControllerLoadBalancerService will respect both annotations, but +// will not care if the load balancer actually is internal or not. +func legacyEndpointsFromDNSControllerLoadBalancerService(svc *v1.Service) []*endpoint.Endpoint { + var endpoints []*endpoint.Endpoint + + // Get the desired hostname of the service from the annotations. + hostnameAnnotation, hasExternal := svc.Annotations[dnsControllerHostnameAnnotationKey] + internalHostnameAnnotation, hasInternal := svc.Annotations[dnsControllerInternalHostnameAnnotationKey] + + if !hasExternal && !hasInternal { + return nil + } + + var hostnameList []string + if hasExternal { + hostnameList = append(hostnameList, strings.Split(strings.Replace(hostnameAnnotation, " ", "", -1), ",")...) + } + if hasInternal { + hostnameList = append(hostnameList, strings.Split(strings.Replace(internalHostnameAnnotation, " ", "", -1), ",")...) + } + + for _, hostname := range hostnameList { + // Create a corresponding endpoint for each configured external entrypoint. + for _, lb := range svc.Status.LoadBalancer.Ingress { + if lb.IP != "" { + endpoints = append(endpoints, endpoint.NewEndpoint(hostname, endpoint.RecordTypeA, lb.IP)) + } + if lb.Hostname != "" { + endpoints = append(endpoints, endpoint.NewEndpoint(hostname, endpoint.RecordTypeCNAME, lb.Hostname)) + } + } + } + + return endpoints +} diff --git a/source/service.go b/source/service.go index aeb9c8661..a6d258311 100644 --- a/source/service.go +++ b/source/service.go @@ -187,7 +187,10 @@ func (sc *serviceSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, e // process legacy annotations if no endpoints were returned and compatibility mode is enabled. if len(svcEndpoints) == 0 && sc.compatibility != "" { - svcEndpoints = legacyEndpointsFromService(svc, sc.compatibility) + svcEndpoints, err = legacyEndpointsFromService(svc, sc) + if err != nil { + return nil, err + } } // apply template if none of the above is found diff --git a/source/service_test.go b/source/service_test.go index d69b88a73..2c004c543 100644 --- a/source/service_test.go +++ b/source/service_test.go @@ -868,6 +868,59 @@ func testServiceSourceEndpoints(t *testing.T) { }, false, }, + { + "load balancer services annotated with DNS Controller annotations return an endpoint with A and CNAME targets in compatibility mode", + "", + "", + "testing", + "foo", + v1.ServiceTypeLoadBalancer, + "dns-controller", + "", + false, + false, + map[string]string{}, + map[string]string{ + dnsControllerInternalHostnameAnnotationKey: "internal.foo.example.org", + }, + "", + []string{}, + []string{"1.2.3.4", "lb.example.com"}, + []string{}, + []*endpoint.Endpoint{ + {DNSName: "internal.foo.example.org", Targets: endpoint.Targets{"1.2.3.4"}}, + {DNSName: "internal.foo.example.org", Targets: endpoint.Targets{"lb.example.com"}}, + }, + false, + }, { + "load balancer services annotated with DNS Controller annotations return an endpoint with both annotations in compatibility mode", + "", + "", + "testing", + "foo", + v1.ServiceTypeLoadBalancer, + "dns-controller", + "", + false, + false, + map[string]string{}, + map[string]string{ + dnsControllerInternalHostnameAnnotationKey: "internal.foo.example.org., internal.bar.example.org", + dnsControllerHostnameAnnotationKey: "foo.example.org., bar.example.org", + }, + "", + []string{}, + []string{"1.2.3.4"}, + []string{}, + []*endpoint.Endpoint{ + {DNSName: "foo.example.org", Targets: endpoint.Targets{"1.2.3.4"}}, + {DNSName: "bar.example.org", Targets: endpoint.Targets{"1.2.3.4"}}, + {DNSName: "internal.foo.example.org", Targets: endpoint.Targets{"1.2.3.4"}}, + {DNSName: "internal.bar.example.org", Targets: endpoint.Targets{"1.2.3.4"}}, + }, + false, + }, + { "not annotated services with set fqdnTemplate return an endpoint with target IP", "", @@ -1603,7 +1656,7 @@ func TestClusterIpServices(t *testing.T) { } // testNodePortServices tests that various services generate the correct endpoints. -func TestNodePortServices(t *testing.T) { +func TestServiceSourceNodePortServices(t *testing.T) { for _, tc := range []struct { title string targetNamespace string @@ -1988,6 +2041,212 @@ func TestNodePortServices(t *testing.T) { []int{}, []v1.PodPhase{}, }, + { + "node port services annotated DNS Controller annotations return an endpoint where all targets has the node role", + "", + "", + "testing", + "foo", + v1.ServiceTypeNodePort, + v1.ServiceExternalTrafficPolicyTypeCluster, + "dns-controller", + "", + false, + map[string]string{}, + map[string]string{ + dnsControllerInternalHostnameAnnotationKey: "internal.foo.example.org., internal.bar.example.org", + }, + nil, + []*endpoint.Endpoint{ + {DNSName: "internal.foo.example.org", Targets: endpoint.Targets{"10.0.1.1"}}, + {DNSName: "internal.bar.example.org", Targets: endpoint.Targets{"10.0.1.1"}}, + }, + false, + []*v1.Node{{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node1", + Labels: map[string]string{ + "node-role.kubernetes.io/node": "", + }, + }, + Status: v1.NodeStatus{ + Addresses: []v1.NodeAddress{ + {Type: v1.NodeExternalIP, Address: "54.10.11.1"}, + {Type: v1.NodeInternalIP, Address: "10.0.1.1"}, + }, + }, + }, { + ObjectMeta: metav1.ObjectMeta{ + Name: "node2", + Labels: map[string]string{ + "node-role.kubernetes.io/control-plane": "", + }, + }, + Status: v1.NodeStatus{ + Addresses: []v1.NodeAddress{ + {Type: v1.NodeExternalIP, Address: "54.10.11.2"}, + {Type: v1.NodeInternalIP, Address: "10.0.1.2"}, + }, + }, + }}, + []string{}, + []int{}, + []v1.PodPhase{}, + }, + { + "node port services annotated with internal DNS Controller annotations return an endpoint in compatibility mode", + "", + "", + "testing", + "foo", + v1.ServiceTypeNodePort, + v1.ServiceExternalTrafficPolicyTypeCluster, + "dns-controller", + "", + false, + map[string]string{}, + map[string]string{ + dnsControllerInternalHostnameAnnotationKey: "internal.foo.example.org., internal.bar.example.org", + }, + nil, + []*endpoint.Endpoint{ + {DNSName: "internal.foo.example.org", Targets: endpoint.Targets{"10.0.1.1", "10.0.1.2"}}, + {DNSName: "internal.bar.example.org", Targets: endpoint.Targets{"10.0.1.1", "10.0.1.2"}}, + }, + false, + []*v1.Node{{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node1", + Labels: map[string]string{ + "node-role.kubernetes.io/node": "", + }, + }, + Status: v1.NodeStatus{ + Addresses: []v1.NodeAddress{ + {Type: v1.NodeExternalIP, Address: "54.10.11.1"}, + {Type: v1.NodeInternalIP, Address: "10.0.1.1"}, + }, + }, + }, { + ObjectMeta: metav1.ObjectMeta{ + Name: "node2", + Labels: map[string]string{ + "node-role.kubernetes.io/node": "", + }, + }, + Status: v1.NodeStatus{ + Addresses: []v1.NodeAddress{ + {Type: v1.NodeExternalIP, Address: "54.10.11.2"}, + {Type: v1.NodeInternalIP, Address: "10.0.1.2"}, + }, + }, + }}, + []string{}, + []int{}, + []v1.PodPhase{}, + }, + { + "node port services annotated with external DNS Controller annotations return an endpoint in compatibility mode", + "", + "", + "testing", + "foo", + v1.ServiceTypeNodePort, + v1.ServiceExternalTrafficPolicyTypeCluster, + "dns-controller", + "", + false, + map[string]string{}, + map[string]string{ + dnsControllerHostnameAnnotationKey: "foo.example.org., bar.example.org", + }, + nil, + []*endpoint.Endpoint{ + {DNSName: "foo.example.org", Targets: endpoint.Targets{"54.10.11.1", "54.10.11.2"}}, + {DNSName: "bar.example.org", Targets: endpoint.Targets{"54.10.11.1", "54.10.11.2"}}, + }, + false, + []*v1.Node{{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node1", + Labels: map[string]string{ + "node-role.kubernetes.io/node": "", + }, + }, + Status: v1.NodeStatus{ + Addresses: []v1.NodeAddress{ + {Type: v1.NodeExternalIP, Address: "54.10.11.1"}, + {Type: v1.NodeInternalIP, Address: "10.0.1.1"}, + }, + }, + }, { + ObjectMeta: metav1.ObjectMeta{ + Name: "node2", + Labels: map[string]string{ + "node-role.kubernetes.io/node": "", + }, + }, + Status: v1.NodeStatus{ + Addresses: []v1.NodeAddress{ + {Type: v1.NodeExternalIP, Address: "54.10.11.2"}, + {Type: v1.NodeInternalIP, Address: "10.0.1.2"}, + }, + }, + }}, + []string{}, + []int{}, + []v1.PodPhase{}, + }, + { + "node port services annotated with both dns-controller annotations return an empty set of addons", + "", + "", + "testing", + "foo", + v1.ServiceTypeNodePort, + v1.ServiceExternalTrafficPolicyTypeCluster, + "dns-controller", + "", + false, + map[string]string{}, + map[string]string{ + dnsControllerInternalHostnameAnnotationKey: "internal.foo.example.org., internal.bar.example.org", + dnsControllerHostnameAnnotationKey: "foo.example.org., bar.example.org", + }, + nil, + []*endpoint.Endpoint{}, + false, + []*v1.Node{{ + ObjectMeta: metav1.ObjectMeta{ + Name: "node1", + Labels: map[string]string{ + "node-role.kubernetes.io/node": "", + }, + }, + Status: v1.NodeStatus{ + Addresses: []v1.NodeAddress{ + {Type: v1.NodeExternalIP, Address: "54.10.11.1"}, + {Type: v1.NodeInternalIP, Address: "10.0.1.1"}, + }, + }, + }, { + ObjectMeta: metav1.ObjectMeta{ + Name: "node2", + Labels: map[string]string{ + "node-role.kubernetes.io/node": "", + }, + }, + Status: v1.NodeStatus{ + Addresses: []v1.NodeAddress{ + {Type: v1.NodeExternalIP, Address: "54.10.11.2"}, + {Type: v1.NodeInternalIP, Address: "10.0.1.2"}, + }, + }, + }}, + []string{}, + []int{}, + []v1.PodPhase{}, + }, } { t.Run(tc.title, func(t *testing.T) { // Create a Kubernetes testing client From 73469a0852c3f518de5fc8a2e4d3e4c3329d454c Mon Sep 17 00:00:00 2001 From: Ole Markus With Date: Fri, 2 Apr 2021 12:12:58 +0200 Subject: [PATCH 154/175] Support dns-controller compat mode for pod source --- README.md | 2 +- source/pod.go | 42 +++++++++++++++++++------ source/pod_test.go | 77 +++++++++++++++++++++++++++++++++++++++++++++- source/store.go | 2 +- 4 files changed, 111 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 46cf77756..e4e38073e 100644 --- a/README.md +++ b/README.md @@ -284,7 +284,7 @@ Here's a rough outline on what is to come (subject to change): - [ ] Ability to replace Kops' [DNS Controller](https://github.com/kubernetes/kops/tree/HEAD/dns-controller) - [x] Add support for pod source - - [ ] Add support for DNS Controller annotations for pod, ingress, and service sources + - [x] Add support for DNS Controller annotations for pod and service sources - [ ] Add support for kOps gossip provider - [x] Ability to replace Zalando's [Mate](https://github.com/linki/mate) - [x] Ability to replace Molecule Software's [route53-kubernetes](https://github.com/wearemolecule/route53-kubernetes) diff --git a/source/pod.go b/source/pod.go index ed0bb9ceb..f3ddf17dc 100644 --- a/source/pod.go +++ b/source/pod.go @@ -34,14 +34,15 @@ import ( ) type podSource struct { - client kubernetes.Interface - namespace string - podInformer coreinformers.PodInformer - nodeInformer coreinformers.NodeInformer + client kubernetes.Interface + namespace string + podInformer coreinformers.PodInformer + nodeInformer coreinformers.NodeInformer + compatibility string } // NewPodSource creates a new podSource with the given config. -func NewPodSource(kubeClient kubernetes.Interface, namespace string) (Source, error) { +func NewPodSource(kubeClient kubernetes.Interface, namespace string, compatibility string) (Source, error) { informerFactory := kubeinformers.NewSharedInformerFactoryWithOptions(kubeClient, 0, kubeinformers.WithNamespace(namespace)) podInformer := informerFactory.Core().V1().Pods() nodeInformer := informerFactory.Core().V1().Nodes() @@ -71,10 +72,11 @@ func NewPodSource(kubeClient kubernetes.Interface, namespace string) (Source, er } return &podSource{ - client: kubeClient, - podInformer: podInformer, - nodeInformer: nodeInformer, - namespace: namespace, + client: kubeClient, + podInformer: podInformer, + nodeInformer: nodeInformer, + namespace: namespace, + compatibility: compatibility, }, nil } @@ -114,6 +116,28 @@ func (ps *podSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error } } } + + if ps.compatibility == "dns-controller" { + if domain, ok := pod.Annotations[dnsControllerInternalHostnameAnnotationKey]; ok { + if _, ok := domains[domain]; !ok { + domains[domain] = []string{} + } + domains[domain] = append(domains[domain], pod.Status.PodIP) + } + + if domain, ok := pod.Annotations[dnsControllerHostnameAnnotationKey]; ok { + if _, ok := domains[domain]; !ok { + domains[domain] = []string{} + } + + node, _ := ps.nodeInformer.Lister().Get(pod.Spec.NodeName) + for _, address := range node.Status.Addresses { + if address.Type == corev1.NodeExternalIP { + domains[domain] = append(domains[domain], address.Address) + } + } + } + } } endpoints := []*endpoint.Endpoint{} for domain, targets := range domains { diff --git a/source/pod_test.go b/source/pod_test.go index c471789fa..57850695d 100644 --- a/source/pod_test.go +++ b/source/pod_test.go @@ -32,6 +32,7 @@ func TestPodSource(t *testing.T) { for _, tc := range []struct { title string targetNamespace string + compatibility string expected []*endpoint.Endpoint expectError bool nodes []*corev1.Node @@ -40,6 +41,7 @@ func TestPodSource(t *testing.T) { { "create records based on pod's external and internal IPs", "", + "", []*endpoint.Endpoint{ {DNSName: "a.foo.example.org", Targets: endpoint.Targets{"54.10.11.1", "54.10.11.2"}, RecordType: endpoint.RecordTypeA}, {DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"10.0.1.1", "10.0.1.2"}, RecordType: endpoint.RecordTypeA}, @@ -106,9 +108,80 @@ func TestPodSource(t *testing.T) { }, }, }, + { + "create records based on pod's external and internal IPs using DNS Controller annotations", + "", + "dns-controller", + []*endpoint.Endpoint{ + {DNSName: "a.foo.example.org", Targets: endpoint.Targets{"54.10.11.1", "54.10.11.2"}, RecordType: endpoint.RecordTypeA}, + {DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"10.0.1.1", "10.0.1.2"}, RecordType: endpoint.RecordTypeA}, + }, + false, + []*corev1.Node{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-node1", + }, + Status: corev1.NodeStatus{ + Addresses: []corev1.NodeAddress{ + {Type: corev1.NodeExternalIP, Address: "54.10.11.1"}, + {Type: corev1.NodeInternalIP, Address: "10.0.1.1"}, + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-node2", + }, + Status: corev1.NodeStatus{ + Addresses: []corev1.NodeAddress{ + {Type: corev1.NodeExternalIP, Address: "54.10.11.2"}, + {Type: corev1.NodeInternalIP, Address: "10.0.1.2"}, + }, + }, + }, + }, + []*corev1.Pod{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-pod1", + Namespace: "kube-system", + Annotations: map[string]string{ + dnsControllerInternalHostnameAnnotationKey: "internal.a.foo.example.org", + dnsControllerHostnameAnnotationKey: "a.foo.example.org", + }, + }, + Spec: corev1.PodSpec{ + HostNetwork: true, + NodeName: "my-node1", + }, + Status: corev1.PodStatus{ + PodIP: "10.0.1.1", + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-pod2", + Namespace: "kube-system", + Annotations: map[string]string{ + dnsControllerInternalHostnameAnnotationKey: "internal.a.foo.example.org", + dnsControllerHostnameAnnotationKey: "a.foo.example.org", + }, + }, + Spec: corev1.PodSpec{ + HostNetwork: true, + NodeName: "my-node2", + }, + Status: corev1.PodStatus{ + PodIP: "10.0.1.2", + }, + }, + }, + }, { "create multiple records", "", + "", []*endpoint.Endpoint{ {DNSName: "a.foo.example.org", Targets: endpoint.Targets{"54.10.11.1"}, RecordType: endpoint.RecordTypeA}, {DNSName: "b.foo.example.org", Targets: endpoint.Targets{"54.10.11.2"}, RecordType: endpoint.RecordTypeA}, @@ -176,6 +249,7 @@ func TestPodSource(t *testing.T) { { "pods with hostNetwore=false should be ignored", "", + "", []*endpoint.Endpoint{ {DNSName: "a.foo.example.org", Targets: endpoint.Targets{"54.10.11.1"}, RecordType: endpoint.RecordTypeA}, {DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"10.0.1.1"}, RecordType: endpoint.RecordTypeA}, @@ -245,6 +319,7 @@ func TestPodSource(t *testing.T) { { "only watch a given namespace", "kube-system", + "", []*endpoint.Endpoint{ {DNSName: "a.foo.example.org", Targets: endpoint.Targets{"54.10.11.1"}, RecordType: endpoint.RecordTypeA}, {DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"10.0.1.1"}, RecordType: endpoint.RecordTypeA}, @@ -332,7 +407,7 @@ func TestPodSource(t *testing.T) { } } - client, err := NewPodSource(kubernetes, tc.targetNamespace) + client, err := NewPodSource(kubernetes, tc.targetNamespace, tc.compatibility) require.NoError(t, err) endpoints, err := client.Endpoints(ctx) diff --git a/source/store.go b/source/store.go index 8bff6a056..ab44fa073 100644 --- a/source/store.go +++ b/source/store.go @@ -193,7 +193,7 @@ func BuildWithConfig(source string, p ClientGenerator, cfg *Config) (Source, err if err != nil { return nil, err } - return NewPodSource(client, cfg.Namespace) + return NewPodSource(client, cfg.Namespace, cfg.Compatibility) case "istio-gateway": kubernetesClient, err := p.KubeClient() if err != nil { From 9295f188e3611b83daeb23c8d97a1f1078fa42ab Mon Sep 17 00:00:00 2001 From: Kundan Kumar Date: Wed, 23 Jun 2021 15:45:52 +0530 Subject: [PATCH 155/175] updated external-dns version to latest --- docs/tutorials/scaleway.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/tutorials/scaleway.md b/docs/tutorials/scaleway.md index 93f39cdd4..d9215bcce 100644 --- a/docs/tutorials/scaleway.md +++ b/docs/tutorials/scaleway.md @@ -52,7 +52,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.4 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. @@ -118,7 +118,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.4 + image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. From 2b39eabe382206ddc6f64562645f03983dea0a85 Mon Sep 17 00:00:00 2001 From: Kyle Michel Date: Wed, 23 Jun 2021 08:14:56 -0400 Subject: [PATCH 156/175] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nick Jüttner --- docs/tutorials/kong.md | 9 ++++----- source/kong_tcpingress.go | 3 +-- source/kong_tcpingress_test.go | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/docs/tutorials/kong.md b/docs/tutorials/kong.md index aa396f8ae..d03ad9681 100644 --- a/docs/tutorials/kong.md +++ b/docs/tutorials/kong.md @@ -22,7 +22,7 @@ spec: containers: - name: external-dns # update this to the desired external-dns version - image: k8s.gcr.io/external-dns/external-dns:v0.7.6 + image: k8s.gcr.io/external-dns/external-dns:v0.9.0 args: - --source=kong-tcpingress - --provider=aws @@ -39,7 +39,7 @@ kind: ServiceAccount metadata: name: external-dns --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns @@ -54,7 +54,7 @@ rules: resources: ["tcpingresses"] verbs: ["get","watch","list"] --- -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer @@ -86,11 +86,10 @@ spec: containers: - name: external-dns # update this to the desired external-dns version - image: k8s.gcr.io/external-dns/external-dns:v0.7.6 + image: k8s.gcr.io/external-dns/external-dns:v0.9.0 args: - --source=kong-tcpingress - --provider=aws - --registry=txt - --txt-owner-id=my-identifier ``` - diff --git a/source/kong_tcpingress.go b/source/kong_tcpingress.go index 639a3f283..1fe0b1111 100644 --- a/source/kong_tcpingress.go +++ b/source/kong_tcpingress.go @@ -1,5 +1,5 @@ /* -Copyright 2017 The Kubernetes Authors. +Copyright 2021 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,7 +22,6 @@ import ( "sort" "time" - //kongv1beta1 "github.com/kong/kubernetes-ingress-controller/pkg/apis/configuration/v1beta1" "github.com/pkg/errors" log "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" diff --git a/source/kong_tcpingress_test.go b/source/kong_tcpingress_test.go index e53a9bda6..b076ecd7b 100644 --- a/source/kong_tcpingress_test.go +++ b/source/kong_tcpingress_test.go @@ -1,5 +1,5 @@ /* -Copyright 2020n The Kubernetes Authors. +Copyright 2021 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 6158bc118ed787458728bb692529c1c955af73dc Mon Sep 17 00:00:00 2001 From: Edward Lynes Date: Wed, 23 Jun 2021 14:45:50 -0400 Subject: [PATCH 157/175] Minor edits. Use v0.8.0 image. Add service account reference to the deployment spec example. Add --txt-prefix to avoid CNAME conflict. --- docs/tutorials/akamai-edgedns.md | 46 +++++++++++++++----------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/docs/tutorials/akamai-edgedns.md b/docs/tutorials/akamai-edgedns.md index 09b4478f3..28c645ef4 100644 --- a/docs/tutorials/akamai-edgedns.md +++ b/docs/tutorials/akamai-edgedns.md @@ -2,17 +2,17 @@ ## Prerequisites -Akamai Edge DNS (formally known as Fast DNS) provider support was first released in External-DNS v0.5.18 +External-DNS v0.8.0 or greater. ### Zones -External-DNS manages service endpoints in existing DNS zones. The Akamai provider does not add, remove or configure new zones in anyway. Edge DNS zones can be created and managed thru the [Akamai Control Center](https://control.akamai.com) or [Akamai DevOps Tools](https://developer.akamai.com/devops), [Akamai CLI](https://developer.akamai.com/cli) and [Akamai Terraform Provider](https://developer.akamai.com/tools/integrations/terraform) +External-DNS manages service endpoints in existing DNS zones. The Akamai provider does not add, remove or configure new zones. The [Akamai Control Center](https://control.akamai.com) or [Akamai DevOps Tools](https://developer.akamai.com/devops), [Akamai CLI](https://developer.akamai.com/cli) and [Akamai Terraform Provider](https://developer.akamai.com/tools/integrations/terraform) can create and manage Edge DNS zones. ### Akamai Edge DNS Authentication -The Akamai Edge DNS provider requires valid Akamai Edgegrid API authentication credentials to access zones and manage associated DNS records. +The Akamai Edge DNS provider requires valid Akamai Edgegrid API authentication credentials to access zones and manage DNS records. -Credentials can be provided to the provider either directly by key or indirectly via a file. The Akamai credential keys and mappings to the Akamai provider utilizing different presentation methods are: +Either directly by key or indirectly via a file can set credentials for the provider. The Akamai credential keys and mappings to the Akamai provider utilizing different presentation methods are: | Edgegrid Auth Key | External-DNS Cmd Line Key | Environment/ConfigMap Key | Description | | ----------------- | ------------------------- | ------------------------- | ----------- | @@ -21,25 +21,20 @@ Credentials can be provided to the provider either directly by key or indirectly | client_token | akamai-client-token | EXTERNAL_DNS_AKAMAI_CLIENT_TOKEN |Akamai Edgegrid API client token | | client-secret | akamai-client-secret | EXTERNAL_DNS_AKAMAI_CLIENT_SECRET |Akamai Edgegrid API client secret | -In addition to specifying auth credentials individually, the credentials may be referenced indirectly by using the Akamai Edgegrid .edgerc file convention. +In addition to specifying auth credentials individually, an Akamai Edgegrid .edgerc file convention can set credentials. | External-DNS Cmd Line | Environment/ConfigMap | Description | | --------------------- | --------------------- | ----------- | | akamai-edgerc-path | EXTERNAL_DNS_AKAMAI_EDGERC_PATH | Accessible path to Edgegrid credentials file, e.g /home/test/.edgerc | | akamai-edgerc-section | EXTERNAL_DNS_AKAMAI_EDGERC_SECTION | Section in Edgegrid credentials file containing credentials | -Note: akamai-edgerc-path and akamai-edgerc-section are present in External-DNS versions after v0.7.5 - -[Akamai API Authentication](https://developer.akamai.com/getting-started/edgegrid) provides an overview and further information pertaining to the generation of auth credentials for API base applications and tools. - -The following example defines and references a Kubernetes ConfigMap secret, applied by referencing the secret and its keys in the env section of the deployment. - +[Akamai API Authentication](https://developer.akamai.com/getting-started/edgegrid) provides an overview and further information about authorization credentials for API base applications and tools. ## Deploy External-DNS -An operational External-DNS deployment consists of an External-DNS container and service. The following sections demonstrate the ConfigMap objects that would make up an example functional external DNS kubernetes configuration utilizing NGINX as the exposed service. +An operational External-DNS deployment consists of an External-DNS container and service. The following sections demonstrate the ConfigMap objects that would make up an example functional external DNS kubernetes configuration utilizing NGINX as the service. -Connect your `kubectl` client to the cluster with which you want to test External-DNS, and then apply one of the following manifest files for deployment: +Connect your `kubectl` client to the External-DNS cluster, and then apply one of the following manifest files: ### Manifest (for clusters without RBAC enabled) @@ -59,9 +54,10 @@ spec: labels: app: external-dns spec: + serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.6 + image: k8s.gcr.io/external-dns/external-dns:v0.8.0 args: - --source=service # or ingress or both - --provider=akamai @@ -69,6 +65,7 @@ spec: # zone-id-filter may be specified as well to filter on contract ID - --registry=txt - --txt-owner-id={{ owner-id-for-this-external-dns }} + - --txt-prefix={{ prefix label for TXT record }}. env: - name: EXTERNAL_DNS_AKAMAI_SERVICECONSUMERDOMAIN valueFrom: @@ -143,9 +140,10 @@ spec: labels: app: external-dns spec: + serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.6 + image: k8s.gcr.io/external-dns/external-dns:v0.8.0 args: - --source=service # or ingress or both - --provider=akamai @@ -153,6 +151,7 @@ spec: # zone-id-filter may be specified as well to filter on contract ID - --registry=txt - --txt-owner-id={{ owner-id-for-this-external-dns }} + - --txt-prefix={{ prefix label for TXT record }}. env: - name: EXTERNAL_DNS_AKAMAI_SERVICECONSUMERDOMAIN valueFrom: @@ -179,7 +178,7 @@ spec: Create the deployment for External-DNS: ``` -$ kubectl create -f externaldns.yaml +$ kubectl apply -f externaldns.yaml ``` ## Deploying an Nginx Service @@ -223,21 +222,21 @@ spec: targetPort: 80 ``` -Create the deployment, service and ingress object: +Create the deployment and service object: ``` -$ kubectl create -f nginx.yaml +$ kubectl apply -f nginx.yaml ``` ## Verify Akamai Edge DNS Records -It is recommended to wait 3-5 minutes before validating the records to allow the record changes to propagate to all the Akamai name servers worldwide. +Wait 3-5 minutes before validating the records to allow the record changes to propagate to all the Akamai name servers. -The records can be validated using the [Akamai Control Center](http://control.akamai.com) or by executing a dig, nslookup or similar DNS command. +Validate records using the [Akamai Control Center](http://control.akamai.com) or by executing a dig, nslookup or similar DNS command. ## Cleanup -Once you successfully configure and verify record management via External-DNS, you can delete the tutorial's example: +Once you successfully configure and verify record management via External-DNS, you can delete the tutorial's examples: ``` $ kubectl delete -f nginx.yaml @@ -246,6 +245,5 @@ $ kubectl delete -f externaldns.yaml ## Additional Information -* The Akamai provider allows the administrative user to filter zones by both name (domain-filter) and contract Id (zone-id-filter). The Edge DNS API will return a '500 Internal Error' if an invalid contract Id is provided. -* The provider will substitute any embedded quotes in TXT records with `` ` `` (back tick) when writing the records to the API. - +* The Akamai provider allows the administrative user to filter zones by both name (`domain-filter`) and contract Id (`zone-id-filter`). The Edge DNS API will return a '500 Internal Error' for invalid contract Ids. +* The provider will substitute quotes in TXT records with a `` ` `` (back tick) when writing records with the API. From 0aae14288ccceec35905a983b8aa502bddd42f15 Mon Sep 17 00:00:00 2001 From: Artem Voronin Date: Wed, 23 Jun 2021 22:01:09 +0300 Subject: [PATCH 158/175] Added test for node with nil labels --- source/node_test.go | 13 +++++++++++++ source/shared_test.go | 6 ++++++ 2 files changed, 19 insertions(+) diff --git a/source/node_test.go b/source/node_test.go index d82425c47..e6ce849c9 100644 --- a/source/node_test.go +++ b/source/node_test.go @@ -307,6 +307,19 @@ func testNodeSourceEndpoints(t *testing.T) { }, false, }, + { + "node with nil Lables returns valid endpoint", + "", + "", + "node1", + []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}}, + nil, + map[string]string{}, + []*endpoint.Endpoint{ + {RecordType: "A", DNSName: "node1", Targets: endpoint.Targets{"1.2.3.4"}, Labels: map[string]string{}}, + }, + false, + }, } { t.Run(tc.title, func(t *testing.T) { // Create a Kubernetes testing client diff --git a/source/shared_test.go b/source/shared_test.go index d7043a82b..9f9060836 100644 --- a/source/shared_test.go +++ b/source/shared_test.go @@ -20,6 +20,7 @@ import ( "sort" "strings" "testing" + "reflect" "sigs.k8s.io/external-dns/endpoint" ) @@ -60,4 +61,9 @@ func validateEndpoint(t *testing.T, endpoint, expected *endpoint.Endpoint) { if expected.RecordType != "" && endpoint.RecordType != expected.RecordType { t.Errorf("expected %s, got %s", expected.RecordType, endpoint.RecordType) } + + // if non-empty labels are expected, check that they matches. + if expected.Labels != nil && !reflect.DeepEqual(endpoint.Labels,expected.Labels) { + t.Errorf("expected %s, got %s", expected.Labels, endpoint.Labels) + } } From ba3081064154ded1933db782c00949aa1c6627b9 Mon Sep 17 00:00:00 2001 From: Ole Markus With Date: Wed, 23 Jun 2021 09:10:30 +0200 Subject: [PATCH 159/175] Use kops dns controller instead of just dns controller where it makes sense MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nick Jüttner --- README.md | 4 ++-- pkg/apis/externaldns/types.go | 2 +- source/compatibility.go | 18 +++++++++--------- source/pod.go | 6 +++--- source/pod_test.go | 10 +++++----- source/service_test.go | 34 +++++++++++++++++----------------- 6 files changed, 37 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index e4e38073e..11c1d2c30 100644 --- a/README.md +++ b/README.md @@ -277,12 +277,12 @@ Here's a rough outline on what is to come (subject to change): ### v0.6 -- [ ] Ability to replace Kops' [DNS Controller](https://github.com/kubernetes/kops/tree/HEAD/dns-controller) (This could also directly become `v1.0`) +- [ ] Ability to replace kOps' [DNS Controller](https://github.com/kubernetes/kops/tree/HEAD/dns-controller) (This could also directly become `v1.0`) - [x] Support for OVH ### v1.0 -- [ ] Ability to replace Kops' [DNS Controller](https://github.com/kubernetes/kops/tree/HEAD/dns-controller) +- [ ] Ability to replace kOps' [DNS Controller](https://github.com/kubernetes/kops/tree/HEAD/dns-controller) - [x] Add support for pod source - [x] Add support for DNS Controller annotations for pod and service sources - [ ] Add support for kOps gossip provider diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 6713d3f13..c76b5c7e8 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -356,7 +356,7 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("combine-fqdn-annotation", "Combine FQDN template and Annotations instead of overwriting").BoolVar(&cfg.CombineFQDNAndAnnotation) app.Flag("ignore-hostname-annotation", "Ignore hostname annotation when generating DNS names, valid only when using fqdn-template is set (optional, default: false)").BoolVar(&cfg.IgnoreHostnameAnnotation) app.Flag("ignore-ingress-tls-spec", "Ignore tls spec section in ingresses resources, applicable only for ingress sources (optional, default: false)").BoolVar(&cfg.IgnoreIngressTLSSpec) - app.Flag("compatibility", "Process annotation semantics from legacy implementations (optional, options: mate, molecule)").Default(defaultConfig.Compatibility).EnumVar(&cfg.Compatibility, "", "mate", "molecule", "dns-controller") + app.Flag("compatibility", "Process annotation semantics from legacy implementations (optional, options: mate, molecule, kops-dns-controller)").Default(defaultConfig.Compatibility).EnumVar(&cfg.Compatibility, "", "mate", "molecule", "kops-dns-controller") app.Flag("publish-internal-services", "Allow external-dns to publish DNS records for ClusterIP services (optional)").BoolVar(&cfg.PublishInternal) app.Flag("publish-host-ip", "Allow external-dns to publish host-ip for headless services (optional)").BoolVar(&cfg.PublishHostIP) app.Flag("always-publish-not-ready-addresses", "Always publish also not ready addresses for headless services (optional)").BoolVar(&cfg.AlwaysPublishNotReadyAddresses) diff --git a/source/compatibility.go b/source/compatibility.go index ff7f7d8f5..bc6e19abf 100644 --- a/source/compatibility.go +++ b/source/compatibility.go @@ -28,10 +28,10 @@ import ( const ( mateAnnotationKey = "zalando.org/dnsname" moleculeAnnotationKey = "domainName" - // dnsControllerHostnameAnnotationKey is the annotation used for defining the desired hostname when DNS controller compatibility mode - dnsControllerHostnameAnnotationKey = "dns.alpha.kubernetes.io/external" - // dnsControllerInternalHostnameAnnotationKey is the annotation used for defining the desired hostname when DNS controller compatibility mode - dnsControllerInternalHostnameAnnotationKey = "dns.alpha.kubernetes.io/internal" + // kopsDNSControllerHostnameAnnotationKey is the annotation used for defining the desired hostname when kOps DNS controller compatibility mode + kopsDNSControllerHostnameAnnotationKey = "dns.alpha.kubernetes.io/external" + // kopsDNSControllerInternalHostnameAnnotationKey is the annotation used for defining the desired hostname when kOps DNS controller compatibility mode + kopsDNSControllerInternalHostnameAnnotationKey = "dns.alpha.kubernetes.io/internal" ) // legacyEndpointsFromService tries to retrieve Endpoints from Services @@ -42,7 +42,7 @@ func legacyEndpointsFromService(svc *v1.Service, sc *serviceSource) ([]*endpoint return legacyEndpointsFromMateService(svc), nil case "molecule": return legacyEndpointsFromMoleculeService(svc), nil - case "dns-controller": + case "kops-dns-controller": return legacyEndpointsFromDNSControllerService(svc, sc) } @@ -126,8 +126,8 @@ func legacyEndpointsFromDNSControllerNodePortService(svc *v1.Service, sc *servic var endpoints []*endpoint.Endpoint // Get the desired hostname of the service from the annotations. - hostnameAnnotation, isExternal := svc.Annotations[dnsControllerHostnameAnnotationKey] - internalHostnameAnnotation, isInternal := svc.Annotations[dnsControllerInternalHostnameAnnotationKey] + hostnameAnnotation, isExternal := svc.Annotations[kopsDNSControllerHostnameAnnotationKey] + internalHostnameAnnotation, isInternal := svc.Annotations[kopsDNSControllerInternalHostnameAnnotationKey] if !isExternal && !isInternal { return nil, nil @@ -175,8 +175,8 @@ func legacyEndpointsFromDNSControllerLoadBalancerService(svc *v1.Service) []*end var endpoints []*endpoint.Endpoint // Get the desired hostname of the service from the annotations. - hostnameAnnotation, hasExternal := svc.Annotations[dnsControllerHostnameAnnotationKey] - internalHostnameAnnotation, hasInternal := svc.Annotations[dnsControllerInternalHostnameAnnotationKey] + hostnameAnnotation, hasExternal := svc.Annotations[kopsDNSControllerHostnameAnnotationKey] + internalHostnameAnnotation, hasInternal := svc.Annotations[kopsDNSControllerInternalHostnameAnnotationKey] if !hasExternal && !hasInternal { return nil diff --git a/source/pod.go b/source/pod.go index f3ddf17dc..57a33de63 100644 --- a/source/pod.go +++ b/source/pod.go @@ -117,15 +117,15 @@ func (ps *podSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error } } - if ps.compatibility == "dns-controller" { - if domain, ok := pod.Annotations[dnsControllerInternalHostnameAnnotationKey]; ok { + if ps.compatibility == "kops-dns-controller" { + if domain, ok := pod.Annotations[kopsDNSControllerInternalHostnameAnnotationKey]; ok { if _, ok := domains[domain]; !ok { domains[domain] = []string{} } domains[domain] = append(domains[domain], pod.Status.PodIP) } - if domain, ok := pod.Annotations[dnsControllerHostnameAnnotationKey]; ok { + if domain, ok := pod.Annotations[kopsDNSControllerHostnameAnnotationKey]; ok { if _, ok := domains[domain]; !ok { domains[domain] = []string{} } diff --git a/source/pod_test.go b/source/pod_test.go index 57850695d..95dfca616 100644 --- a/source/pod_test.go +++ b/source/pod_test.go @@ -111,7 +111,7 @@ func TestPodSource(t *testing.T) { { "create records based on pod's external and internal IPs using DNS Controller annotations", "", - "dns-controller", + "kops-dns-controller", []*endpoint.Endpoint{ {DNSName: "a.foo.example.org", Targets: endpoint.Targets{"54.10.11.1", "54.10.11.2"}, RecordType: endpoint.RecordTypeA}, {DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"10.0.1.1", "10.0.1.2"}, RecordType: endpoint.RecordTypeA}, @@ -147,8 +147,8 @@ func TestPodSource(t *testing.T) { Name: "my-pod1", Namespace: "kube-system", Annotations: map[string]string{ - dnsControllerInternalHostnameAnnotationKey: "internal.a.foo.example.org", - dnsControllerHostnameAnnotationKey: "a.foo.example.org", + kopsDNSControllerInternalHostnameAnnotationKey: "internal.a.foo.example.org", + kopsDNSControllerHostnameAnnotationKey: "a.foo.example.org", }, }, Spec: corev1.PodSpec{ @@ -164,8 +164,8 @@ func TestPodSource(t *testing.T) { Name: "my-pod2", Namespace: "kube-system", Annotations: map[string]string{ - dnsControllerInternalHostnameAnnotationKey: "internal.a.foo.example.org", - dnsControllerHostnameAnnotationKey: "a.foo.example.org", + kopsDNSControllerInternalHostnameAnnotationKey: "internal.a.foo.example.org", + kopsDNSControllerHostnameAnnotationKey: "a.foo.example.org", }, }, Spec: corev1.PodSpec{ diff --git a/source/service_test.go b/source/service_test.go index 2c004c543..0aece2bf6 100644 --- a/source/service_test.go +++ b/source/service_test.go @@ -489,7 +489,7 @@ func testServiceSourceEndpoints(t *testing.T) { false, }, { - "our controller type is dns-controller", + "our controller type is kops dns controller", "", "", "testing", @@ -875,13 +875,13 @@ func testServiceSourceEndpoints(t *testing.T) { "testing", "foo", v1.ServiceTypeLoadBalancer, - "dns-controller", + "kops-dns-controller", "", false, false, map[string]string{}, map[string]string{ - dnsControllerInternalHostnameAnnotationKey: "internal.foo.example.org", + kopsDNSControllerInternalHostnameAnnotationKey: "internal.foo.example.org", }, "", []string{}, @@ -899,14 +899,14 @@ func testServiceSourceEndpoints(t *testing.T) { "testing", "foo", v1.ServiceTypeLoadBalancer, - "dns-controller", + "kops-dns-controller", "", false, false, map[string]string{}, map[string]string{ - dnsControllerInternalHostnameAnnotationKey: "internal.foo.example.org., internal.bar.example.org", - dnsControllerHostnameAnnotationKey: "foo.example.org., bar.example.org", + kopsDNSControllerInternalHostnameAnnotationKey: "internal.foo.example.org., internal.bar.example.org", + kopsDNSControllerHostnameAnnotationKey: "foo.example.org., bar.example.org", }, "", []string{}, @@ -2049,12 +2049,12 @@ func TestServiceSourceNodePortServices(t *testing.T) { "foo", v1.ServiceTypeNodePort, v1.ServiceExternalTrafficPolicyTypeCluster, - "dns-controller", + "kops-dns-controller", "", false, map[string]string{}, map[string]string{ - dnsControllerInternalHostnameAnnotationKey: "internal.foo.example.org., internal.bar.example.org", + kopsDNSControllerInternalHostnameAnnotationKey: "internal.foo.example.org., internal.bar.example.org", }, nil, []*endpoint.Endpoint{ @@ -2101,12 +2101,12 @@ func TestServiceSourceNodePortServices(t *testing.T) { "foo", v1.ServiceTypeNodePort, v1.ServiceExternalTrafficPolicyTypeCluster, - "dns-controller", + "kops-dns-controller", "", false, map[string]string{}, map[string]string{ - dnsControllerInternalHostnameAnnotationKey: "internal.foo.example.org., internal.bar.example.org", + kopsDNSControllerInternalHostnameAnnotationKey: "internal.foo.example.org., internal.bar.example.org", }, nil, []*endpoint.Endpoint{ @@ -2153,12 +2153,12 @@ func TestServiceSourceNodePortServices(t *testing.T) { "foo", v1.ServiceTypeNodePort, v1.ServiceExternalTrafficPolicyTypeCluster, - "dns-controller", + "kops-dns-controller", "", false, map[string]string{}, map[string]string{ - dnsControllerHostnameAnnotationKey: "foo.example.org., bar.example.org", + kopsDNSControllerHostnameAnnotationKey: "foo.example.org., bar.example.org", }, nil, []*endpoint.Endpoint{ @@ -2198,20 +2198,20 @@ func TestServiceSourceNodePortServices(t *testing.T) { []v1.PodPhase{}, }, { - "node port services annotated with both dns-controller annotations return an empty set of addons", + "node port services annotated with both kops dns controller annotations return an empty set of addons", "", "", "testing", "foo", v1.ServiceTypeNodePort, v1.ServiceExternalTrafficPolicyTypeCluster, - "dns-controller", + "kops-dns-controller", "", false, map[string]string{}, map[string]string{ - dnsControllerInternalHostnameAnnotationKey: "internal.foo.example.org., internal.bar.example.org", - dnsControllerHostnameAnnotationKey: "foo.example.org., bar.example.org", + kopsDNSControllerInternalHostnameAnnotationKey: "internal.foo.example.org., internal.bar.example.org", + kopsDNSControllerHostnameAnnotationKey: "foo.example.org., bar.example.org", }, nil, []*endpoint.Endpoint{}, @@ -2958,7 +2958,7 @@ func TestHeadlessServicesHostIP(t *testing.T) { require.NoError(t, err) address := v1.EndpointAddress{ - IP: "4.3.2.1", + IP: "4.3.2.1", TargetRef: tc.targetRefs[i], } if tc.podsReady[i] { From 0306e20429bb0a381f6579f0f27c0de946c13598 Mon Sep 17 00:00:00 2001 From: Ole Markus With Date: Thu, 24 Jun 2021 08:55:42 +0200 Subject: [PATCH 160/175] Add documentation on kops-compatibility-mode --- docs/legacy/kops-dns-controller.md | 84 --------------------------- docs/tutorials/kops-dns-controller.md | 37 ++++++++++++ 2 files changed, 37 insertions(+), 84 deletions(-) delete mode 100644 docs/legacy/kops-dns-controller.md create mode 100644 docs/tutorials/kops-dns-controller.md diff --git a/docs/legacy/kops-dns-controller.md b/docs/legacy/kops-dns-controller.md deleted file mode 100644 index 45fc7e12f..000000000 --- a/docs/legacy/kops-dns-controller.md +++ /dev/null @@ -1,84 +0,0 @@ -# Kops dns-controller annotations - -Kops includes a dns-controller, and this document describes the existing annotations and their behaviour. This -document is intended to allow us to see the use-cases identified by kops dns-controller, to ensure the same annotations -can be recognized (perhaps with a `--compatibilty` flag), and to ensure that we have comparable functionality. - -## Flags - -* `--dns`: `aws-route53,google-clouddns` - -The DNS flag lets us choose which DNS provider to use. - -* `--watch-ingress` boolean - -Turns ingress functionality on and off. For AWS at least, we are blocked on switching to a release -from the `kubernetes/ingress` project (instead of one from the `contrib` project). - -* `--zones` configures permitted zones, and also disambiguates when domain names are duplicated. It is a list that matches zones we are allowed to match. - - - `*` and `*/*` are wildcard, and match all zones - - - `example.com` matches zones with name=`example.com` - - - `example.com/1234` matches zones with id=`1234` and name=`example.com`. This is useful to disambiguate between -multiple zones named `example.com`. - - - `*/1234` matches the zone with id=`1234`. A zone has a unique name, so this is equivalent to `example.com/1234`, -but a little shorter - and less self-documenting! - -* Standard glog flags (--v, --logtostderr etc) - -* Standard kubectl_util client flags - - -## Annotations - -We define 2 primary annotations: - -* `dns.alpha.kubernetes.io/external` which is used to define a DNS record for accessing the resource publicly (i.e. public IPs) - -* `dns.alpha.kubernetes.io/internal` which is used to define a DNS record for accessing the resource from outside the cluster but inside the cloud, -i.e. it will typically use internal IPs for instances. - -These annotations may both be comma-separated lists of names. - -On a node, we also have a WIP annotation `dns.alpha.kubernetes.io/external-ip`, which configures the external ip -for a node (to work around [#42125](https://github.com/kubernetes/kubernetes/issues/42125)). That is an annotation -that lets us defined the equivalent of an address with type ExternalIP. - -## DNS record mappings - -The DNS record mappings try to "do the right thing", but what this means is different for each resource type. - -### Ingress - -We consult the `Status.LoadBalancer.Ingress` records on the ingress. For each one, we create a record. -If the record is an IP address, we add an A record. If the record is a hostname (AWS ELB), we use a CNAME. - -We would like to use an ALIAS, but we have not yet done this because of limitations of the DNS provider. - -### Pods - -For the external annotation, we will map a HostNetwork=true pod to the external IPs of the node. We create an A record. - -For the internal annotation, we will map a HostNetwork=true pod to the internal IPs of the node. We create an A record. - -We ignore pods that are not HostNetwork=true - -### Services - -* For a Service of Type=LoadBalancer, we look at Status.LoadBalancer.Ingress. We create CNAMEs to hostnames, - and A records for IP addresses. (We should create ALIASes for ELBs). We do this for both internal & external - names - there is no difference on GCE or AWS. - -* For a Service of Type=NodePort, we create A records for the node's internal/external IP addresses, as appropriate. - -(A canonical use for NodePort internal is having a prometheus server running inside EC2 monitoring your kubernetes cluster, -for NodePort external is to expose your service without an ELB). - - -### Nodes - -(We don't currently support annotations on the nodes themselves. We do set up internal "alias" records, -which is how we do JOINs for e.g. NodePort services) diff --git a/docs/tutorials/kops-dns-controller.md b/docs/tutorials/kops-dns-controller.md new file mode 100644 index 000000000..04da968bf --- /dev/null +++ b/docs/tutorials/kops-dns-controller.md @@ -0,0 +1,37 @@ +# kOps dns-controller compatibility mode + +kOps includes a dns-controller that is primarily used to bootstrap the cluster, but can also be used for provisioning DNS entries for Services and Ingress. + +ExternalDNS can be used as a drop-in replacement for dns-controller if you are running a non-gossip cluster. The flag `--compatibility kops-dns-controller` enables the dns-controller behaviour. + +## Annotations + +In kops-dns-controller compatibility mode, ExternalDNS supports two additional annotations: + +* `dns.alpha.kubernetes.io/external` which is used to define a DNS record for accessing the resource publicly (i.e. public IPs) + +* `dns.alpha.kubernetes.io/internal` which is used to define a DNS record for accessing the resource from outside the cluster but inside the cloud, +i.e. it will typically use internal IPs for instances. + +These annotations may both be comma-separated lists of names. + +## DNS record mappings + +The DNS record mappings try to "do the right thing", but what this means is different for each resource type. + +### Pods + +For the external annotation, ExternalDNS will map a HostNetwork=true Pod to the external IPs of the Node. + +For the internal annotation, ExternalDNS will map a HostNetwork=true Pod to the internal IPs of the Node. + +ExternalDNS ignore Pods that are not HostNetwork=true + +Annotations added to Pods will always result in an A record being created. + +### Services + +* For a Service of Type=LoadBalancer, ExternalDNS looks at Status.LoadBalancer.Ingress. It will create CNAMEs to hostnames, + and A records for IP addresses. It will do this for both internal and external names + +* For a Service of Type=NodePort, ExternalDNS will create A records for the Node's internal/external IP addresses, as appropriate. \ No newline at end of file From b05df8b3889601d17d53cd674dd542ffaeb93150 Mon Sep 17 00:00:00 2001 From: Stephen Greene Date: Fri, 25 Jun 2021 11:30:47 -0400 Subject: [PATCH 161/175] source: Clean up OpenShift Route source source/ocproute.go: Add/clean up godocs and general in-line comments. Change `routeapi` named import to `routev1`. Update `routev1` calling sites accordingly. Signed-off-by: Stephen Greene --- source/ocproute.go | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/source/ocproute.go b/source/ocproute.go index c09acf09f..2b0eb6f31 100644 --- a/source/ocproute.go +++ b/source/ocproute.go @@ -25,7 +25,7 @@ import ( "text/template" "time" - routeapi "github.com/openshift/api/route/v1" + routev1 "github.com/openshift/api/route/v1" versioned "github.com/openshift/client-go/route/clientset/versioned" extInformers "github.com/openshift/client-go/route/informers/externalversions" routeInformer "github.com/openshift/client-go/route/informers/externalversions/route/v1" @@ -39,9 +39,10 @@ import ( ) // ocpRouteSource is an implementation of Source for OpenShift Route objects. -// Route implementation will use the spec.host value for the hostname -// Use targetAnnotationKey to explicitly set Endpoint. (useful if the router -// does not update, or to override with alternative endpoint) +// The Route implementation will use the Route spec.host field for the hostname, +// and the Route status' canonicalHostname field as the target. +// The targetAnnotationKey can be used to explicitly set an alternative +// endpoint, if desired. type ocpRouteSource struct { client versioned.Interface namespace string @@ -74,7 +75,7 @@ func NewOcpRouteSource( } } - // Use shared informer to listen for add/update/delete of Routes in the specified namespace. + // Use a shared informer to listen for add/update/delete of Routes in the specified namespace. // Set resync period to 0, to prevent processing when nothing has changed. informerFactory := extInformers.NewFilteredSharedInformerFactory(ocpClient, 0, namespace, nil) routeInformer := informerFactory.Route().V1().Routes() @@ -114,7 +115,8 @@ func (ors *ocpRouteSource) AddEventHandler(ctx context.Context, handler func()) } // Endpoints returns endpoint objects for each host-target combination that should be processed. -// Retrieves all OpenShift Route resources on all namespaces +// Retrieves all OpenShift Route resources on all namespaces, unless an explicit namespace +// is specified in ocpRouteSource. func (ors *ocpRouteSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error) { ocpRoutes, err := ors.routeInformer.Lister().Routes(ors.namespace).List(labels.Everything()) if err != nil { @@ -170,7 +172,7 @@ func (ors *ocpRouteSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, return endpoints, nil } -func (ors *ocpRouteSource) endpointsFromTemplate(ocpRoute *routeapi.Route) ([]*endpoint.Endpoint, error) { +func (ors *ocpRouteSource) endpointsFromTemplate(ocpRoute *routev1.Route) ([]*endpoint.Endpoint, error) { // Process the whole template string var buf bytes.Buffer err := ors.fqdnTemplate.Execute(&buf, ocpRoute) @@ -203,7 +205,7 @@ func (ors *ocpRouteSource) endpointsFromTemplate(ocpRoute *routeapi.Route) ([]*e return endpoints, nil } -func (ors *ocpRouteSource) filterByAnnotations(ocpRoutes []*routeapi.Route) ([]*routeapi.Route, error) { +func (ors *ocpRouteSource) filterByAnnotations(ocpRoutes []*routev1.Route) ([]*routev1.Route, error) { labelSelector, err := metav1.ParseToLabelSelector(ors.annotationFilter) if err != nil { return nil, err @@ -218,7 +220,7 @@ func (ors *ocpRouteSource) filterByAnnotations(ocpRoutes []*routeapi.Route) ([]* return ocpRoutes, nil } - filteredList := []*routeapi.Route{} + filteredList := []*routev1.Route{} for _, ocpRoute := range ocpRoutes { // convert the Route's annotations to an equivalent label selector @@ -233,14 +235,14 @@ func (ors *ocpRouteSource) filterByAnnotations(ocpRoutes []*routeapi.Route) ([]* return filteredList, nil } -func (ors *ocpRouteSource) setResourceLabel(ocpRoute *routeapi.Route, endpoints []*endpoint.Endpoint) { +func (ors *ocpRouteSource) setResourceLabel(ocpRoute *routev1.Route, endpoints []*endpoint.Endpoint) { for _, ep := range endpoints { ep.Labels[endpoint.ResourceLabelKey] = fmt.Sprintf("route/%s/%s", ocpRoute.Namespace, ocpRoute.Name) } } // endpointsFromOcpRoute extracts the endpoints from a OpenShift Route object -func endpointsFromOcpRoute(ocpRoute *routeapi.Route, ignoreHostnameAnnotation bool) []*endpoint.Endpoint { +func endpointsFromOcpRoute(ocpRoute *routev1.Route, ignoreHostnameAnnotation bool) []*endpoint.Endpoint { var endpoints []*endpoint.Endpoint ttl, err := getTTLFromAnnotations(ocpRoute.Annotations) @@ -270,7 +272,7 @@ func endpointsFromOcpRoute(ocpRoute *routeapi.Route, ignoreHostnameAnnotation bo return endpoints } -func targetsFromOcpRouteStatus(status routeapi.RouteStatus) endpoint.Targets { +func targetsFromOcpRouteStatus(status routev1.RouteStatus) endpoint.Targets { var targets endpoint.Targets for _, ing := range status.Ingress { From d273066d6b47931a070082e7d884379e3aa3f7b3 Mon Sep 17 00:00:00 2001 From: Stephen Greene Date: Fri, 25 Jun 2021 15:23:52 -0400 Subject: [PATCH 162/175] source: Add ocproute source unit tests source/ocproute_test.go: New file for source/ocproute.go unit tests. Inspired by the service source unit tests, this commit adds basic unit tests to verify basic functionality of the OCP route source. Signed-off-by: Stephen Greene --- source/ocproute_test.go | 275 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 source/ocproute_test.go diff --git a/source/ocproute_test.go b/source/ocproute_test.go new file mode 100644 index 000000000..d7c8a1821 --- /dev/null +++ b/source/ocproute_test.go @@ -0,0 +1,275 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package source + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + + routev1 "github.com/openshift/api/route/v1" + fake "github.com/openshift/client-go/route/clientset/versioned/fake" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "sigs.k8s.io/external-dns/endpoint" +) + +type OCPRouteSuite struct { + suite.Suite + sc Source + routeWithTargets *routev1.Route +} + +func (suite *OCPRouteSuite) SetupTest() { + fakeClient := fake.NewSimpleClientset() + var err error + + suite.sc, err = NewOcpRouteSource( + fakeClient, + "", + "", + "{{.Name}}", + false, + false, + ) + + suite.routeWithTargets = &routev1.Route{ + Spec: routev1.RouteSpec{ + Host: "my-domain.com", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "route-with-targets", + Annotations: map[string]string{}, + }, + Status: routev1.RouteStatus{ + Ingress: []routev1.RouteIngress{ + { + RouterCanonicalHostname: "apps.my-domain.com", + }, + }, + }, + } + + suite.NoError(err, "should initialize route source") + + _, err = fakeClient.RouteV1().Routes(suite.routeWithTargets.Namespace).Create(context.Background(), suite.routeWithTargets, metav1.CreateOptions{}) + suite.NoError(err, "should successfully create route") +} + +func (suite *OCPRouteSuite) TestResourceLabelIsSet() { + endpoints, _ := suite.sc.Endpoints(context.Background()) + for _, ep := range endpoints { + suite.Equal("route/default/route-with-targets", ep.Labels[endpoint.ResourceLabelKey], "should set correct resource label") + } +} + +func TestOcpRouteSource(t *testing.T) { + suite.Run(t, new(OCPRouteSuite)) + t.Run("Interface", testOcpRouteSourceImplementsSource) + t.Run("NewOcpRouteSource", testOcpRouteSourceNewOcpRouteSource) + t.Run("Endpoints", testOcpRouteSourceEndpoints) +} + +// testOcpRouteSourceImplementsSource tests that ocpRouteSource is a valid Source. +func testOcpRouteSourceImplementsSource(t *testing.T) { + assert.Implements(t, (*Source)(nil), new(ocpRouteSource)) +} + +// testOcpRouteSourceNewOcpRouteSource tests that NewOcpRouteSource doesn't return an error. +func testOcpRouteSourceNewOcpRouteSource(t *testing.T) { + for _, ti := range []struct { + title string + annotationFilter string + fqdnTemplate string + expectError bool + }{ + { + title: "invalid template", + expectError: true, + fqdnTemplate: "{{.Name", + }, + { + title: "valid empty template", + expectError: false, + }, + { + title: "valid template", + expectError: false, + fqdnTemplate: "{{.Name}}-{{.Namespace}}.ext-dns.test.com", + }, + { + title: "non-empty annotation filter label", + expectError: false, + annotationFilter: "kubernetes.io/ingress.class=nginx", + }, + } { + t.Run(ti.title, func(t *testing.T) { + _, err := NewOcpRouteSource( + fake.NewSimpleClientset(), + "", + ti.annotationFilter, + ti.fqdnTemplate, + false, + false, + ) + + if ti.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} + +// testOcpRouteSourceEndpoints tests that various OCP routes generate the correct endpoints. +func testOcpRouteSourceEndpoints(t *testing.T) { + for _, tc := range []struct { + title string + targetNamespace string + annotationFilter string + fqdnTemplate string + ignoreHostnameAnnotation bool + ocpRoute *routev1.Route + expected []*endpoint.Endpoint + expectError bool + }{ + { + title: "route with basic hostname and route status target", + targetNamespace: "", + annotationFilter: "", + fqdnTemplate: "", + ignoreHostnameAnnotation: false, + ocpRoute: &routev1.Route{ + Spec: routev1.RouteSpec{ + Host: "my-domain.com", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "route-with-target", + Annotations: map[string]string{}, + }, + Status: routev1.RouteStatus{ + Ingress: []routev1.RouteIngress{ + { + RouterCanonicalHostname: "apps.my-domain.com", + }, + }, + }, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "my-domain.com", + Targets: []string{ + "apps.my-domain.com", + }, + }, + }, + expectError: false, + }, + { + title: "route with incorrect externalDNS controller annotation", + targetNamespace: "", + annotationFilter: "", + fqdnTemplate: "", + ignoreHostnameAnnotation: false, + ocpRoute: &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "route-with-ignore-annotation", + Annotations: map[string]string{ + "external-dns.alpha.kubernetes.io/controller": "foo", + }, + }, + }, + expected: []*endpoint.Endpoint{}, + expectError: false, + }, + { + title: "route with basic hostname and annotation target", + targetNamespace: "", + annotationFilter: "", + fqdnTemplate: "", + ignoreHostnameAnnotation: false, + ocpRoute: &routev1.Route{ + Spec: routev1.RouteSpec{ + Host: "my-annotation-domain.com", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "route-with-annotation-target", + Annotations: map[string]string{ + "external-dns.alpha.kubernetes.io/target": "my.site.foo.com", + }, + }, + }, + expected: []*endpoint.Endpoint{ + { + DNSName: "my-annotation-domain.com", + Targets: []string{ + "my.site.foo.com", + }, + }, + }, + expectError: false, + }, + } { + t.Run(tc.title, func(t *testing.T) { + // Create a Kubernetes testing client + fakeClient := fake.NewSimpleClientset() + + _, err := fakeClient.RouteV1().Routes(tc.ocpRoute.Namespace).Create(context.Background(), tc.ocpRoute, metav1.CreateOptions{}) + require.NoError(t, err) + + source, err := NewOcpRouteSource( + fakeClient, + "", + "", + "{{.Name}}", + false, + false, + ) + require.NoError(t, err) + + var res []*endpoint.Endpoint + + // wait up to a few seconds for new resources to appear in informer cache. + err = poll(time.Second, 3*time.Second, func() (bool, error) { + res, err = source.Endpoints(context.Background()) + if err != nil { + // stop waiting if we get an error + return true, err + } + return len(res) >= len(tc.expected), nil + }) + + if tc.expectError { + require.Error(t, err) + } else { + require.NoError(t, err) + } + + // Validate returned endpoints against desired endpoints. + validateEndpoints(t, res, tc.expected) + }) + } +} From 3c7813088a0cda86ba9e79a2a3b249ee18af3a3c Mon Sep 17 00:00:00 2001 From: Aron Parsons Date: Tue, 15 Jun 2021 15:28:26 -0400 Subject: [PATCH 163/175] rfc2136: add batch size support Signed-off-by: Aron Parsons --- main.go | 2 +- pkg/apis/externaldns/types.go | 3 + provider/rfc2136/rfc2136.go | 160 ++++++++++++++++++++++++---------- 3 files changed, 117 insertions(+), 48 deletions(-) diff --git a/main.go b/main.go index bc6905956..911fdfb26 100644 --- a/main.go +++ b/main.go @@ -293,7 +293,7 @@ func main() { p, err = oci.NewOCIProvider(*config, domainFilter, zoneIDFilter, cfg.DryRun) } case "rfc2136": - p, err = rfc2136.NewRfc2136Provider(cfg.RFC2136Host, cfg.RFC2136Port, cfg.RFC2136Zone, cfg.RFC2136Insecure, cfg.RFC2136TSIGKeyName, cfg.RFC2136TSIGSecret, cfg.RFC2136TSIGSecretAlg, cfg.RFC2136TAXFR, domainFilter, cfg.DryRun, cfg.RFC2136MinTTL, cfg.RFC2136GSSTSIG, cfg.RFC2136KerberosUsername, cfg.RFC2136KerberosPassword, cfg.RFC2136KerberosRealm, nil) + p, err = rfc2136.NewRfc2136Provider(cfg.RFC2136Host, cfg.RFC2136Port, cfg.RFC2136Zone, cfg.RFC2136Insecure, cfg.RFC2136TSIGKeyName, cfg.RFC2136TSIGSecret, cfg.RFC2136TSIGSecretAlg, cfg.RFC2136TAXFR, domainFilter, cfg.DryRun, cfg.RFC2136MinTTL, cfg.RFC2136GSSTSIG, cfg.RFC2136KerberosUsername, cfg.RFC2136KerberosPassword, cfg.RFC2136KerberosRealm, cfg.RFC2136BatchChangeSize, nil) case "ns1": p, err = ns1.NewNS1Provider( ns1.NS1Config{ diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 8655dc480..efb3b644a 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -156,6 +156,7 @@ type Config struct { RFC2136TSIGSecretAlg string RFC2136TAXFR bool RFC2136MinTTL time.Duration + RFC2136BatchChangeSize int NS1Endpoint string NS1IgnoreSSL bool NS1MinTTLSeconds int @@ -275,6 +276,7 @@ var defaultConfig = &Config{ RFC2136TSIGSecretAlg: "", RFC2136TAXFR: true, RFC2136MinTTL: 0, + RFC2136BatchChangeSize: 50, NS1Endpoint: "", NS1IgnoreSSL: false, TransIPAccountName: "", @@ -455,6 +457,7 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("rfc2136-kerberos-username", "When using the RFC2136 provider with GSS-TSIG, specify the username of the user with permissions to update DNS records (required when --rfc2136-gss-tsig=true)").Default(defaultConfig.RFC2136KerberosUsername).StringVar(&cfg.RFC2136KerberosUsername) app.Flag("rfc2136-kerberos-password", "When using the RFC2136 provider with GSS-TSIG, specify the password of the user with permissions to update DNS records (required when --rfc2136-gss-tsig=true)").Default(defaultConfig.RFC2136KerberosPassword).StringVar(&cfg.RFC2136KerberosPassword) app.Flag("rfc2136-kerberos-realm", "When using the RFC2136 provider with GSS-TSIG, specify the realm of the user with permissions to update DNS records (required when --rfc2136-gss-tsig=true)").Default(defaultConfig.RFC2136KerberosRealm).StringVar(&cfg.RFC2136KerberosRealm) + app.Flag("rfc2136-batch-change-size", "When using the RFC2136 provider, set the maximum number of changes that will be applied in each batch.").Default(strconv.Itoa(defaultConfig.RFC2136BatchChangeSize)).IntVar(&cfg.RFC2136BatchChangeSize) // Flags related to TransIP provider app.Flag("transip-account", "When using the TransIP provider, specify the account name (required when --provider=transip)").Default(defaultConfig.TransIPAccountName).StringVar(&cfg.TransIPAccountName) diff --git a/provider/rfc2136/rfc2136.go b/provider/rfc2136/rfc2136.go index 0ce9b8cc5..50ee6e7b5 100644 --- a/provider/rfc2136/rfc2136.go +++ b/provider/rfc2136/rfc2136.go @@ -48,14 +48,15 @@ const ( // rfc2136 provider type type rfc2136Provider struct { provider.BaseProvider - nameserver string - zoneName string - tsigKeyName string - tsigSecret string - tsigSecretAlg string - insecure bool - axfr bool - minTTL time.Duration + nameserver string + zoneName string + tsigKeyName string + tsigSecret string + tsigSecretAlg string + insecure bool + axfr bool + minTTL time.Duration + batchChangeSize int // options specific to rfc3645 gss-tsig support gssTsig bool @@ -85,7 +86,7 @@ type rfc2136Actions interface { } // NewRfc2136Provider is a factory function for OpenStack rfc2136 providers -func NewRfc2136Provider(host string, port int, zoneName string, insecure bool, keyName string, secret string, secretAlg string, axfr bool, domainFilter endpoint.DomainFilter, dryRun bool, minTTL time.Duration, gssTsig bool, krb5Username string, krb5Password string, krb5Realm string, actions rfc2136Actions) (provider.Provider, error) { +func NewRfc2136Provider(host string, port int, zoneName string, insecure bool, keyName string, secret string, secretAlg string, axfr bool, domainFilter endpoint.DomainFilter, dryRun bool, minTTL time.Duration, gssTsig bool, krb5Username string, krb5Password string, krb5Realm string, batchChangeSize int, actions rfc2136Actions) (provider.Provider, error) { secretAlgChecked, ok := tsigAlgs[secretAlg] if !ok && !insecure && !gssTsig { return nil, errors.Errorf("%s is not supported TSIG algorithm", secretAlg) @@ -96,17 +97,18 @@ func NewRfc2136Provider(host string, port int, zoneName string, insecure bool, k } r := &rfc2136Provider{ - nameserver: net.JoinHostPort(host, strconv.Itoa(port)), - zoneName: dns.Fqdn(zoneName), - insecure: insecure, - gssTsig: gssTsig, - krb5Username: krb5Username, - krb5Password: krb5Password, - krb5Realm: strings.ToUpper(krb5Realm), - domainFilter: domainFilter, - dryRun: dryRun, - axfr: axfr, - minTTL: minTTL, + nameserver: net.JoinHostPort(host, strconv.Itoa(port)), + zoneName: dns.Fqdn(zoneName), + insecure: insecure, + gssTsig: gssTsig, + krb5Username: krb5Username, + krb5Password: krb5Password, + krb5Realm: strings.ToUpper(krb5Realm), + domainFilter: domainFilter, + dryRun: dryRun, + axfr: axfr, + minTTL: minTTL, + batchChangeSize: batchChangeSize, } if actions != nil { r.actions = actions @@ -246,40 +248,88 @@ func (r rfc2136Provider) List() ([]dns.RR, error) { func (r rfc2136Provider) ApplyChanges(ctx context.Context, changes *plan.Changes) error { log.Debugf("ApplyChanges (Create: %d, UpdateOld: %d, UpdateNew: %d, Delete: %d)", len(changes.Create), len(changes.UpdateOld), len(changes.UpdateNew), len(changes.Delete)) - m := new(dns.Msg) - m.SetUpdate(r.zoneName) + var errors []error - for _, ep := range changes.Create { - if !r.domainFilter.Match(ep.DNSName) { - log.Debugf("Skipping record %s because it was filtered out by the specified --domain-filter", ep.DNSName) - continue + for c, chunk := range chunkBy(changes.Create, r.batchChangeSize) { + log.Debugf("Processing batch %d of create changes", c) + + m := new(dns.Msg) + m.SetUpdate(r.zoneName) + + for _, ep := range chunk { + if !r.domainFilter.Match(ep.DNSName) { + log.Debugf("Skipping record %s because it was filtered out by the specified --domain-filter", ep.DNSName) + continue + } + + r.AddRecord(m, ep) } - r.AddRecord(m, ep) - } - for i, ep := range changes.UpdateNew { - if !r.domainFilter.Match(ep.DNSName) { - log.Debugf("Skipping record %s because it was filtered out by the specified --domain-filter", ep.DNSName) - continue + // only send if there are records available + if len(m.Ns) > 0 { + err := r.actions.SendMessage(m) + if err != nil { + log.Errorf("RFC2136 update failed: %v", err) + errors = append(errors, err) + continue + } } - - r.UpdateRecord(m, changes.UpdateOld[i], ep) - } - for _, ep := range changes.Delete { - if !r.domainFilter.Match(ep.DNSName) { - log.Debugf("Skipping record %s because it was filtered out by the specified --domain-filter", ep.DNSName) - continue - } - - r.RemoveRecord(m, ep) } - // only send if there are records available - if len(m.Ns) > 0 { - err := r.actions.SendMessage(m) - if err != nil { - return fmt.Errorf("RFC2136 update failed: %v", err) + for c, chunk := range chunkBy(changes.UpdateNew, r.batchChangeSize) { + log.Debugf("Processing batch %d of update changes", c) + + m := new(dns.Msg) + m.SetUpdate(r.zoneName) + + for i, ep := range chunk { + if !r.domainFilter.Match(ep.DNSName) { + log.Debugf("Skipping record %s because it was filtered out by the specified --domain-filter", ep.DNSName) + continue + } + + r.UpdateRecord(m, changes.UpdateOld[i], ep) } + + // only send if there are records available + if len(m.Ns) > 0 { + err := r.actions.SendMessage(m) + if err != nil { + log.Errorf("RFC2136 update failed: %v", err) + errors = append(errors, err) + continue + } + } + } + + for c, chunk := range chunkBy(changes.Delete, r.batchChangeSize) { + log.Debugf("Processing batch %d of delete changes", c) + + m := new(dns.Msg) + m.SetUpdate(r.zoneName) + + for _, ep := range chunk { + if !r.domainFilter.Match(ep.DNSName) { + log.Debugf("Skipping record %s because it was filtered out by the specified --domain-filter", ep.DNSName) + continue + } + + r.RemoveRecord(m, ep) + } + + // only send if there are records available + if len(m.Ns) > 0 { + err := r.actions.SendMessage(m) + if err != nil { + log.Errorf("RFC2136 update failed: %v", err) + errors = append(errors, err) + continue + } + } + } + + if len(errors) > 0 { + return fmt.Errorf("RFC2136 had errors in one or more of its batches: %v", errors) } return nil @@ -388,3 +438,19 @@ func (r rfc2136Provider) SendMessage(msg *dns.Msg) error { log.Debugf("SendMessage.success") return nil } + +func chunkBy(slice []*endpoint.Endpoint, chunkSize int) [][]*endpoint.Endpoint { + var chunks [][]*endpoint.Endpoint + + for i := 0; i < len(slice); i += chunkSize { + end := i + chunkSize + + if end > len(slice) { + end = len(slice) + } + + chunks = append(chunks, slice[i:end]) + } + + return chunks +} From fdbaef499a2ba80d521e8e5393c0b4a703dc966a Mon Sep 17 00:00:00 2001 From: Jeffrey Egeland Date: Wed, 23 Jun 2021 16:34:04 -0400 Subject: [PATCH 164/175] rfc2136: add config validation for batch size --- pkg/apis/externaldns/validation/validation.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/apis/externaldns/validation/validation.go b/pkg/apis/externaldns/validation/validation.go index 3251a7b09..b93b84aad 100644 --- a/pkg/apis/externaldns/validation/validation.go +++ b/pkg/apis/externaldns/validation/validation.go @@ -96,6 +96,10 @@ func ValidateConfig(cfg *externaldns.Config) error { return errors.New("--rfc2136-kerberos-realm, --rfc2136-kerberos-username, and --rfc2136-kerberos-password are required when specifying --rfc2136-gss-tsig option") } } + + if cfg.RFC2136BatchChangeSize < 1 { + return errors.New("Batch Size specified for rfc2136 cannot be less than 1") + } } if cfg.IgnoreHostnameAnnotation && cfg.FQDNTemplate == "" { From 45e28261d08d06fdbf4f347a13cdfe2cbdc7f0f4 Mon Sep 17 00:00:00 2001 From: Jeffrey Egeland Date: Wed, 23 Jun 2021 16:34:34 -0400 Subject: [PATCH 165/175] rfc2136: add unit tests for batch size changes --- pkg/apis/externaldns/types_test.go | 4 ++++ pkg/apis/externaldns/validation/validation.go | 2 +- .../externaldns/validation/validation_test.go | 24 +++++++++++++++++++ provider/rfc2136/rfc2136_test.go | 20 +++++++++++++++- 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/pkg/apis/externaldns/types_test.go b/pkg/apis/externaldns/types_test.go index c9782f284..50144cb97 100644 --- a/pkg/apis/externaldns/types_test.go +++ b/pkg/apis/externaldns/types_test.go @@ -113,6 +113,7 @@ var ( TransIPPrivateKeyFile: "", DigitalOceanAPIPageSize: 50, ManagedDNSRecordTypes: []string{endpoint.RecordTypeA, endpoint.RecordTypeCNAME}, + RFC2136BatchChangeSize: 50, } overriddenConfig = &Config{ @@ -205,6 +206,7 @@ var ( TransIPPrivateKeyFile: "/path/to/transip.key", DigitalOceanAPIPageSize: 100, ManagedDNSRecordTypes: []string{endpoint.RecordTypeA, endpoint.RecordTypeCNAME}, + RFC2136BatchChangeSize: 100, } ) @@ -321,6 +323,7 @@ func TestParseFlags(t *testing.T) { "--transip-account=transip", "--transip-keyfile=/path/to/transip.key", "--digitalocean-api-page-size=100", + "--rfc2136-batch-change-size=100", }, envVars: map[string]string{}, expected: overriddenConfig, @@ -417,6 +420,7 @@ func TestParseFlags(t *testing.T) { "EXTERNAL_DNS_TRANSIP_ACCOUNT": "transip", "EXTERNAL_DNS_TRANSIP_KEYFILE": "/path/to/transip.key", "EXTERNAL_DNS_DIGITALOCEAN_API_PAGE_SIZE": "100", + "EXTERNAL_DNS_RFC2136_BATCH_CHANGE_SIZE": "100", }, expected: overriddenConfig, }, diff --git a/pkg/apis/externaldns/validation/validation.go b/pkg/apis/externaldns/validation/validation.go index b93b84aad..9f8c3889a 100644 --- a/pkg/apis/externaldns/validation/validation.go +++ b/pkg/apis/externaldns/validation/validation.go @@ -98,7 +98,7 @@ func ValidateConfig(cfg *externaldns.Config) error { } if cfg.RFC2136BatchChangeSize < 1 { - return errors.New("Batch Size specified for rfc2136 cannot be less than 1") + return errors.New("batch size specified for rfc2136 cannot be less than 1") } } diff --git a/pkg/apis/externaldns/validation/validation_test.go b/pkg/apis/externaldns/validation/validation_test.go index 8bb6fdafa..55f5e6354 100644 --- a/pkg/apis/externaldns/validation/validation_test.go +++ b/pkg/apis/externaldns/validation/validation_test.go @@ -132,6 +132,21 @@ func TestValidateBadRfc2136Config(t *testing.T) { cfg.Sources = []string{"test-source"} cfg.Provider = "rfc2136" cfg.RFC2136MinTTL = -1 + cfg.RFC2136BatchChangeSize = 50 + + err := ValidateConfig(cfg) + + assert.NotNil(t, err) +} + +func TestValidateBadRfc2136Batch(t *testing.T) { + cfg := externaldns.NewConfig() + + cfg.LogFormat = "json" + cfg.Sources = []string{"test-source"} + cfg.Provider = "rfc2136" + cfg.RFC2136MinTTL = 3600 + cfg.RFC2136BatchChangeSize = 0 err := ValidateConfig(cfg) @@ -145,6 +160,7 @@ func TestValidateGoodRfc2136Config(t *testing.T) { cfg.Sources = []string{"test-source"} cfg.Provider = "rfc2136" cfg.RFC2136MinTTL = 3600 + cfg.RFC2136BatchChangeSize = 50 err := ValidateConfig(cfg) @@ -162,6 +178,7 @@ func TestValidateBadRfc2136GssTsigConfig(t *testing.T) { RFC2136KerberosUsername: "test-user", RFC2136KerberosPassword: "", RFC2136MinTTL: 3600, + RFC2136BatchChangeSize: 50, }, { LogFormat: "json", @@ -172,6 +189,7 @@ func TestValidateBadRfc2136GssTsigConfig(t *testing.T) { RFC2136KerberosUsername: "", RFC2136KerberosPassword: "test-pass", RFC2136MinTTL: 3600, + RFC2136BatchChangeSize: 50, }, { LogFormat: "json", @@ -183,6 +201,7 @@ func TestValidateBadRfc2136GssTsigConfig(t *testing.T) { RFC2136KerberosUsername: "test-user", RFC2136KerberosPassword: "test-pass", RFC2136MinTTL: 3600, + RFC2136BatchChangeSize: 50, }, { LogFormat: "json", @@ -193,6 +212,7 @@ func TestValidateBadRfc2136GssTsigConfig(t *testing.T) { RFC2136KerberosUsername: "test-user", RFC2136KerberosPassword: "", RFC2136MinTTL: 3600, + RFC2136BatchChangeSize: 50, }, { LogFormat: "json", @@ -203,6 +223,7 @@ func TestValidateBadRfc2136GssTsigConfig(t *testing.T) { RFC2136KerberosUsername: "", RFC2136KerberosPassword: "test-pass", RFC2136MinTTL: 3600, + RFC2136BatchChangeSize: 50, }, { LogFormat: "json", @@ -214,6 +235,7 @@ func TestValidateBadRfc2136GssTsigConfig(t *testing.T) { RFC2136KerberosUsername: "test-user", RFC2136KerberosPassword: "test-pass", RFC2136MinTTL: 3600, + RFC2136BatchChangeSize: 50, }, { LogFormat: "json", @@ -224,6 +246,7 @@ func TestValidateBadRfc2136GssTsigConfig(t *testing.T) { RFC2136KerberosUsername: "test-user", RFC2136KerberosPassword: "test-pass", RFC2136MinTTL: 3600, + RFC2136BatchChangeSize: 50, }, } @@ -246,6 +269,7 @@ func TestValidateGoodRfc2136GssTsigConfig(t *testing.T) { RFC2136KerberosUsername: "test-user", RFC2136KerberosPassword: "test-pass", RFC2136MinTTL: 3600, + RFC2136BatchChangeSize: 50, }, } diff --git a/provider/rfc2136/rfc2136_test.go b/provider/rfc2136/rfc2136_test.go index 59d3ea818..89e3b9012 100644 --- a/provider/rfc2136/rfc2136_test.go +++ b/provider/rfc2136/rfc2136_test.go @@ -95,7 +95,7 @@ func (r *rfc2136Stub) IncomeTransfer(m *dns.Msg, a string) (env chan *dns.Envelo } func createRfc2136StubProvider(stub *rfc2136Stub) (provider.Provider, error) { - return NewRfc2136Provider("", 0, "", false, "key", "secret", "hmac-sha512", true, endpoint.DomainFilter{}, false, 300*time.Second, false, "", "", "", stub) + return NewRfc2136Provider("", 0, "", false, "key", "secret", "hmac-sha512", true, endpoint.DomainFilter{}, false, 300*time.Second, false, "", "", "", 50, stub) } func extractAuthoritySectionFromMessage(msg fmt.Stringer) []string { @@ -326,6 +326,24 @@ func TestRfc2136ApplyChangesWithUpdate(t *testing.T) { } +func TestChunkBy(t *testing.T) { + var records []*endpoint.Endpoint + + for i := 0; i < 10; i++ { + records = append(records, &endpoint.Endpoint{ + DNSName: "v1.foo.com", + RecordType: "A", + Targets: []string{"1.1.2.2"}, + RecordTTL: endpoint.TTL(400), + }) + } + + chunks := chunkBy(records, 2) + if len(chunks) != 5 { + t.Errorf("incorrect number of chunks returned") + } +} + func contains(arr []*endpoint.Endpoint, name string) bool { for _, a := range arr { if a.DNSName == name { From bc7aa5abeb2ea11f826d2442506ad7d990531008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nick=20J=C3=BCttner?= Date: Wed, 30 Jun 2021 17:30:26 +0200 Subject: [PATCH 166/175] Update docs/tutorials/scaleway.md --- docs/tutorials/scaleway.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/scaleway.md b/docs/tutorials/scaleway.md index d9215bcce..9c1c04abf 100644 --- a/docs/tutorials/scaleway.md +++ b/docs/tutorials/scaleway.md @@ -52,7 +52,7 @@ spec: spec: containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.6 + image: k8s.gcr.io/external-dns/external-dns:v0.8.0 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. From 3754701ab458f2331891b50d739b11930e619226 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nick=20J=C3=BCttner?= Date: Wed, 30 Jun 2021 17:30:31 +0200 Subject: [PATCH 167/175] Update docs/tutorials/scaleway.md --- docs/tutorials/scaleway.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/scaleway.md b/docs/tutorials/scaleway.md index 9c1c04abf..f564bef1f 100644 --- a/docs/tutorials/scaleway.md +++ b/docs/tutorials/scaleway.md @@ -118,7 +118,7 @@ spec: serviceAccountName: external-dns containers: - name: external-dns - image: k8s.gcr.io/external-dns/external-dns:v0.7.6 + image: k8s.gcr.io/external-dns/external-dns:v0.8.0 args: - --source=service # ingress is also possible - --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. From 9bccccf414555cdd89b787858b6823b8aab9194b Mon Sep 17 00:00:00 2001 From: Anand Patel Date: Tue, 18 May 2021 17:19:12 -0700 Subject: [PATCH 168/175] add ignoreIngressRulesSpec for ingress source --- source/ingress.go | 16 ++++++++++------ source/ingress_test.go | 20 ++++++++++++++++---- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/source/ingress.go b/source/ingress.go index 23bea7c29..0ca558eb7 100644 --- a/source/ingress.go +++ b/source/ingress.go @@ -61,6 +61,7 @@ type ingressSource struct { ignoreHostnameAnnotation bool ingressInformer extinformers.IngressInformer ignoreIngressTLSSpec bool + ignoreIngressRulesSpec bool } // NewIngressSource creates a new ingressSource with the given config. @@ -138,7 +139,7 @@ func (sc *ingressSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, e continue } - ingEndpoints := endpointsFromIngress(ing, sc.ignoreHostnameAnnotation, sc.ignoreIngressTLSSpec) + ingEndpoints := endpointsFromIngress(ing, sc.ignoreHostnameAnnotation, sc.ignoreIngressTLSSpec, sc.ignoreIngressRulesSpec) // apply template if host is missing on ingress if (sc.combineFQDNAnnotation || len(ingEndpoints) == 0) && sc.fqdnTemplate != nil { @@ -246,7 +247,7 @@ func (sc *ingressSource) setDualstackLabel(ingress *v1beta1.Ingress, endpoints [ } // endpointsFromIngress extracts the endpoints from ingress object -func endpointsFromIngress(ing *v1beta1.Ingress, ignoreHostnameAnnotation bool, ignoreIngressTLSSpec bool) []*endpoint.Endpoint { +func endpointsFromIngress(ing *v1beta1.Ingress, ignoreHostnameAnnotation bool, ignoreIngressTLSSpec bool, ignoreIngressRulesSpec bool) []*endpoint.Endpoint { ttl, err := getTTLFromAnnotations(ing.Annotations) if err != nil { log.Warn(err) @@ -262,11 +263,14 @@ func endpointsFromIngress(ing *v1beta1.Ingress, ignoreHostnameAnnotation bool, i // Gather endpoints defined on hosts sections of the ingress var definedHostsEndpoints []*endpoint.Endpoint - for _, rule := range ing.Spec.Rules { - if rule.Host == "" { - continue + // Skip endpoints if we do not want entries from Rules section + if !ignoreIngressRulesSpec { + for _, rule := range ing.Spec.Rules { + if rule.Host == "" { + continue + } + definedHostsEndpoints = append(definedHostsEndpoints, endpointsForHostname(rule.Host, targets, ttl, providerSpecific, setIdentifier)...) } - definedHostsEndpoints = append(definedHostsEndpoints, endpointsForHostname(rule.Host, targets, ttl, providerSpecific, setIdentifier)...) } // Skip endpoints if we do not want entries from tls spec section diff --git a/source/ingress_test.go b/source/ingress_test.go index 0840e241b..c7f3325db 100644 --- a/source/ingress_test.go +++ b/source/ingress_test.go @@ -149,9 +149,12 @@ func TestNewIngressSource(t *testing.T) { func testEndpointsFromIngress(t *testing.T) { for _, ti := range []struct { - title string - ingress fakeIngress - expected []*endpoint.Endpoint + title string + ingress fakeIngress + ignoreHostnameAnnotation bool + ignoreIngressTLSSpec bool + ignoreIngressRulesSpec bool + expected []*endpoint.Endpoint }{ { title: "one rule.host one lb.hostname", @@ -221,10 +224,19 @@ func testEndpointsFromIngress(t *testing.T) { }, expected: []*endpoint.Endpoint{}, }, + { + title: "ignore rules with one rule.host one lb.hostname", + ingress: fakeIngress{ + dnsnames: []string{"test"}, // Kubernetes requires removal of trailing dot + hostnames: []string{"lb.com"}, // Kubernetes omits the trailing dot + }, + expected: []*endpoint.Endpoint{}, + ignoreIngressRulesSpec: true, + }, } { t.Run(ti.title, func(t *testing.T) { realIngress := ti.ingress.Ingress() - validateEndpoints(t, endpointsFromIngress(realIngress, false, false), ti.expected) + validateEndpoints(t, endpointsFromIngress(realIngress, ti.ignoreHostnameAnnotation, ti.ignoreIngressTLSSpec, ti.ignoreIngressRulesSpec), ti.expected) }) } } From 509a07c493a3317b88cc2c446b91cf8e4488c957 Mon Sep 17 00:00:00 2001 From: Anand Patel Date: Tue, 18 May 2021 17:34:03 -0700 Subject: [PATCH 169/175] create new source ingress config option IgnoreIngressRulesSpec --- main.go | 1 + pkg/apis/externaldns/types.go | 3 +++ pkg/apis/externaldns/types_test.go | 3 +++ source/ingress.go | 3 ++- source/ingress_test.go | 26 +++++++++++++++++++++++++- source/store.go | 3 ++- 6 files changed, 36 insertions(+), 3 deletions(-) diff --git a/main.go b/main.go index fb6f72ff1..51ba35b23 100644 --- a/main.go +++ b/main.go @@ -108,6 +108,7 @@ func main() { CombineFQDNAndAnnotation: cfg.CombineFQDNAndAnnotation, IgnoreHostnameAnnotation: cfg.IgnoreHostnameAnnotation, IgnoreIngressTLSSpec: cfg.IgnoreIngressTLSSpec, + IgnoreIngressRulesSpec: cfg.IgnoreIngressRulesSpec, Compatibility: cfg.Compatibility, PublishInternal: cfg.PublishInternal, PublishHostIP: cfg.PublishHostIP, diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 7dac065b5..c2c8fca16 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -57,6 +57,7 @@ type Config struct { CombineFQDNAndAnnotation bool IgnoreHostnameAnnotation bool IgnoreIngressTLSSpec bool + IgnoreIngressRulesSpec bool Compatibility string PublishInternal bool PublishHostIP bool @@ -187,6 +188,7 @@ var defaultConfig = &Config{ CombineFQDNAndAnnotation: false, IgnoreHostnameAnnotation: false, IgnoreIngressTLSSpec: false, + IgnoreIngressRulesSpec: false, Compatibility: "", PublishInternal: false, PublishHostIP: false, @@ -361,6 +363,7 @@ func (cfg *Config) ParseFlags(args []string) error { app.Flag("ignore-hostname-annotation", "Ignore hostname annotation when generating DNS names, valid only when using fqdn-template is set (optional, default: false)").BoolVar(&cfg.IgnoreHostnameAnnotation) app.Flag("ignore-ingress-tls-spec", "Ignore tls spec section in ingresses resources, applicable only for ingress sources (optional, default: false)").BoolVar(&cfg.IgnoreIngressTLSSpec) app.Flag("compatibility", "Process annotation semantics from legacy implementations (optional, options: mate, molecule, kops-dns-controller)").Default(defaultConfig.Compatibility).EnumVar(&cfg.Compatibility, "", "mate", "molecule", "kops-dns-controller") + app.Flag("ignore-ingress-rules-spec", "Ignore rules spec section in ingresses resources, applicable only for ingress sources (optional, default: false)").BoolVar(&cfg.IgnoreIngressRulesSpec) app.Flag("publish-internal-services", "Allow external-dns to publish DNS records for ClusterIP services (optional)").BoolVar(&cfg.PublishInternal) app.Flag("publish-host-ip", "Allow external-dns to publish host-ip for headless services (optional)").BoolVar(&cfg.PublishHostIP) app.Flag("always-publish-not-ready-addresses", "Always publish also not ready addresses for headless services (optional)").BoolVar(&cfg.AlwaysPublishNotReadyAddresses) diff --git a/pkg/apis/externaldns/types_test.go b/pkg/apis/externaldns/types_test.go index c9782f284..a9319e202 100644 --- a/pkg/apis/externaldns/types_test.go +++ b/pkg/apis/externaldns/types_test.go @@ -126,6 +126,7 @@ var ( Namespace: "namespace", IgnoreHostnameAnnotation: true, IgnoreIngressTLSSpec: true, + IgnoreIngressRulesSpec: true, FQDNTemplate: "{{.Name}}.service.example.com", Compatibility: "mate", Provider: "google", @@ -240,6 +241,7 @@ func TestParseFlags(t *testing.T) { "--fqdn-template={{.Name}}.service.example.com", "--ignore-hostname-annotation", "--ignore-ingress-tls-spec", + "--ignore-ingress-rules-spec", "--compatibility=mate", "--provider=google", "--google-project=project", @@ -340,6 +342,7 @@ func TestParseFlags(t *testing.T) { "EXTERNAL_DNS_FQDN_TEMPLATE": "{{.Name}}.service.example.com", "EXTERNAL_DNS_IGNORE_HOSTNAME_ANNOTATION": "1", "EXTERNAL_DNS_IGNORE_INGRESS_TLS_SPEC": "1", + "EXTERNAL_DNS_IGNORE_INGRESS_RULES_SPEC": "1", "EXTERNAL_DNS_COMPATIBILITY": "mate", "EXTERNAL_DNS_PROVIDER": "google", "EXTERNAL_DNS_GOOGLE_PROJECT": "project", diff --git a/source/ingress.go b/source/ingress.go index 0ca558eb7..932650a7f 100644 --- a/source/ingress.go +++ b/source/ingress.go @@ -65,7 +65,7 @@ type ingressSource struct { } // NewIngressSource creates a new ingressSource with the given config. -func NewIngressSource(kubeClient kubernetes.Interface, namespace, annotationFilter string, fqdnTemplate string, combineFqdnAnnotation bool, ignoreHostnameAnnotation bool, ignoreIngressTLSSpec bool) (Source, error) { +func NewIngressSource(kubeClient kubernetes.Interface, namespace, annotationFilter string, fqdnTemplate string, combineFqdnAnnotation bool, ignoreHostnameAnnotation bool, ignoreIngressTLSSpec bool, ignoreIngressRulesSpec bool) (Source, error) { var ( tmpl *template.Template err error @@ -112,6 +112,7 @@ func NewIngressSource(kubeClient kubernetes.Interface, namespace, annotationFilt ignoreHostnameAnnotation: ignoreHostnameAnnotation, ingressInformer: ingressInformer, ignoreIngressTLSSpec: ignoreIngressTLSSpec, + ignoreIngressRulesSpec: ignoreIngressRulesSpec, } return sc, nil } diff --git a/source/ingress_test.go b/source/ingress_test.go index c7f3325db..c5bf50404 100644 --- a/source/ingress_test.go +++ b/source/ingress_test.go @@ -53,6 +53,7 @@ func (suite *IngressSuite) SetupTest() { false, false, false, + false, ) suite.NoError(err, "should initialize ingress source") @@ -137,6 +138,7 @@ func TestNewIngressSource(t *testing.T) { ti.combineFQDNAndAnnotation, false, false, + false, ) if ti.expectError { assert.Error(t, err) @@ -328,7 +330,7 @@ func testEndpointsFromIngressHostnameSourceAnnotation(t *testing.T) { } { t.Run(ti.title, func(t *testing.T) { realIngress := ti.ingress.Ingress() - validateEndpoints(t, endpointsFromIngress(realIngress, false, false), ti.expected) + validateEndpoints(t, endpointsFromIngress(realIngress, false, false, false), ti.expected) }) } } @@ -346,6 +348,7 @@ func testIngressEndpoints(t *testing.T) { combineFQDNAndAnnotation bool ignoreHostnameAnnotation bool ignoreIngressTLSSpec bool + ignoreIngressRulesSpec bool }{ { title: "no ingress", @@ -379,6 +382,26 @@ func testIngressEndpoints(t *testing.T) { }, }, }, + { + title: "ignore rules", + targetNamespace: "", + ignoreIngressRulesSpec: true, + ingressItems: []fakeIngress{ + { + name: "fake1", + namespace: namespace, + dnsnames: []string{"example.org"}, + ips: []string{"8.8.8.8"}, + }, + { + name: "fake2", + namespace: namespace, + dnsnames: []string{"new.org"}, + hostnames: []string{"lb.com"}, + }, + }, + expected: []*endpoint.Endpoint{}, + }, { title: "two simple ingresses on different namespaces", targetNamespace: "", @@ -1150,6 +1173,7 @@ func testIngressEndpoints(t *testing.T) { ti.combineFQDNAndAnnotation, ti.ignoreHostnameAnnotation, ti.ignoreIngressTLSSpec, + ti.ignoreIngressRulesSpec, ) for _, ingress := range ingresses { _, err := fakeClient.ExtensionsV1beta1().Ingresses(ingress.Namespace).Create(context.Background(), ingress, metav1.CreateOptions{}) diff --git a/source/store.go b/source/store.go index f133de4e8..82cd2f6ec 100644 --- a/source/store.go +++ b/source/store.go @@ -47,6 +47,7 @@ type Config struct { CombineFQDNAndAnnotation bool IgnoreHostnameAnnotation bool IgnoreIngressTLSSpec bool + IgnoreIngressRulesSpec bool Compatibility string PublishInternal bool PublishHostIP bool @@ -188,7 +189,7 @@ func BuildWithConfig(source string, p ClientGenerator, cfg *Config) (Source, err if err != nil { return nil, err } - return NewIngressSource(client, cfg.Namespace, cfg.AnnotationFilter, cfg.FQDNTemplate, cfg.CombineFQDNAndAnnotation, cfg.IgnoreHostnameAnnotation, cfg.IgnoreIngressTLSSpec) + return NewIngressSource(client, cfg.Namespace, cfg.AnnotationFilter, cfg.FQDNTemplate, cfg.CombineFQDNAndAnnotation, cfg.IgnoreHostnameAnnotation, cfg.IgnoreIngressTLSSpec, cfg.IgnoreIngressRulesSpec) case "pod": client, err := p.KubeClient() if err != nil { From 5f31f5806d3a6b599792a2f092641905426cf189 Mon Sep 17 00:00:00 2001 From: Goutam Tadi <8926556+goutamtadi1@users.noreply.github.com> Date: Wed, 30 Jun 2021 10:42:04 -0700 Subject: [PATCH 170/175] Remove extra `$` on clicking in `copy to clipboard` --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 139b31a98..49ee8bda2 100644 --- a/README.md +++ b/README.md @@ -175,20 +175,20 @@ from source. Next, run an application and expose it via a Kubernetes Service: ```console -$ kubectl run nginx --image=nginx --port=80 -$ kubectl expose pod nginx --port=80 --target-port=80 --type=LoadBalancer +kubectl run nginx --image=nginx --port=80 +kubectl expose pod nginx --port=80 --target-port=80 --type=LoadBalancer ``` Annotate the Service with your desired external DNS name. Make sure to change `example.org` to your domain. ```console -$ kubectl annotate service nginx "external-dns.alpha.kubernetes.io/hostname=nginx.example.org." +kubectl annotate service nginx "external-dns.alpha.kubernetes.io/hostname=nginx.example.org." ``` Optionally, you can customize the TTL value of the resulting DNS record by using the `external-dns.alpha.kubernetes.io/ttl` annotation: ```console -$ kubectl annotate service nginx "external-dns.alpha.kubernetes.io/ttl=10" +kubectl annotate service nginx "external-dns.alpha.kubernetes.io/ttl=10" ``` For more details on configuring TTL, see [here](docs/ttl.md). @@ -196,7 +196,7 @@ For more details on configuring TTL, see [here](docs/ttl.md). Use the internal-hostname annotation to create DNS records with ClusterIP as the target. ```console -$ kubectl annotate service nginx "external-dns.alpha.kubernetes.io/internal-hostname=nginx.internal.example.org." +kubectl annotate service nginx "external-dns.alpha.kubernetes.io/internal-hostname=nginx.internal.example.org." ``` If the service is not of type Loadbalancer you need the --publish-internal-services flag. @@ -204,7 +204,7 @@ If the service is not of type Loadbalancer you need the --publish-internal-servi Locally run a single sync loop of ExternalDNS. ```console -$ external-dns --registry txt --txt-owner-id my-cluster-id --provider google --google-project example-project --source service --once --dry-run +external-dns --registry txt --txt-owner-id my-cluster-id --provider google --google-project example-project --source service --once --dry-run ``` This should output the DNS records it will modify to match the managed zone with the DNS records you desire. It also assumes you are running in the `default` namespace. See the [FAQ](docs/faq.md) for more information regarding namespaces. @@ -214,13 +214,13 @@ Note: TXT records will have `my-cluster-id` value embedded. Those are used to en Once you're satisfied with the result, you can run ExternalDNS like you would run it in your cluster: as a control loop, and **not in dry-run** mode: ```console -$ external-dns --registry txt --txt-owner-id my-cluster-id --provider google --google-project example-project --source service +external-dns --registry txt --txt-owner-id my-cluster-id --provider google --google-project example-project --source service ``` Check that ExternalDNS has created the desired DNS record for your Service and that it points to its load balancer's IP. Then try to resolve it: ```console -$ dig +short nginx.example.org. +dig +short nginx.example.org. 104.155.60.49 ``` From 3dd98dda0f772fa6645f43d70b81b8e2a0e9fd63 Mon Sep 17 00:00:00 2001 From: jayonlau Date: Thu, 8 Jul 2021 23:47:59 +0800 Subject: [PATCH 171/175] Clean up extra spaces Clean up extra spaces, although these errors are not important, they affect the code specification. --- scripts/update_route53_k8s_txt_owner.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/scripts/update_route53_k8s_txt_owner.py b/scripts/update_route53_k8s_txt_owner.py index f1a0c7056..ceb1afb31 100644 --- a/scripts/update_route53_k8s_txt_owner.py +++ b/scripts/update_route53_k8s_txt_owner.py @@ -14,10 +14,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -# This is a script that we wrote to try to help the migration over to using external-dns. -# This script looks at kubernetes ingresses and services (which are the two things we have -# external-dns looking at) and compares them to existing TXT and A records in route53 to -# find out where there are gaps. It then assigns the heritage and owner TXT records where +# This is a script that we wrote to try to help the migration over to using external-dns. +# This script looks at kubernetes ingresses and services (which are the two things we have +# external-dns looking at) and compares them to existing TXT and A records in route53 to +# find out where there are gaps. It then assigns the heritage and owner TXT records where # needed so external-dns can take over managing those resources. You can modify the script # to only look at one or the other if needed. # @@ -40,8 +40,8 @@ external_dns_manages_ingresses = True config.load_kube_config() -# grab all the domains that k8s thinks it is going to -# manage (services with domainName specified and +# grab all the domains that k8s thinks it is going to +# manage (services with domainName specified and # ingress hosts) k8s_domains = [] @@ -64,7 +64,7 @@ if external_dns_manages_ingresses: r53client = boto3.client('route53') -# grab the existing route53 domains and identify gaps where a domain may be +# grab the existing route53 domains and identify gaps where a domain may be # missing a txt record pair existing_r53_txt_domains=[] existing_r53_domains=[] @@ -73,8 +73,8 @@ next_record_name, next_record_type='','' while has_next: if next_record_name is not '' and next_record_type is not '': - resource_records = r53client.list_resource_record_sets(HostedZoneId=hosted_zone_id, - StartRecordName=next_record_name, + resource_records = r53client.list_resource_record_sets(HostedZoneId=hosted_zone_id, + StartRecordName=next_record_name, StartRecordType=next_record_type) else: resource_records = r53client.list_resource_record_sets(HostedZoneId=hosted_zone_id) @@ -113,7 +113,7 @@ for r in missing_k8s_txt: print('This will create the following resources') print(change_batch) -response = input("Good to go? ") +response = input("Good to go? ") if response.lower() in ['y', 'yes', 'yup', 'ok', 'sure', 'why not', 'why not?']: print('Updating route53') From f2f8681c246cd93fb74016530df409adb37d0ffa Mon Sep 17 00:00:00 2001 From: Jaideep Bellani Date: Thu, 24 Jun 2021 15:29:25 -0500 Subject: [PATCH 172/175] bluecat: add delete functionality --- provider/bluecat/bluecat.go | 120 ++++++++++++++++++++----------- provider/bluecat/bluecat_test.go | 71 ++++++++++++++---- 2 files changed, 134 insertions(+), 57 deletions(-) diff --git a/provider/bluecat/bluecat.go b/provider/bluecat/bluecat.go index 88caf717e..c8410cf20 100644 --- a/provider/bluecat/bluecat.go +++ b/provider/bluecat/bluecat.go @@ -27,6 +27,7 @@ import ( "io/ioutil" "net/http" "os" + "regexp" "strconv" "strings" @@ -68,13 +69,13 @@ type GatewayClient interface { getCNAMERecord(name string, record *BluecatCNAMERecord) error createHostRecord(zone string, req *bluecatCreateHostRecordRequest) (res interface{}, err error) createCNAMERecord(zone string, req *bluecatCreateCNAMERecordRequest) (res interface{}, err error) - deleteHostRecord(name string) (err error) - deleteCNAMERecord(name string) (err error) + deleteHostRecord(name string, zone string) (err error) + deleteCNAMERecord(name string, zone string) (err error) buildHTTPRequest(method, url string, body io.Reader) (*http.Request, error) getTXTRecords(zone string, records *[]BluecatTXTRecord) error getTXTRecord(name string, record *BluecatTXTRecord) error createTXTRecord(zone string, req *bluecatCreateTXTRecordRequest) (res interface{}, err error) - deleteTXTRecord(name string) error + deleteTXTRecord(name string, zone string) error } // GatewayClientConfig defines new client on bluecat gateway @@ -114,9 +115,9 @@ type BluecatCNAMERecord struct { // BluecatTXTRecord defines dns TXT record type BluecatTXTRecord struct { - ID int `json:"id"` - Name string `json:"name"` - Text string `json:"text"` + ID int `json:"id"` + Name string `json:"name"` + Properties string `json:"properties"` } type bluecatRecordSet struct { @@ -201,31 +202,52 @@ func (p *BluecatProvider) Records(ctx context.Context) (endpoints []*endpoint.En return nil, errors.Wrap(err, "could not fetch zones") } + // Parsing Text records first, so we can get the owner from them. for _, zone := range zones { log.Debugf("fetching records from zone '%s'", zone) + + var resT []BluecatTXTRecord + err = p.gatewayClient.getTXTRecords(zone, &resT) + if err != nil { + return nil, errors.Wrapf(err, "could not fetch TXT records for zone: %v", zone) + } + for _, rec := range resT { + tempEndpoint := endpoint.NewEndpoint(rec.Name, endpoint.RecordTypeTXT, rec.Properties) + tempEndpoint.Labels[endpoint.OwnerLabelKey], err = extractOwnerfromTXTRecord(rec.Properties) + if err != nil { + return nil, errors.Wrapf(err, "Error fetching owner from record") + } + endpoints = append(endpoints, tempEndpoint) + } + var resH []BluecatHostRecord err = p.gatewayClient.getHostRecords(zone, &resH) if err != nil { return nil, errors.Wrapf(err, "could not fetch host records for zone: %v", zone) } + var ep *endpoint.Endpoint for _, rec := range resH { propMap := splitProperties(rec.Properties) ips := strings.Split(propMap["addresses"], ",") - if _, ok := propMap["ttl"]; ok { - ttl, err := strconv.Atoi(propMap["ttl"]) - if err != nil { - return nil, errors.Wrapf(err, "could not parse ttl '%d' as int for host record %v", ttl, rec.Name) + for _, ip := range ips { + if _, ok := propMap["ttl"]; ok { + ttl, err := strconv.Atoi(propMap["ttl"]) + if err != nil { + return nil, errors.Wrapf(err, "could not parse ttl '%d' as int for host record %v", ttl, rec.Name) + } + ep = endpoint.NewEndpointWithTTL(propMap["absoluteName"], endpoint.RecordTypeA, endpoint.TTL(ttl), ip) + } else { + ep = endpoint.NewEndpoint(propMap["absoluteName"], endpoint.RecordTypeA, ip) } - - for _, ip := range ips { - ep := endpoint.NewEndpointWithTTL(propMap["absoluteName"], endpoint.RecordTypeA, endpoint.TTL(ttl), ip) - endpoints = append(endpoints, ep) - } - } else { - for _, ip := range ips { - ep := endpoint.NewEndpoint(propMap["absoluteName"], endpoint.RecordTypeA, ip) - endpoints = append(endpoints, ep) + for _, txtRec := range resT { + if strings.Compare(rec.Name, txtRec.Name) == 0 { + ep.Labels[endpoint.OwnerLabelKey], err = extractOwnerfromTXTRecord(txtRec.Properties) + if err != nil { + return nil, errors.Wrapf(err, "owner not parsed correctly") + } + } } + endpoints = append(endpoints, ep) } } @@ -234,6 +256,7 @@ func (p *BluecatProvider) Records(ctx context.Context) (endpoints []*endpoint.En if err != nil { return nil, errors.Wrapf(err, "could not fetch CNAME records for zone: %v", zone) } + for _, rec := range resC { propMap := splitProperties(rec.Properties) if _, ok := propMap["ttl"]; ok { @@ -241,20 +264,22 @@ func (p *BluecatProvider) Records(ctx context.Context) (endpoints []*endpoint.En if err != nil { return nil, errors.Wrapf(err, "could not parse ttl '%d' as int for CNAME record %v", ttl, rec.Name) } - endpoints = append(endpoints, endpoint.NewEndpointWithTTL(propMap["absoluteName"], endpoint.RecordTypeCNAME, endpoint.TTL(ttl), propMap["linkedRecordName"])) + ep = endpoint.NewEndpointWithTTL(propMap["absoluteName"], endpoint.RecordTypeCNAME, endpoint.TTL(ttl), propMap["linkedRecordName"]) } else { - endpoints = append(endpoints, endpoint.NewEndpoint(propMap["absoluteName"], endpoint.RecordTypeCNAME, propMap["linkedRecordName"])) + ep = endpoint.NewEndpoint(propMap["absoluteName"], endpoint.RecordTypeCNAME, propMap["linkedRecordName"]) } + for _, txtRec := range resT { + if strings.Compare(rec.Name, txtRec.Name) == 0 { + ep.Labels[endpoint.OwnerLabelKey], err = extractOwnerfromTXTRecord(txtRec.Properties) + if err != nil { + return nil, errors.Wrapf(err, "owner not parsed correctly") + } + } + } + endpoints = append(endpoints, ep) } - var resT []BluecatTXTRecord - err = p.gatewayClient.getTXTRecords(zone, &resT) - if err != nil { - return nil, errors.Wrapf(err, "could not fetch TXT records for zone: %v", zone) - } - for _, rec := range resT { - endpoints = append(endpoints, endpoint.NewEndpoint(rec.Name, endpoint.RecordTypeTXT, rec.Text)) - } + // TODO: add bluecat deploy API call here } log.Debugf("fetched %d records from Bluecat", len(endpoints)) @@ -277,8 +302,6 @@ func (p *BluecatProvider) ApplyChanges(ctx context.Context, changes *plan.Change p.deleteRecords(deleted) p.createRecords(created) - // TODO: add bluecat deploy API call here - return nil } @@ -449,15 +472,15 @@ func (p *BluecatProvider) deleteRecords(deleted bluecatChangeMap) { switch ep.RecordType { case endpoint.RecordTypeA: for _, record := range *recordSet.res.(*[]BluecatHostRecord) { - err = p.gatewayClient.deleteHostRecord(record.Name) + err = p.gatewayClient.deleteHostRecord(record.Name, zone) } case endpoint.RecordTypeCNAME: for _, record := range *recordSet.res.(*[]BluecatCNAMERecord) { - err = p.gatewayClient.deleteCNAMERecord(record.Name) + err = p.gatewayClient.deleteCNAMERecord(record.Name, zone) } case endpoint.RecordTypeTXT: for _, record := range *recordSet.res.(*[]BluecatTXTRecord) { - err = p.gatewayClient.deleteTXTRecord(record.Name) + err = p.gatewayClient.deleteTXTRecord(record.Name, zone) } } if err != nil { @@ -727,7 +750,6 @@ func (c GatewayClientConfig) getTXTRecords(zone string, records *[]BluecatTXTRec log.Debugf("Get Txt Records response: %v", resp) defer resp.Body.Close() - json.NewDecoder(resp.Body).Decode(records) log.Debugf("Get TXT Records Body: %v", records) @@ -801,6 +823,7 @@ func (c GatewayClientConfig) getTXTRecord(name string, record *BluecatTXTRecord) url := c.Host + "/api/v1/configurations/" + c.DNSConfiguration + "/views/" + c.View + "/" + "text_records/" + name + "/" + req, err := c.buildHTTPRequest("GET", url, nil) if err != nil { return errors.Wrap(err, "error building http request") @@ -812,7 +835,6 @@ func (c GatewayClientConfig) getTXTRecord(name string, record *BluecatTXTRecord) } defer resp.Body.Close() - json.NewDecoder(resp.Body).Decode(record) log.Debugf("Get TXT Record Response: %v", record) @@ -894,7 +916,7 @@ func (c GatewayClientConfig) createTXTRecord(zone string, req *bluecatCreateTXTR return res, err } -func (c GatewayClientConfig) deleteHostRecord(name string) (err error) { +func (c GatewayClientConfig) deleteHostRecord(name string, zone string) (err error) { transportCfg := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: c.SkipTLSVerify}, } @@ -904,7 +926,7 @@ func (c GatewayClientConfig) deleteHostRecord(name string) (err error) { url := c.Host + "/api/v1/configurations/" + c.DNSConfiguration + "/views/" + c.View + "/" + - "host_records/" + name + "/" + "host_records/" + name + "." + zone + "/" req, err := c.buildHTTPRequest("DELETE", url, nil) if err != nil { return errors.Wrapf(err, "error building http request: %v", name) @@ -918,7 +940,7 @@ func (c GatewayClientConfig) deleteHostRecord(name string) (err error) { return nil } -func (c GatewayClientConfig) deleteCNAMERecord(name string) (err error) { +func (c GatewayClientConfig) deleteCNAMERecord(name string, zone string) (err error) { transportCfg := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: c.SkipTLSVerify}, } @@ -928,7 +950,7 @@ func (c GatewayClientConfig) deleteCNAMERecord(name string) (err error) { url := c.Host + "/api/v1/configurations/" + c.DNSConfiguration + "/views/" + c.View + "/" + - "cname_records/" + name + "/" + "cname_records/" + name + "." + zone + "/" req, err := c.buildHTTPRequest("DELETE", url, nil) if err != nil { return errors.Wrapf(err, "error building http request: %v", name) @@ -942,7 +964,7 @@ func (c GatewayClientConfig) deleteCNAMERecord(name string) (err error) { return nil } -func (c GatewayClientConfig) deleteTXTRecord(name string) error { +func (c GatewayClientConfig) deleteTXTRecord(name string, zone string) error { transportCfg := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: c.SkipTLSVerify}, } @@ -952,7 +974,7 @@ func (c GatewayClientConfig) deleteTXTRecord(name string) error { url := c.Host + "/api/v1/configurations/" + c.DNSConfiguration + "/views/" + c.View + "/" + - "text_records/" + name + "/" + "text_records/" + name + "." + zone + "/" req, err := c.buildHTTPRequest("DELETE", url, nil) if err != nil { @@ -980,7 +1002,6 @@ func (c GatewayClientConfig) buildHTTPRequest(method, url string, body io.Reader // i.e. "foo=bar|baz=mop" func splitProperties(props string) map[string]string { propMap := make(map[string]string) - // remove trailing | character before we split props = strings.TrimSuffix(props, "|") @@ -1008,3 +1029,16 @@ func expandZone(zone string) string { } return ze } + +//extractOwnerFromTXTRecord takes a single text property string and returns the owner after parsing theowner string. +func extractOwnerfromTXTRecord(propString string) (string, error) { + if len(propString) == 0 { + return "", errors.Errorf("External-DNS Owner not found") + } + re := regexp.MustCompile(`external-dns/owner=[^,]+`) + match := re.FindStringSubmatch(propString) + if len(match) == 0 { + return "", errors.Errorf("External-DNS Owner not found, %s", propString) + } + return strings.Split(match[0], "=")[1], nil +} diff --git a/provider/bluecat/bluecat_test.go b/provider/bluecat/bluecat_test.go index a94ba4834..831382fb6 100644 --- a/provider/bluecat/bluecat_test.go +++ b/provider/bluecat/bluecat_test.go @@ -1,12 +1,9 @@ /* Copyright 2020 The Kubernetes Authors. - Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -84,11 +81,11 @@ func (g mockGatewayClient) createHostRecord(zone string, req *bluecatCreateHostR func (g mockGatewayClient) createCNAMERecord(zone string, req *bluecatCreateCNAMERecordRequest) (res interface{}, err error) { return nil, nil } -func (g mockGatewayClient) deleteHostRecord(name string) (err error) { +func (g mockGatewayClient) deleteHostRecord(name string, zone string) (err error) { *g.mockBluecatHosts = nil return nil } -func (g mockGatewayClient) deleteCNAMERecord(name string) (err error) { +func (g mockGatewayClient) deleteCNAMERecord(name string, zone string) (err error) { *g.mockBluecatCNAMEs = nil return nil } @@ -108,7 +105,7 @@ func (g mockGatewayClient) getTXTRecord(name string, record *BluecatTXTRecord) e func (g mockGatewayClient) createTXTRecord(zone string, req *bluecatCreateTXTRecordRequest) (res interface{}, err error) { return nil, nil } -func (g mockGatewayClient) deleteTXTRecord(name string) error { +func (g mockGatewayClient) deleteTXTRecord(name string, zone string) error { *g.mockBluecatTXTs = nil return nil } @@ -148,8 +145,8 @@ func createMockBluecatCNAME(alias, target string, ttl int) BluecatCNAMERecord { func createMockBluecatTXT(fqdn, txt string) BluecatTXTRecord { return BluecatTXTRecord{ - Name: fqdn, - Text: txt, + Name: fqdn, + Properties: txt, } } @@ -196,9 +193,10 @@ var tests = bluecatTestData{ RecordTTL: endpoint.TTL(30), }, { - DNSName: "abc.example.com", + DNSName: "kdb.example.com", RecordType: endpoint.RecordTypeTXT, - Targets: endpoint.Targets{"hello"}, + Targets: endpoint.Targets{"heritage=external-dns,external-dns/owner=default,external-dns/resource=service/openshift-ingress/router-default"}, + Labels: endpoint.Labels{"owner": "default"}, }, }, }, @@ -209,6 +207,9 @@ func TestBluecatRecords(t *testing.T) { mockBluecatZones: &[]BluecatZone{ createMockBluecatZone("example.com"), }, + mockBluecatTXTs: &[]BluecatTXTRecord{ + createMockBluecatTXT("kdb.example.com", "heritage=external-dns,external-dns/owner=default,external-dns/resource=service/openshift-ingress/router-default"), + }, mockBluecatHosts: &[]BluecatHostRecord{ createMockBluecatHostRecord("example.com", "123.123.123.122", 30), createMockBluecatHostRecord("nginx.example.com", "123.123.123.123", 30), @@ -217,9 +218,6 @@ func TestBluecatRecords(t *testing.T) { mockBluecatCNAMEs: &[]BluecatCNAMERecord{ createMockBluecatCNAME("hack.example.com", "bluecatnetworks.com", 30), }, - mockBluecatTXTs: &[]BluecatTXTRecord{ - createMockBluecatTXT("abc.example.com", "hello"), - }, } provider := newBluecatProvider( @@ -276,7 +274,7 @@ func TestBluecatApplyChangesDelete(t *testing.T) { createMockBluecatCNAME("hack.example.com", "bluecatnetworks.com", 30), }, mockBluecatTXTs: &[]BluecatTXTRecord{ - createMockBluecatTXT("abc.example.com", "hello"), + createMockBluecatTXT("kdb.example.com", "heritage=external-dns,external-dns/owner=default,external-dns/resource=service/openshift-ingress/router-default"), }, } @@ -298,6 +296,51 @@ func TestBluecatApplyChangesDelete(t *testing.T) { } } +func TestBluecatApplyChangesDeleteWithOwner(t *testing.T) { + client := mockGatewayClient{ + mockBluecatZones: &[]BluecatZone{ + createMockBluecatZone("example.com"), + }, + mockBluecatHosts: &[]BluecatHostRecord{ + createMockBluecatHostRecord("example.com", "123.123.123.122", 30), + createMockBluecatHostRecord("nginx.example.com", "123.123.123.123", 30), + createMockBluecatHostRecord("whitespace.example.com", "123.123.123.124", 30), + }, + mockBluecatCNAMEs: &[]BluecatCNAMERecord{ + createMockBluecatCNAME("hack.example.com", "bluecatnetworks.com", 30), + }, + mockBluecatTXTs: &[]BluecatTXTRecord{ + createMockBluecatTXT("kdb.example.com", "heritage=external-dns,external-dns/owner=default,external-dns/resource=service/openshift-ingress/router-default"), + }, + } + + provider := newBluecatProvider( + endpoint.NewDomainFilter([]string{"example.com"}), + provider.NewZoneIDFilter([]string{""}), false, client) + + for _, ti := range tests { + for _, ep := range ti.Endpoints { + if strings.Contains(ep.Targets.String(), "external-dns") { + owner, err := extractOwnerfromTXTRecord(ep.Targets.String()) + if err != nil { + continue + } + t.Logf("Owner %s %s", owner, err) + } + } + err := provider.ApplyChanges(context.Background(), &plan.Changes{Delete: ti.Endpoints}) + if err != nil { + t.Fatal(err) + } + actual, err := provider.Records(context.Background()) + if err != nil { + t.Fatal(err) + } + validateEndpoints(t, actual, []*endpoint.Endpoint{}) + } + +} + // TODO: ensure mapChanges method is tested // TODO: ensure findZone method is tested // TODO: ensure zones method is tested From 2f0149097d76d44af56e56a79cc9041f03bc877e Mon Sep 17 00:00:00 2001 From: Jaideep Bellani Date: Mon, 19 Jul 2021 16:13:22 -0500 Subject: [PATCH 173/175] bluecat: do not return if owner not found We were returning an error when the owner string was not found and this was causing the loop to quit. This is not ideal because it does not fetch the other records once it returns. --- provider/bluecat/bluecat.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/provider/bluecat/bluecat.go b/provider/bluecat/bluecat.go index c8410cf20..dc3b12edb 100644 --- a/provider/bluecat/bluecat.go +++ b/provider/bluecat/bluecat.go @@ -215,7 +215,7 @@ func (p *BluecatProvider) Records(ctx context.Context) (endpoints []*endpoint.En tempEndpoint := endpoint.NewEndpoint(rec.Name, endpoint.RecordTypeTXT, rec.Properties) tempEndpoint.Labels[endpoint.OwnerLabelKey], err = extractOwnerfromTXTRecord(rec.Properties) if err != nil { - return nil, errors.Wrapf(err, "Error fetching owner from record") + log.Debugf("External DNS Owner %s", err) } endpoints = append(endpoints, tempEndpoint) } @@ -243,7 +243,7 @@ func (p *BluecatProvider) Records(ctx context.Context) (endpoints []*endpoint.En if strings.Compare(rec.Name, txtRec.Name) == 0 { ep.Labels[endpoint.OwnerLabelKey], err = extractOwnerfromTXTRecord(txtRec.Properties) if err != nil { - return nil, errors.Wrapf(err, "owner not parsed correctly") + log.Debugf("External DNS Owner %s", err) } } } @@ -272,7 +272,7 @@ func (p *BluecatProvider) Records(ctx context.Context) (endpoints []*endpoint.En if strings.Compare(rec.Name, txtRec.Name) == 0 { ep.Labels[endpoint.OwnerLabelKey], err = extractOwnerfromTXTRecord(txtRec.Properties) if err != nil { - return nil, errors.Wrapf(err, "owner not parsed correctly") + log.Debugf("External DNS Owner %s", err) } } } From 0e621aa1e98611b47911053262f9104509b22645 Mon Sep 17 00:00:00 2001 From: Jaideep Bellani Date: Mon, 19 Jul 2021 16:15:52 -0500 Subject: [PATCH 174/175] bluecat: add additional tests and test cases --- provider/bluecat/bluecat_test.go | 49 ++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/provider/bluecat/bluecat_test.go b/provider/bluecat/bluecat_test.go index 831382fb6..b3f3e4a67 100644 --- a/provider/bluecat/bluecat_test.go +++ b/provider/bluecat/bluecat_test.go @@ -192,6 +192,18 @@ var tests = bluecatTestData{ Targets: endpoint.Targets{"bluecatnetworks.com"}, RecordTTL: endpoint.TTL(30), }, + { + DNSName: "wack.example.com", + RecordType: endpoint.RecordTypeTXT, + Targets: endpoint.Targets{"hello"}, + Labels: endpoint.Labels{"owner": ""}, + }, + { + DNSName: "sack.example.com", + RecordType: endpoint.RecordTypeTXT, + Targets: endpoint.Targets{""}, + Labels: endpoint.Labels{"owner": ""}, + }, { DNSName: "kdb.example.com", RecordType: endpoint.RecordTypeTXT, @@ -209,6 +221,8 @@ func TestBluecatRecords(t *testing.T) { }, mockBluecatTXTs: &[]BluecatTXTRecord{ createMockBluecatTXT("kdb.example.com", "heritage=external-dns,external-dns/owner=default,external-dns/resource=service/openshift-ingress/router-default"), + createMockBluecatTXT("wack.example.com", "hello"), + createMockBluecatTXT("sack.example.com", ""), }, mockBluecatHosts: &[]BluecatHostRecord{ createMockBluecatHostRecord("example.com", "123.123.123.122", 30), @@ -227,7 +241,9 @@ func TestBluecatRecords(t *testing.T) { for _, ti := range tests { actual, err := provider.Records(context.Background()) if err != nil { - t.Fatal(err) + if !strings.Contains(err.Error(), "External-DNS Owner not found") { + t.Fatal(err) + } } validateEndpoints(t, actual, ti.Endpoints) } @@ -275,6 +291,8 @@ func TestBluecatApplyChangesDelete(t *testing.T) { }, mockBluecatTXTs: &[]BluecatTXTRecord{ createMockBluecatTXT("kdb.example.com", "heritage=external-dns,external-dns/owner=default,external-dns/resource=service/openshift-ingress/router-default"), + createMockBluecatTXT("wack.example.com", "hello"), + createMockBluecatTXT("sack.example.com", ""), }, } @@ -311,6 +329,8 @@ func TestBluecatApplyChangesDeleteWithOwner(t *testing.T) { }, mockBluecatTXTs: &[]BluecatTXTRecord{ createMockBluecatTXT("kdb.example.com", "heritage=external-dns,external-dns/owner=default,external-dns/resource=service/openshift-ingress/router-default"), + createMockBluecatTXT("wack.example.com", "hello"), + createMockBluecatTXT("sack.example.com", ""), }, } @@ -341,7 +361,32 @@ func TestBluecatApplyChangesDeleteWithOwner(t *testing.T) { } -// TODO: ensure mapChanges method is tested +func TestExpandZones(t *testing.T) { + mockZones := []string{"example.com", "nginx.example.com", "hack.example.com"} + expected := []string{"zones/com/zones/example/zones/", "zones/com/zones/example/zones/nginx/zones/", "zones/com/zones/example/zones/hack/zones/"} + for i := range mockZones { + if expandZone(mockZones[i]) != expected[i] { + t.Fatalf("%s", expected[i]) + } + } +} + +func TestBluecatNewGatewayClient(t *testing.T) { + testCookie := http.Cookie{Name: "testCookie", Value: "exampleCookie"} + testToken := "exampleToken" + testgateWayHost := "exampleHost" + testDNSConfiguration := "exampleDNSConfiguration" + testView := "testView" + testZone := "example.com" + testVerify := true + + client := NewGatewayClient(testCookie, testToken, testgateWayHost, testDNSConfiguration, testView, testZone, testVerify) + + if client.Cookie.Value != testCookie.Value || client.Cookie.Name != testCookie.Name || client.Token != testToken || client.Host != testgateWayHost || client.DNSConfiguration != testDNSConfiguration || client.View != testView || client.RootZone != testZone || client.SkipTLSVerify != testVerify { + t.Fatal("Client values dont match") + } +} + // TODO: ensure findZone method is tested // TODO: ensure zones method is tested // TODO: ensure createRecords method is tested From fc1b7bda3f405b896840b08dae82c47d7182067f Mon Sep 17 00:00:00 2001 From: Jaideep Bellani Date: Mon, 19 Jul 2021 16:42:37 -0500 Subject: [PATCH 175/175] bluecat: changed block to original statement --- provider/bluecat/bluecat_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/provider/bluecat/bluecat_test.go b/provider/bluecat/bluecat_test.go index b3f3e4a67..8793a95b8 100644 --- a/provider/bluecat/bluecat_test.go +++ b/provider/bluecat/bluecat_test.go @@ -241,9 +241,7 @@ func TestBluecatRecords(t *testing.T) { for _, ti := range tests { actual, err := provider.Records(context.Background()) if err != nil { - if !strings.Contains(err.Error(), "External-DNS Owner not found") { - t.Fatal(err) - } + t.Fatal(err) } validateEndpoints(t, actual, ti.Endpoints) }