mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2025-12-24 05:01:00 +01:00
cloudflare: bugfix - do not attempt to create unconfigured empty custom hostnames; improve tests; streamline logic (#5146)
improve test coverage test the edge case when the custom hostname has changed during the record deletion don't use custom hostnames if Cloudflare for SaaS fails to authenticate Use new --cloudflare-custom-hostnames flag to enable cloudflare custom hostnames support custom hostnames flags --cloudflare-custom-hostnames-min-tls-version and --cloudflare-custom-hostnames-certificate-authority support markdown lint Update cloudflare.md
This commit is contained in:
parent
a3f4188965
commit
44f1008ee1
@ -87,6 +87,9 @@
|
|||||||
| `--tencent-cloud-config-file="/etc/kubernetes/tencent-cloud.json"` | When using the Tencent Cloud provider, specify the Tencent Cloud configuration file (required when --provider=tencentcloud) |
|
| `--tencent-cloud-config-file="/etc/kubernetes/tencent-cloud.json"` | When using the Tencent Cloud provider, specify the Tencent Cloud configuration file (required when --provider=tencentcloud) |
|
||||||
| `--tencent-cloud-zone-type=` | When using the Tencent Cloud provider, filter for zones with visibility (optional, options: public, private) |
|
| `--tencent-cloud-zone-type=` | When using the Tencent Cloud provider, filter for zones with visibility (optional, options: public, private) |
|
||||||
| `--[no-]cloudflare-proxied` | When using the Cloudflare provider, specify if the proxy mode must be enabled (default: disabled) |
|
| `--[no-]cloudflare-proxied` | When using the Cloudflare provider, specify if the proxy mode must be enabled (default: disabled) |
|
||||||
|
| `--[no-]cloudflare-custom-hostnames` | When using the Cloudflare provider, specify if the Custom Hostnames feature will be used. Requires "Cloudflare for SaaS" enabled. (default: disabled) |
|
||||||
|
| `--cloudflare-custom-hostnames-min-tls-version=1.0` | When using the Cloudflare provider with the Custom Hostnames, specify which Minimum TLS Version will be used by default. (default: 1.0, options: 1.0, 1.1, 1.2, 1.3) |
|
||||||
|
| `--cloudflare-custom-hostnames-certificate-authority=google` | When using the Cloudflare provider with the Custom Hostnames, specify which Cerrtificate Authority will be used by default. (default: google, options: google, ssl_com, lets_encrypt) |
|
||||||
| `--cloudflare-dns-records-per-page=100` | When using the Cloudflare provider, specify how many DNS records listed per page, max possible 5,000 (default: 100) |
|
| `--cloudflare-dns-records-per-page=100` | When using the Cloudflare provider, specify how many DNS records listed per page, max possible 5,000 (default: 100) |
|
||||||
| `--cloudflare-region-key=CLOUDFLARE-REGION-KEY` | When using the Cloudflare provider, specify the region (default: earth) |
|
| `--cloudflare-region-key=CLOUDFLARE-REGION-KEY` | When using the Cloudflare provider, specify the region (default: earth) |
|
||||||
| `--coredns-prefix="/skydns/"` | When using the CoreDNS provider, specify the prefix name |
|
| `--coredns-prefix="/skydns/"` | When using the CoreDNS provider, specify the prefix name |
|
||||||
|
|||||||
@ -310,7 +310,14 @@ If not set the value will default to `global`.
|
|||||||
|
|
||||||
## Setting cloudflare-custom-hostname
|
## Setting cloudflare-custom-hostname
|
||||||
|
|
||||||
Using the `external-dns.alpha.kubernetes.io/cloudflare-custom-hostname: "<custom hostname>"` annotation, you can have [custom hostnames](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/) automatically managed for A/CNAME record as a custom origin.
|
You can automatically configure custom hostnames for A/CNAME DNS records (as custom origins) using the `--cloudflare-custom-hostnames` flag and the `external-dns.alpha.kubernetes.io/cloudflare-custom-hostname: "<custom hostname>"` annotation.
|
||||||
|
|
||||||
|
See [Cloudflare for Platforms](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/domain-support/) for more information on custom hostnames.
|
||||||
|
|
||||||
|
This feature is disabled by default and supports the `--cloudflare-custom-hostnames-min-tls-version` and `--cloudflare-custom-hostnames-certificate-authority` flags.
|
||||||
|
|
||||||
|
The custom hostname DNS must resolve to the Cloudflare DNS record (`external-dns.alpha.kubernetes.io/hostname`) for automatic certificate validation via the HTTP method. It's important to note that the TXT method does not allow automatic validation and is not supported.
|
||||||
|
|
||||||
Requires [Cloudflare for SaaS](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/) product and "SSL and Certificates" API permission.
|
Requires [Cloudflare for SaaS](https://developers.cloudflare.com/cloudflare-for-platforms/cloudflare-for-saas/) product and "SSL and Certificates" API permission.
|
||||||
|
|
||||||
## Using CRD source to manage DNS records in Cloudflare
|
## Using CRD source to manage DNS records in Cloudflare
|
||||||
|
|||||||
13
main.go
13
main.go
@ -250,7 +250,18 @@ func main() {
|
|||||||
case "civo":
|
case "civo":
|
||||||
p, err = civo.NewCivoProvider(domainFilter, cfg.DryRun)
|
p, err = civo.NewCivoProvider(domainFilter, cfg.DryRun)
|
||||||
case "cloudflare":
|
case "cloudflare":
|
||||||
p, err = cloudflare.NewCloudFlareProvider(domainFilter, zoneIDFilter, cfg.CloudflareProxied, cfg.DryRun, cfg.CloudflareDNSRecordsPerPage, cfg.CloudflareRegionKey)
|
p, err = cloudflare.NewCloudFlareProvider(
|
||||||
|
domainFilter,
|
||||||
|
zoneIDFilter,
|
||||||
|
cfg.CloudflareProxied,
|
||||||
|
cfg.DryRun,
|
||||||
|
cfg.CloudflareDNSRecordsPerPage,
|
||||||
|
cfg.CloudflareRegionKey,
|
||||||
|
cloudflare.CustomHostnamesConfig{
|
||||||
|
Enabled: cfg.CloudflareCustomHostnames,
|
||||||
|
MinTLSVersion: cfg.CloudflareCustomHostnamesMinTLSVersion,
|
||||||
|
CertificateAuthority: cfg.CloudflareCustomHostnamesCertificateAuthority,
|
||||||
|
})
|
||||||
case "google":
|
case "google":
|
||||||
p, err = google.NewGoogleProvider(ctx, cfg.GoogleProject, domainFilter, zoneIDFilter, cfg.GoogleBatchChangeSize, cfg.GoogleBatchChangeInterval, cfg.GoogleZoneVisibility, cfg.DryRun)
|
p, err = google.NewGoogleProvider(ctx, cfg.GoogleProject, domainFilter, zoneIDFilter, cfg.GoogleBatchChangeSize, cfg.GoogleBatchChangeInterval, cfg.GoogleZoneVisibility, cfg.DryRun)
|
||||||
case "digitalocean":
|
case "digitalocean":
|
||||||
|
|||||||
@ -43,332 +43,338 @@ var Version = "unknown"
|
|||||||
|
|
||||||
// Config is a project-wide configuration
|
// Config is a project-wide configuration
|
||||||
type Config struct {
|
type Config struct {
|
||||||
APIServerURL string
|
APIServerURL string
|
||||||
KubeConfig string
|
KubeConfig string
|
||||||
RequestTimeout time.Duration
|
RequestTimeout time.Duration
|
||||||
DefaultTargets []string
|
DefaultTargets []string
|
||||||
GlooNamespaces []string
|
GlooNamespaces []string
|
||||||
SkipperRouteGroupVersion string
|
SkipperRouteGroupVersion string
|
||||||
Sources []string
|
Sources []string
|
||||||
Namespace string
|
Namespace string
|
||||||
AnnotationFilter string
|
AnnotationFilter string
|
||||||
LabelFilter string
|
LabelFilter string
|
||||||
IngressClassNames []string
|
IngressClassNames []string
|
||||||
FQDNTemplate string
|
FQDNTemplate string
|
||||||
CombineFQDNAndAnnotation bool
|
CombineFQDNAndAnnotation bool
|
||||||
IgnoreHostnameAnnotation bool
|
IgnoreHostnameAnnotation bool
|
||||||
IgnoreNonHostNetworkPods bool
|
IgnoreNonHostNetworkPods bool
|
||||||
IgnoreIngressTLSSpec bool
|
IgnoreIngressTLSSpec bool
|
||||||
IgnoreIngressRulesSpec bool
|
IgnoreIngressRulesSpec bool
|
||||||
ListenEndpointEvents bool
|
ListenEndpointEvents bool
|
||||||
GatewayName string
|
GatewayName string
|
||||||
GatewayNamespace string
|
GatewayNamespace string
|
||||||
GatewayLabelFilter string
|
GatewayLabelFilter string
|
||||||
Compatibility string
|
Compatibility string
|
||||||
PodSourceDomain string
|
PodSourceDomain string
|
||||||
PublishInternal bool
|
PublishInternal bool
|
||||||
PublishHostIP bool
|
PublishHostIP bool
|
||||||
AlwaysPublishNotReadyAddresses bool
|
AlwaysPublishNotReadyAddresses bool
|
||||||
ConnectorSourceServer string
|
ConnectorSourceServer string
|
||||||
Provider string
|
Provider string
|
||||||
ProviderCacheTime time.Duration
|
ProviderCacheTime time.Duration
|
||||||
GoogleProject string
|
GoogleProject string
|
||||||
GoogleBatchChangeSize int
|
GoogleBatchChangeSize int
|
||||||
GoogleBatchChangeInterval time.Duration
|
GoogleBatchChangeInterval time.Duration
|
||||||
GoogleZoneVisibility string
|
GoogleZoneVisibility string
|
||||||
DomainFilter []string
|
DomainFilter []string
|
||||||
ExcludeDomains []string
|
ExcludeDomains []string
|
||||||
RegexDomainFilter *regexp.Regexp
|
RegexDomainFilter *regexp.Regexp
|
||||||
RegexDomainExclusion *regexp.Regexp
|
RegexDomainExclusion *regexp.Regexp
|
||||||
ZoneNameFilter []string
|
ZoneNameFilter []string
|
||||||
ZoneIDFilter []string
|
ZoneIDFilter []string
|
||||||
TargetNetFilter []string
|
TargetNetFilter []string
|
||||||
ExcludeTargetNets []string
|
ExcludeTargetNets []string
|
||||||
AlibabaCloudConfigFile string
|
AlibabaCloudConfigFile string
|
||||||
AlibabaCloudZoneType string
|
AlibabaCloudZoneType string
|
||||||
AWSZoneType string
|
AWSZoneType string
|
||||||
AWSZoneTagFilter []string
|
AWSZoneTagFilter []string
|
||||||
AWSAssumeRole string
|
AWSAssumeRole string
|
||||||
AWSProfiles []string
|
AWSProfiles []string
|
||||||
AWSAssumeRoleExternalID string `secure:"yes"`
|
AWSAssumeRoleExternalID string `secure:"yes"`
|
||||||
AWSBatchChangeSize int
|
AWSBatchChangeSize int
|
||||||
AWSBatchChangeSizeBytes int
|
AWSBatchChangeSizeBytes int
|
||||||
AWSBatchChangeSizeValues int
|
AWSBatchChangeSizeValues int
|
||||||
AWSBatchChangeInterval time.Duration
|
AWSBatchChangeInterval time.Duration
|
||||||
AWSEvaluateTargetHealth bool
|
AWSEvaluateTargetHealth bool
|
||||||
AWSAPIRetries int
|
AWSAPIRetries int
|
||||||
AWSPreferCNAME bool
|
AWSPreferCNAME bool
|
||||||
AWSZoneCacheDuration time.Duration
|
AWSZoneCacheDuration time.Duration
|
||||||
AWSSDServiceCleanup bool
|
AWSSDServiceCleanup bool
|
||||||
AWSSDCreateTag map[string]string
|
AWSSDCreateTag map[string]string
|
||||||
AWSZoneMatchParent bool
|
AWSZoneMatchParent bool
|
||||||
AWSDynamoDBRegion string
|
AWSDynamoDBRegion string
|
||||||
AWSDynamoDBTable string
|
AWSDynamoDBTable string
|
||||||
AzureConfigFile string
|
AzureConfigFile string
|
||||||
AzureResourceGroup string
|
AzureResourceGroup string
|
||||||
AzureSubscriptionID string
|
AzureSubscriptionID string
|
||||||
AzureUserAssignedIdentityClientID string
|
AzureUserAssignedIdentityClientID string
|
||||||
AzureActiveDirectoryAuthorityHost string
|
AzureActiveDirectoryAuthorityHost string
|
||||||
AzureZonesCacheDuration time.Duration
|
AzureZonesCacheDuration time.Duration
|
||||||
CloudflareProxied bool
|
CloudflareProxied bool
|
||||||
CloudflareDNSRecordsPerPage int
|
CloudflareCustomHostnames bool
|
||||||
CloudflareRegionKey string
|
CloudflareCustomHostnamesMinTLSVersion string
|
||||||
CoreDNSPrefix string
|
CloudflareCustomHostnamesCertificateAuthority string
|
||||||
AkamaiServiceConsumerDomain string
|
CloudflareDNSRecordsPerPage int
|
||||||
AkamaiClientToken string
|
CloudflareRegionKey string
|
||||||
AkamaiClientSecret string
|
CoreDNSPrefix string
|
||||||
AkamaiAccessToken string
|
AkamaiServiceConsumerDomain string
|
||||||
AkamaiEdgercPath string
|
AkamaiClientToken string
|
||||||
AkamaiEdgercSection string
|
AkamaiClientSecret string
|
||||||
OCIConfigFile string
|
AkamaiAccessToken string
|
||||||
OCICompartmentOCID string
|
AkamaiEdgercPath string
|
||||||
OCIAuthInstancePrincipal bool
|
AkamaiEdgercSection string
|
||||||
OCIZoneScope string
|
OCIConfigFile string
|
||||||
OCIZoneCacheDuration time.Duration
|
OCICompartmentOCID string
|
||||||
InMemoryZones []string
|
OCIAuthInstancePrincipal bool
|
||||||
OVHEndpoint string
|
OCIZoneScope string
|
||||||
OVHApiRateLimit int
|
OCIZoneCacheDuration time.Duration
|
||||||
PDNSServer string
|
InMemoryZones []string
|
||||||
PDNSServerID string
|
OVHEndpoint string
|
||||||
PDNSAPIKey string `secure:"yes"`
|
OVHApiRateLimit int
|
||||||
PDNSSkipTLSVerify bool
|
PDNSServer string
|
||||||
TLSCA string
|
PDNSServerID string
|
||||||
TLSClientCert string
|
PDNSAPIKey string `secure:"yes"`
|
||||||
TLSClientCertKey string
|
PDNSSkipTLSVerify bool
|
||||||
Policy string
|
TLSCA string
|
||||||
Registry string
|
TLSClientCert string
|
||||||
TXTOwnerID string
|
TLSClientCertKey string
|
||||||
TXTPrefix string
|
Policy string
|
||||||
TXTSuffix string
|
Registry string
|
||||||
TXTEncryptEnabled bool
|
TXTOwnerID string
|
||||||
TXTEncryptAESKey string `secure:"yes"`
|
TXTPrefix string
|
||||||
TXTNewFormatOnly bool
|
TXTSuffix string
|
||||||
Interval time.Duration
|
TXTEncryptEnabled bool
|
||||||
MinEventSyncInterval time.Duration
|
TXTEncryptAESKey string `secure:"yes"`
|
||||||
Once bool
|
TXTNewFormatOnly bool
|
||||||
DryRun bool
|
Interval time.Duration
|
||||||
UpdateEvents bool
|
MinEventSyncInterval time.Duration
|
||||||
LogFormat string
|
Once bool
|
||||||
MetricsAddress string
|
DryRun bool
|
||||||
LogLevel string
|
UpdateEvents bool
|
||||||
TXTCacheInterval time.Duration
|
LogFormat string
|
||||||
TXTWildcardReplacement string
|
MetricsAddress string
|
||||||
ExoscaleEndpoint string
|
LogLevel string
|
||||||
ExoscaleAPIKey string `secure:"yes"`
|
TXTCacheInterval time.Duration
|
||||||
ExoscaleAPISecret string `secure:"yes"`
|
TXTWildcardReplacement string
|
||||||
ExoscaleAPIEnvironment string
|
ExoscaleEndpoint string
|
||||||
ExoscaleAPIZone string
|
ExoscaleAPIKey string `secure:"yes"`
|
||||||
CRDSourceAPIVersion string
|
ExoscaleAPISecret string `secure:"yes"`
|
||||||
CRDSourceKind string
|
ExoscaleAPIEnvironment string
|
||||||
ServiceTypeFilter []string
|
ExoscaleAPIZone string
|
||||||
CFAPIEndpoint string
|
CRDSourceAPIVersion string
|
||||||
CFUsername string
|
CRDSourceKind string
|
||||||
CFPassword string
|
ServiceTypeFilter []string
|
||||||
ResolveServiceLoadBalancerHostname bool
|
CFAPIEndpoint string
|
||||||
RFC2136Host []string
|
CFUsername string
|
||||||
RFC2136Port int
|
CFPassword string
|
||||||
RFC2136Zone []string
|
ResolveServiceLoadBalancerHostname bool
|
||||||
RFC2136Insecure bool
|
RFC2136Host []string
|
||||||
RFC2136GSSTSIG bool
|
RFC2136Port int
|
||||||
RFC2136CreatePTR bool
|
RFC2136Zone []string
|
||||||
RFC2136KerberosRealm string
|
RFC2136Insecure bool
|
||||||
RFC2136KerberosUsername string
|
RFC2136GSSTSIG bool
|
||||||
RFC2136KerberosPassword string `secure:"yes"`
|
RFC2136CreatePTR bool
|
||||||
RFC2136TSIGKeyName string
|
RFC2136KerberosRealm string
|
||||||
RFC2136TSIGSecret string `secure:"yes"`
|
RFC2136KerberosUsername string
|
||||||
RFC2136TSIGSecretAlg string
|
RFC2136KerberosPassword string `secure:"yes"`
|
||||||
RFC2136TAXFR bool
|
RFC2136TSIGKeyName string
|
||||||
RFC2136MinTTL time.Duration
|
RFC2136TSIGSecret string `secure:"yes"`
|
||||||
RFC2136LoadBalancingStrategy string
|
RFC2136TSIGSecretAlg string
|
||||||
RFC2136BatchChangeSize int
|
RFC2136TAXFR bool
|
||||||
RFC2136UseTLS bool
|
RFC2136MinTTL time.Duration
|
||||||
RFC2136SkipTLSVerify bool
|
RFC2136LoadBalancingStrategy string
|
||||||
NS1Endpoint string
|
RFC2136BatchChangeSize int
|
||||||
NS1IgnoreSSL bool
|
RFC2136UseTLS bool
|
||||||
NS1MinTTLSeconds int
|
RFC2136SkipTLSVerify bool
|
||||||
TransIPAccountName string
|
NS1Endpoint string
|
||||||
TransIPPrivateKeyFile string
|
NS1IgnoreSSL bool
|
||||||
DigitalOceanAPIPageSize int
|
NS1MinTTLSeconds int
|
||||||
ManagedDNSRecordTypes []string
|
TransIPAccountName string
|
||||||
ExcludeDNSRecordTypes []string
|
TransIPPrivateKeyFile string
|
||||||
GoDaddyAPIKey string `secure:"yes"`
|
DigitalOceanAPIPageSize int
|
||||||
GoDaddySecretKey string `secure:"yes"`
|
ManagedDNSRecordTypes []string
|
||||||
GoDaddyTTL int64
|
ExcludeDNSRecordTypes []string
|
||||||
GoDaddyOTE bool
|
GoDaddyAPIKey string `secure:"yes"`
|
||||||
OCPRouterName string
|
GoDaddySecretKey string `secure:"yes"`
|
||||||
IBMCloudProxied bool
|
GoDaddyTTL int64
|
||||||
IBMCloudConfigFile string
|
GoDaddyOTE bool
|
||||||
TencentCloudConfigFile string
|
OCPRouterName string
|
||||||
TencentCloudZoneType string
|
IBMCloudProxied bool
|
||||||
PiholeServer string
|
IBMCloudConfigFile string
|
||||||
PiholePassword string `secure:"yes"`
|
TencentCloudConfigFile string
|
||||||
PiholeTLSInsecureSkipVerify bool
|
TencentCloudZoneType string
|
||||||
PluralCluster string
|
PiholeServer string
|
||||||
PluralProvider string
|
PiholePassword string `secure:"yes"`
|
||||||
WebhookProviderURL string
|
PiholeTLSInsecureSkipVerify bool
|
||||||
WebhookProviderReadTimeout time.Duration
|
PluralCluster string
|
||||||
WebhookProviderWriteTimeout time.Duration
|
PluralProvider string
|
||||||
WebhookServer bool
|
WebhookProviderURL string
|
||||||
TraefikDisableLegacy bool
|
WebhookProviderReadTimeout time.Duration
|
||||||
TraefikDisableNew bool
|
WebhookProviderWriteTimeout time.Duration
|
||||||
NAT64Networks []string
|
WebhookServer bool
|
||||||
|
TraefikDisableLegacy bool
|
||||||
|
TraefikDisableNew bool
|
||||||
|
NAT64Networks []string
|
||||||
}
|
}
|
||||||
|
|
||||||
var defaultConfig = &Config{
|
var defaultConfig = &Config{
|
||||||
APIServerURL: "",
|
APIServerURL: "",
|
||||||
KubeConfig: "",
|
KubeConfig: "",
|
||||||
RequestTimeout: time.Second * 30,
|
RequestTimeout: time.Second * 30,
|
||||||
DefaultTargets: []string{},
|
DefaultTargets: []string{},
|
||||||
GlooNamespaces: []string{"gloo-system"},
|
GlooNamespaces: []string{"gloo-system"},
|
||||||
SkipperRouteGroupVersion: "zalando.org/v1",
|
SkipperRouteGroupVersion: "zalando.org/v1",
|
||||||
Sources: nil,
|
Sources: nil,
|
||||||
Namespace: "",
|
Namespace: "",
|
||||||
AnnotationFilter: "",
|
AnnotationFilter: "",
|
||||||
LabelFilter: labels.Everything().String(),
|
LabelFilter: labels.Everything().String(),
|
||||||
IngressClassNames: nil,
|
IngressClassNames: nil,
|
||||||
FQDNTemplate: "",
|
FQDNTemplate: "",
|
||||||
CombineFQDNAndAnnotation: false,
|
CombineFQDNAndAnnotation: false,
|
||||||
IgnoreHostnameAnnotation: false,
|
IgnoreHostnameAnnotation: false,
|
||||||
IgnoreIngressTLSSpec: false,
|
IgnoreIngressTLSSpec: false,
|
||||||
IgnoreIngressRulesSpec: false,
|
IgnoreIngressRulesSpec: false,
|
||||||
GatewayName: "",
|
GatewayName: "",
|
||||||
GatewayNamespace: "",
|
GatewayNamespace: "",
|
||||||
GatewayLabelFilter: "",
|
GatewayLabelFilter: "",
|
||||||
Compatibility: "",
|
Compatibility: "",
|
||||||
PublishInternal: false,
|
PublishInternal: false,
|
||||||
PublishHostIP: false,
|
PublishHostIP: false,
|
||||||
ConnectorSourceServer: "localhost:8080",
|
ConnectorSourceServer: "localhost:8080",
|
||||||
Provider: "",
|
Provider: "",
|
||||||
ProviderCacheTime: 0,
|
ProviderCacheTime: 0,
|
||||||
GoogleProject: "",
|
GoogleProject: "",
|
||||||
GoogleBatchChangeSize: 1000,
|
GoogleBatchChangeSize: 1000,
|
||||||
GoogleBatchChangeInterval: time.Second,
|
GoogleBatchChangeInterval: time.Second,
|
||||||
GoogleZoneVisibility: "",
|
GoogleZoneVisibility: "",
|
||||||
DomainFilter: []string{},
|
DomainFilter: []string{},
|
||||||
ZoneIDFilter: []string{},
|
ZoneIDFilter: []string{},
|
||||||
ExcludeDomains: []string{},
|
ExcludeDomains: []string{},
|
||||||
RegexDomainFilter: regexp.MustCompile(""),
|
RegexDomainFilter: regexp.MustCompile(""),
|
||||||
RegexDomainExclusion: regexp.MustCompile(""),
|
RegexDomainExclusion: regexp.MustCompile(""),
|
||||||
TargetNetFilter: []string{},
|
TargetNetFilter: []string{},
|
||||||
ExcludeTargetNets: []string{},
|
ExcludeTargetNets: []string{},
|
||||||
AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json",
|
AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json",
|
||||||
AWSZoneType: "",
|
AWSZoneType: "",
|
||||||
AWSZoneTagFilter: []string{},
|
AWSZoneTagFilter: []string{},
|
||||||
AWSZoneMatchParent: false,
|
AWSZoneMatchParent: false,
|
||||||
AWSAssumeRole: "",
|
AWSAssumeRole: "",
|
||||||
AWSAssumeRoleExternalID: "",
|
AWSAssumeRoleExternalID: "",
|
||||||
AWSBatchChangeSize: 1000,
|
AWSBatchChangeSize: 1000,
|
||||||
AWSBatchChangeSizeBytes: 32000,
|
AWSBatchChangeSizeBytes: 32000,
|
||||||
AWSBatchChangeSizeValues: 1000,
|
AWSBatchChangeSizeValues: 1000,
|
||||||
AWSBatchChangeInterval: time.Second,
|
AWSBatchChangeInterval: time.Second,
|
||||||
AWSEvaluateTargetHealth: true,
|
AWSEvaluateTargetHealth: true,
|
||||||
AWSAPIRetries: 3,
|
AWSAPIRetries: 3,
|
||||||
AWSPreferCNAME: false,
|
AWSPreferCNAME: false,
|
||||||
AWSZoneCacheDuration: 0 * time.Second,
|
AWSZoneCacheDuration: 0 * time.Second,
|
||||||
AWSSDServiceCleanup: false,
|
AWSSDServiceCleanup: false,
|
||||||
AWSSDCreateTag: map[string]string{},
|
AWSSDCreateTag: map[string]string{},
|
||||||
AWSDynamoDBRegion: "",
|
AWSDynamoDBRegion: "",
|
||||||
AWSDynamoDBTable: "external-dns",
|
AWSDynamoDBTable: "external-dns",
|
||||||
AzureConfigFile: "/etc/kubernetes/azure.json",
|
AzureConfigFile: "/etc/kubernetes/azure.json",
|
||||||
AzureResourceGroup: "",
|
AzureResourceGroup: "",
|
||||||
AzureSubscriptionID: "",
|
AzureSubscriptionID: "",
|
||||||
AzureZonesCacheDuration: 0 * time.Second,
|
AzureZonesCacheDuration: 0 * time.Second,
|
||||||
CloudflareProxied: false,
|
CloudflareProxied: false,
|
||||||
CloudflareDNSRecordsPerPage: 100,
|
CloudflareCustomHostnames: false,
|
||||||
CloudflareRegionKey: "earth",
|
CloudflareCustomHostnamesMinTLSVersion: "1.0",
|
||||||
CoreDNSPrefix: "/skydns/",
|
CloudflareCustomHostnamesCertificateAuthority: "google",
|
||||||
AkamaiServiceConsumerDomain: "",
|
CloudflareDNSRecordsPerPage: 100,
|
||||||
AkamaiClientToken: "",
|
CloudflareRegionKey: "earth",
|
||||||
AkamaiClientSecret: "",
|
CoreDNSPrefix: "/skydns/",
|
||||||
AkamaiAccessToken: "",
|
AkamaiServiceConsumerDomain: "",
|
||||||
AkamaiEdgercSection: "",
|
AkamaiClientToken: "",
|
||||||
AkamaiEdgercPath: "",
|
AkamaiClientSecret: "",
|
||||||
OCIConfigFile: "/etc/kubernetes/oci.yaml",
|
AkamaiAccessToken: "",
|
||||||
OCIZoneScope: "GLOBAL",
|
AkamaiEdgercSection: "",
|
||||||
OCIZoneCacheDuration: 0 * time.Second,
|
AkamaiEdgercPath: "",
|
||||||
InMemoryZones: []string{},
|
OCIConfigFile: "/etc/kubernetes/oci.yaml",
|
||||||
OVHEndpoint: "ovh-eu",
|
OCIZoneScope: "GLOBAL",
|
||||||
OVHApiRateLimit: 20,
|
OCIZoneCacheDuration: 0 * time.Second,
|
||||||
PDNSServer: "http://localhost:8081",
|
InMemoryZones: []string{},
|
||||||
PDNSServerID: "localhost",
|
OVHEndpoint: "ovh-eu",
|
||||||
PDNSAPIKey: "",
|
OVHApiRateLimit: 20,
|
||||||
PDNSSkipTLSVerify: false,
|
PDNSServer: "http://localhost:8081",
|
||||||
PodSourceDomain: "",
|
PDNSServerID: "localhost",
|
||||||
TLSCA: "",
|
PDNSAPIKey: "",
|
||||||
TLSClientCert: "",
|
PDNSSkipTLSVerify: false,
|
||||||
TLSClientCertKey: "",
|
PodSourceDomain: "",
|
||||||
Policy: "sync",
|
TLSCA: "",
|
||||||
Registry: "txt",
|
TLSClientCert: "",
|
||||||
TXTOwnerID: "default",
|
TLSClientCertKey: "",
|
||||||
TXTPrefix: "",
|
Policy: "sync",
|
||||||
TXTSuffix: "",
|
Registry: "txt",
|
||||||
TXTCacheInterval: 0,
|
TXTOwnerID: "default",
|
||||||
TXTWildcardReplacement: "",
|
TXTPrefix: "",
|
||||||
MinEventSyncInterval: 5 * time.Second,
|
TXTSuffix: "",
|
||||||
TXTEncryptEnabled: false,
|
TXTCacheInterval: 0,
|
||||||
TXTEncryptAESKey: "",
|
TXTWildcardReplacement: "",
|
||||||
TXTNewFormatOnly: false,
|
MinEventSyncInterval: 5 * time.Second,
|
||||||
Interval: time.Minute,
|
TXTEncryptEnabled: false,
|
||||||
Once: false,
|
TXTEncryptAESKey: "",
|
||||||
DryRun: false,
|
TXTNewFormatOnly: false,
|
||||||
UpdateEvents: false,
|
Interval: time.Minute,
|
||||||
LogFormat: "text",
|
Once: false,
|
||||||
MetricsAddress: ":7979",
|
DryRun: false,
|
||||||
LogLevel: logrus.InfoLevel.String(),
|
UpdateEvents: false,
|
||||||
ExoscaleAPIEnvironment: "api",
|
LogFormat: "text",
|
||||||
ExoscaleAPIZone: "ch-gva-2",
|
MetricsAddress: ":7979",
|
||||||
ExoscaleAPIKey: "",
|
LogLevel: logrus.InfoLevel.String(),
|
||||||
ExoscaleAPISecret: "",
|
ExoscaleAPIEnvironment: "api",
|
||||||
CRDSourceAPIVersion: "externaldns.k8s.io/v1alpha1",
|
ExoscaleAPIZone: "ch-gva-2",
|
||||||
CRDSourceKind: "DNSEndpoint",
|
ExoscaleAPIKey: "",
|
||||||
ServiceTypeFilter: []string{},
|
ExoscaleAPISecret: "",
|
||||||
CFAPIEndpoint: "",
|
CRDSourceAPIVersion: "externaldns.k8s.io/v1alpha1",
|
||||||
CFUsername: "",
|
CRDSourceKind: "DNSEndpoint",
|
||||||
CFPassword: "",
|
ServiceTypeFilter: []string{},
|
||||||
RFC2136Host: []string{""},
|
CFAPIEndpoint: "",
|
||||||
RFC2136Port: 0,
|
CFUsername: "",
|
||||||
RFC2136Zone: []string{},
|
CFPassword: "",
|
||||||
RFC2136Insecure: false,
|
RFC2136Host: []string{""},
|
||||||
RFC2136GSSTSIG: false,
|
RFC2136Port: 0,
|
||||||
RFC2136KerberosRealm: "",
|
RFC2136Zone: []string{},
|
||||||
RFC2136KerberosUsername: "",
|
RFC2136Insecure: false,
|
||||||
RFC2136KerberosPassword: "",
|
RFC2136GSSTSIG: false,
|
||||||
RFC2136TSIGKeyName: "",
|
RFC2136KerberosRealm: "",
|
||||||
RFC2136TSIGSecret: "",
|
RFC2136KerberosUsername: "",
|
||||||
RFC2136TSIGSecretAlg: "",
|
RFC2136KerberosPassword: "",
|
||||||
RFC2136TAXFR: true,
|
RFC2136TSIGKeyName: "",
|
||||||
RFC2136MinTTL: 0,
|
RFC2136TSIGSecret: "",
|
||||||
RFC2136BatchChangeSize: 50,
|
RFC2136TSIGSecretAlg: "",
|
||||||
RFC2136UseTLS: false,
|
RFC2136TAXFR: true,
|
||||||
RFC2136LoadBalancingStrategy: "disabled",
|
RFC2136MinTTL: 0,
|
||||||
RFC2136SkipTLSVerify: false,
|
RFC2136BatchChangeSize: 50,
|
||||||
NS1Endpoint: "",
|
RFC2136UseTLS: false,
|
||||||
NS1IgnoreSSL: false,
|
RFC2136LoadBalancingStrategy: "disabled",
|
||||||
TransIPAccountName: "",
|
RFC2136SkipTLSVerify: false,
|
||||||
TransIPPrivateKeyFile: "",
|
NS1Endpoint: "",
|
||||||
DigitalOceanAPIPageSize: 50,
|
NS1IgnoreSSL: false,
|
||||||
ManagedDNSRecordTypes: []string{endpoint.RecordTypeA, endpoint.RecordTypeAAAA, endpoint.RecordTypeCNAME},
|
TransIPAccountName: "",
|
||||||
ExcludeDNSRecordTypes: []string{},
|
TransIPPrivateKeyFile: "",
|
||||||
GoDaddyAPIKey: "",
|
DigitalOceanAPIPageSize: 50,
|
||||||
GoDaddySecretKey: "",
|
ManagedDNSRecordTypes: []string{endpoint.RecordTypeA, endpoint.RecordTypeAAAA, endpoint.RecordTypeCNAME},
|
||||||
GoDaddyTTL: 600,
|
ExcludeDNSRecordTypes: []string{},
|
||||||
GoDaddyOTE: false,
|
GoDaddyAPIKey: "",
|
||||||
IBMCloudProxied: false,
|
GoDaddySecretKey: "",
|
||||||
IBMCloudConfigFile: "/etc/kubernetes/ibmcloud.json",
|
GoDaddyTTL: 600,
|
||||||
TencentCloudConfigFile: "/etc/kubernetes/tencent-cloud.json",
|
GoDaddyOTE: false,
|
||||||
TencentCloudZoneType: "",
|
IBMCloudProxied: false,
|
||||||
PiholeServer: "",
|
IBMCloudConfigFile: "/etc/kubernetes/ibmcloud.json",
|
||||||
PiholePassword: "",
|
TencentCloudConfigFile: "/etc/kubernetes/tencent-cloud.json",
|
||||||
PiholeTLSInsecureSkipVerify: false,
|
TencentCloudZoneType: "",
|
||||||
PluralCluster: "",
|
PiholeServer: "",
|
||||||
PluralProvider: "",
|
PiholePassword: "",
|
||||||
WebhookProviderURL: "http://localhost:8888",
|
PiholeTLSInsecureSkipVerify: false,
|
||||||
WebhookProviderReadTimeout: 5 * time.Second,
|
PluralCluster: "",
|
||||||
WebhookProviderWriteTimeout: 10 * time.Second,
|
PluralProvider: "",
|
||||||
WebhookServer: false,
|
WebhookProviderURL: "http://localhost:8888",
|
||||||
TraefikDisableLegacy: false,
|
WebhookProviderReadTimeout: 5 * time.Second,
|
||||||
TraefikDisableNew: false,
|
WebhookProviderWriteTimeout: 10 * time.Second,
|
||||||
NAT64Networks: []string{},
|
WebhookServer: false,
|
||||||
|
TraefikDisableLegacy: false,
|
||||||
|
TraefikDisableNew: false,
|
||||||
|
NAT64Networks: []string{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewConfig returns new Config object
|
// NewConfig returns new Config object
|
||||||
@ -518,6 +524,9 @@ func App(cfg *Config) *kingpin.Application {
|
|||||||
app.Flag("tencent-cloud-zone-type", "When using the Tencent Cloud provider, filter for zones with visibility (optional, options: public, private)").Default(defaultConfig.TencentCloudZoneType).EnumVar(&cfg.TencentCloudZoneType, "", "public", "private")
|
app.Flag("tencent-cloud-zone-type", "When using the Tencent Cloud provider, filter for zones with visibility (optional, options: public, private)").Default(defaultConfig.TencentCloudZoneType).EnumVar(&cfg.TencentCloudZoneType, "", "public", "private")
|
||||||
|
|
||||||
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-proxied", "When using the Cloudflare provider, specify if the proxy mode must be enabled (default: disabled)").BoolVar(&cfg.CloudflareProxied)
|
||||||
|
app.Flag("cloudflare-custom-hostnames", "When using the Cloudflare provider, specify if the Custom Hostnames feature will be used. Requires \"Cloudflare for SaaS\" enabled. (default: disabled)").BoolVar(&cfg.CloudflareCustomHostnames)
|
||||||
|
app.Flag("cloudflare-custom-hostnames-min-tls-version", "When using the Cloudflare provider with the Custom Hostnames, specify which Minimum TLS Version will be used by default. (default: 1.0, options: 1.0, 1.1, 1.2, 1.3)").Default("1.0").EnumVar(&cfg.CloudflareCustomHostnamesMinTLSVersion, "1.0", "1.1", "1.2", "1.3")
|
||||||
|
app.Flag("cloudflare-custom-hostnames-certificate-authority", "When using the Cloudflare provider with the Custom Hostnames, specify which Cerrtificate Authority will be used by default. (default: google, options: google, ssl_com, lets_encrypt)").Default("google").EnumVar(&cfg.CloudflareCustomHostnamesCertificateAuthority, "google", "ssl_com", "lets_encrypt")
|
||||||
app.Flag("cloudflare-dns-records-per-page", "When using the Cloudflare provider, specify how many DNS records listed per page, max possible 5,000 (default: 100)").Default(strconv.Itoa(defaultConfig.CloudflareDNSRecordsPerPage)).IntVar(&cfg.CloudflareDNSRecordsPerPage)
|
app.Flag("cloudflare-dns-records-per-page", "When using the Cloudflare provider, specify how many DNS records listed per page, max possible 5,000 (default: 100)").Default(strconv.Itoa(defaultConfig.CloudflareDNSRecordsPerPage)).IntVar(&cfg.CloudflareDNSRecordsPerPage)
|
||||||
app.Flag("cloudflare-region-key", "When using the Cloudflare provider, specify the region (default: earth)").StringVar(&cfg.CloudflareRegionKey)
|
app.Flag("cloudflare-region-key", "When using the Cloudflare provider, specify the region (default: earth)").StringVar(&cfg.CloudflareRegionKey)
|
||||||
app.Flag("coredns-prefix", "When using the CoreDNS provider, specify the prefix name").Default(defaultConfig.CoreDNSPrefix).StringVar(&cfg.CoreDNSPrefix)
|
app.Flag("coredns-prefix", "When using the CoreDNS provider, specify the prefix name").Default(defaultConfig.CoreDNSPrefix).StringVar(&cfg.CoreDNSPrefix)
|
||||||
|
|||||||
@ -32,213 +32,219 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
minimalConfig = &Config{
|
minimalConfig = &Config{
|
||||||
APIServerURL: "",
|
APIServerURL: "",
|
||||||
KubeConfig: "",
|
KubeConfig: "",
|
||||||
RequestTimeout: time.Second * 30,
|
RequestTimeout: time.Second * 30,
|
||||||
GlooNamespaces: []string{"gloo-system"},
|
GlooNamespaces: []string{"gloo-system"},
|
||||||
SkipperRouteGroupVersion: "zalando.org/v1",
|
SkipperRouteGroupVersion: "zalando.org/v1",
|
||||||
Sources: []string{"service"},
|
Sources: []string{"service"},
|
||||||
Namespace: "",
|
Namespace: "",
|
||||||
FQDNTemplate: "",
|
FQDNTemplate: "",
|
||||||
Compatibility: "",
|
Compatibility: "",
|
||||||
Provider: "google",
|
Provider: "google",
|
||||||
GoogleProject: "",
|
GoogleProject: "",
|
||||||
GoogleBatchChangeSize: 1000,
|
GoogleBatchChangeSize: 1000,
|
||||||
GoogleBatchChangeInterval: time.Second,
|
GoogleBatchChangeInterval: time.Second,
|
||||||
GoogleZoneVisibility: "",
|
GoogleZoneVisibility: "",
|
||||||
DomainFilter: []string{""},
|
DomainFilter: []string{""},
|
||||||
ExcludeDomains: []string{""},
|
ExcludeDomains: []string{""},
|
||||||
RegexDomainFilter: regexp.MustCompile(""),
|
RegexDomainFilter: regexp.MustCompile(""),
|
||||||
RegexDomainExclusion: regexp.MustCompile(""),
|
RegexDomainExclusion: regexp.MustCompile(""),
|
||||||
ZoneNameFilter: []string{""},
|
ZoneNameFilter: []string{""},
|
||||||
ZoneIDFilter: []string{""},
|
ZoneIDFilter: []string{""},
|
||||||
AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json",
|
AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json",
|
||||||
AWSZoneType: "",
|
AWSZoneType: "",
|
||||||
AWSZoneTagFilter: []string{""},
|
AWSZoneTagFilter: []string{""},
|
||||||
AWSZoneMatchParent: false,
|
AWSZoneMatchParent: false,
|
||||||
AWSAssumeRole: "",
|
AWSAssumeRole: "",
|
||||||
AWSAssumeRoleExternalID: "",
|
AWSAssumeRoleExternalID: "",
|
||||||
AWSBatchChangeSize: 1000,
|
AWSBatchChangeSize: 1000,
|
||||||
AWSBatchChangeSizeBytes: 32000,
|
AWSBatchChangeSizeBytes: 32000,
|
||||||
AWSBatchChangeSizeValues: 1000,
|
AWSBatchChangeSizeValues: 1000,
|
||||||
AWSBatchChangeInterval: time.Second,
|
AWSBatchChangeInterval: time.Second,
|
||||||
AWSEvaluateTargetHealth: true,
|
AWSEvaluateTargetHealth: true,
|
||||||
AWSAPIRetries: 3,
|
AWSAPIRetries: 3,
|
||||||
AWSPreferCNAME: false,
|
AWSPreferCNAME: false,
|
||||||
AWSProfiles: []string{""},
|
AWSProfiles: []string{""},
|
||||||
AWSZoneCacheDuration: 0 * time.Second,
|
AWSZoneCacheDuration: 0 * time.Second,
|
||||||
AWSSDServiceCleanup: false,
|
AWSSDServiceCleanup: false,
|
||||||
AWSSDCreateTag: map[string]string{},
|
AWSSDCreateTag: map[string]string{},
|
||||||
AWSDynamoDBTable: "external-dns",
|
AWSDynamoDBTable: "external-dns",
|
||||||
AzureConfigFile: "/etc/kubernetes/azure.json",
|
AzureConfigFile: "/etc/kubernetes/azure.json",
|
||||||
AzureResourceGroup: "",
|
AzureResourceGroup: "",
|
||||||
AzureSubscriptionID: "",
|
AzureSubscriptionID: "",
|
||||||
CloudflareProxied: false,
|
CloudflareProxied: false,
|
||||||
CloudflareDNSRecordsPerPage: 100,
|
CloudflareCustomHostnames: false,
|
||||||
CloudflareRegionKey: "",
|
CloudflareCustomHostnamesMinTLSVersion: "1.0",
|
||||||
CoreDNSPrefix: "/skydns/",
|
CloudflareCustomHostnamesCertificateAuthority: "google",
|
||||||
AkamaiServiceConsumerDomain: "",
|
CloudflareDNSRecordsPerPage: 100,
|
||||||
AkamaiClientToken: "",
|
CloudflareRegionKey: "",
|
||||||
AkamaiClientSecret: "",
|
CoreDNSPrefix: "/skydns/",
|
||||||
AkamaiAccessToken: "",
|
AkamaiServiceConsumerDomain: "",
|
||||||
AkamaiEdgercPath: "",
|
AkamaiClientToken: "",
|
||||||
AkamaiEdgercSection: "",
|
AkamaiClientSecret: "",
|
||||||
OCIConfigFile: "/etc/kubernetes/oci.yaml",
|
AkamaiAccessToken: "",
|
||||||
OCIZoneScope: "GLOBAL",
|
AkamaiEdgercPath: "",
|
||||||
OCIZoneCacheDuration: 0 * time.Second,
|
AkamaiEdgercSection: "",
|
||||||
InMemoryZones: []string{""},
|
OCIConfigFile: "/etc/kubernetes/oci.yaml",
|
||||||
OVHEndpoint: "ovh-eu",
|
OCIZoneScope: "GLOBAL",
|
||||||
OVHApiRateLimit: 20,
|
OCIZoneCacheDuration: 0 * time.Second,
|
||||||
PDNSServer: "http://localhost:8081",
|
InMemoryZones: []string{""},
|
||||||
PDNSServerID: "localhost",
|
OVHEndpoint: "ovh-eu",
|
||||||
PDNSAPIKey: "",
|
OVHApiRateLimit: 20,
|
||||||
Policy: "sync",
|
PDNSServer: "http://localhost:8081",
|
||||||
Registry: "txt",
|
PDNSServerID: "localhost",
|
||||||
TXTOwnerID: "default",
|
PDNSAPIKey: "",
|
||||||
TXTPrefix: "",
|
Policy: "sync",
|
||||||
TXTCacheInterval: 0,
|
Registry: "txt",
|
||||||
TXTNewFormatOnly: false,
|
TXTOwnerID: "default",
|
||||||
Interval: time.Minute,
|
TXTPrefix: "",
|
||||||
MinEventSyncInterval: 5 * time.Second,
|
TXTCacheInterval: 0,
|
||||||
Once: false,
|
TXTNewFormatOnly: false,
|
||||||
DryRun: false,
|
Interval: time.Minute,
|
||||||
UpdateEvents: false,
|
MinEventSyncInterval: 5 * time.Second,
|
||||||
LogFormat: "text",
|
Once: false,
|
||||||
MetricsAddress: ":7979",
|
DryRun: false,
|
||||||
LogLevel: logrus.InfoLevel.String(),
|
UpdateEvents: false,
|
||||||
ConnectorSourceServer: "localhost:8080",
|
LogFormat: "text",
|
||||||
ExoscaleAPIEnvironment: "api",
|
MetricsAddress: ":7979",
|
||||||
ExoscaleAPIZone: "ch-gva-2",
|
LogLevel: logrus.InfoLevel.String(),
|
||||||
ExoscaleAPIKey: "",
|
ConnectorSourceServer: "localhost:8080",
|
||||||
ExoscaleAPISecret: "",
|
ExoscaleAPIEnvironment: "api",
|
||||||
CRDSourceAPIVersion: "externaldns.k8s.io/v1alpha1",
|
ExoscaleAPIZone: "ch-gva-2",
|
||||||
CRDSourceKind: "DNSEndpoint",
|
ExoscaleAPIKey: "",
|
||||||
TransIPAccountName: "",
|
ExoscaleAPISecret: "",
|
||||||
TransIPPrivateKeyFile: "",
|
CRDSourceAPIVersion: "externaldns.k8s.io/v1alpha1",
|
||||||
DigitalOceanAPIPageSize: 50,
|
CRDSourceKind: "DNSEndpoint",
|
||||||
ManagedDNSRecordTypes: []string{endpoint.RecordTypeA, endpoint.RecordTypeAAAA, endpoint.RecordTypeCNAME},
|
TransIPAccountName: "",
|
||||||
RFC2136BatchChangeSize: 50,
|
TransIPPrivateKeyFile: "",
|
||||||
RFC2136Host: []string{""},
|
DigitalOceanAPIPageSize: 50,
|
||||||
RFC2136LoadBalancingStrategy: "disabled",
|
ManagedDNSRecordTypes: []string{endpoint.RecordTypeA, endpoint.RecordTypeAAAA, endpoint.RecordTypeCNAME},
|
||||||
OCPRouterName: "default",
|
RFC2136BatchChangeSize: 50,
|
||||||
IBMCloudProxied: false,
|
RFC2136Host: []string{""},
|
||||||
IBMCloudConfigFile: "/etc/kubernetes/ibmcloud.json",
|
RFC2136LoadBalancingStrategy: "disabled",
|
||||||
TencentCloudConfigFile: "/etc/kubernetes/tencent-cloud.json",
|
OCPRouterName: "default",
|
||||||
TencentCloudZoneType: "",
|
IBMCloudProxied: false,
|
||||||
WebhookProviderURL: "http://localhost:8888",
|
IBMCloudConfigFile: "/etc/kubernetes/ibmcloud.json",
|
||||||
WebhookProviderReadTimeout: 5 * time.Second,
|
TencentCloudConfigFile: "/etc/kubernetes/tencent-cloud.json",
|
||||||
WebhookProviderWriteTimeout: 10 * time.Second,
|
TencentCloudZoneType: "",
|
||||||
|
WebhookProviderURL: "http://localhost:8888",
|
||||||
|
WebhookProviderReadTimeout: 5 * time.Second,
|
||||||
|
WebhookProviderWriteTimeout: 10 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
overriddenConfig = &Config{
|
overriddenConfig = &Config{
|
||||||
APIServerURL: "http://127.0.0.1:8080",
|
APIServerURL: "http://127.0.0.1:8080",
|
||||||
KubeConfig: "/some/path",
|
KubeConfig: "/some/path",
|
||||||
RequestTimeout: time.Second * 77,
|
RequestTimeout: time.Second * 77,
|
||||||
GlooNamespaces: []string{"gloo-not-system", "gloo-second-system"},
|
GlooNamespaces: []string{"gloo-not-system", "gloo-second-system"},
|
||||||
SkipperRouteGroupVersion: "zalando.org/v2",
|
SkipperRouteGroupVersion: "zalando.org/v2",
|
||||||
Sources: []string{"service", "ingress", "connector"},
|
Sources: []string{"service", "ingress", "connector"},
|
||||||
Namespace: "namespace",
|
Namespace: "namespace",
|
||||||
IgnoreHostnameAnnotation: true,
|
IgnoreHostnameAnnotation: true,
|
||||||
IgnoreNonHostNetworkPods: false,
|
IgnoreNonHostNetworkPods: false,
|
||||||
IgnoreIngressTLSSpec: true,
|
IgnoreIngressTLSSpec: true,
|
||||||
IgnoreIngressRulesSpec: true,
|
IgnoreIngressRulesSpec: true,
|
||||||
FQDNTemplate: "{{.Name}}.service.example.com",
|
FQDNTemplate: "{{.Name}}.service.example.com",
|
||||||
Compatibility: "mate",
|
Compatibility: "mate",
|
||||||
Provider: "google",
|
Provider: "google",
|
||||||
GoogleProject: "project",
|
GoogleProject: "project",
|
||||||
GoogleBatchChangeSize: 100,
|
GoogleBatchChangeSize: 100,
|
||||||
GoogleBatchChangeInterval: time.Second * 2,
|
GoogleBatchChangeInterval: time.Second * 2,
|
||||||
GoogleZoneVisibility: "private",
|
GoogleZoneVisibility: "private",
|
||||||
DomainFilter: []string{"example.org", "company.com"},
|
DomainFilter: []string{"example.org", "company.com"},
|
||||||
ExcludeDomains: []string{"xapi.example.org", "xapi.company.com"},
|
ExcludeDomains: []string{"xapi.example.org", "xapi.company.com"},
|
||||||
RegexDomainFilter: regexp.MustCompile("(example\\.org|company\\.com)$"),
|
RegexDomainFilter: regexp.MustCompile("(example\\.org|company\\.com)$"),
|
||||||
RegexDomainExclusion: regexp.MustCompile("xapi\\.(example\\.org|company\\.com)$"),
|
RegexDomainExclusion: regexp.MustCompile("xapi\\.(example\\.org|company\\.com)$"),
|
||||||
ZoneNameFilter: []string{"yapi.example.org", "yapi.company.com"},
|
ZoneNameFilter: []string{"yapi.example.org", "yapi.company.com"},
|
||||||
ZoneIDFilter: []string{"/hostedzone/ZTST1", "/hostedzone/ZTST2"},
|
ZoneIDFilter: []string{"/hostedzone/ZTST1", "/hostedzone/ZTST2"},
|
||||||
TargetNetFilter: []string{"10.0.0.0/9", "10.1.0.0/9"},
|
TargetNetFilter: []string{"10.0.0.0/9", "10.1.0.0/9"},
|
||||||
ExcludeTargetNets: []string{"1.0.0.0/9", "1.1.0.0/9"},
|
ExcludeTargetNets: []string{"1.0.0.0/9", "1.1.0.0/9"},
|
||||||
AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json",
|
AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json",
|
||||||
AWSZoneType: "private",
|
AWSZoneType: "private",
|
||||||
AWSZoneTagFilter: []string{"tag=foo"},
|
AWSZoneTagFilter: []string{"tag=foo"},
|
||||||
AWSZoneMatchParent: true,
|
AWSZoneMatchParent: true,
|
||||||
AWSAssumeRole: "some-other-role",
|
AWSAssumeRole: "some-other-role",
|
||||||
AWSAssumeRoleExternalID: "pg2000",
|
AWSAssumeRoleExternalID: "pg2000",
|
||||||
AWSBatchChangeSize: 100,
|
AWSBatchChangeSize: 100,
|
||||||
AWSBatchChangeSizeBytes: 16000,
|
AWSBatchChangeSizeBytes: 16000,
|
||||||
AWSBatchChangeSizeValues: 100,
|
AWSBatchChangeSizeValues: 100,
|
||||||
AWSBatchChangeInterval: time.Second * 2,
|
AWSBatchChangeInterval: time.Second * 2,
|
||||||
AWSEvaluateTargetHealth: false,
|
AWSEvaluateTargetHealth: false,
|
||||||
AWSAPIRetries: 13,
|
AWSAPIRetries: 13,
|
||||||
AWSPreferCNAME: true,
|
AWSPreferCNAME: true,
|
||||||
AWSProfiles: []string{"profile1", "profile2"},
|
AWSProfiles: []string{"profile1", "profile2"},
|
||||||
AWSZoneCacheDuration: 10 * time.Second,
|
AWSZoneCacheDuration: 10 * time.Second,
|
||||||
AWSSDServiceCleanup: true,
|
AWSSDServiceCleanup: true,
|
||||||
AWSSDCreateTag: map[string]string{"key1": "value1", "key2": "value2"},
|
AWSSDCreateTag: map[string]string{"key1": "value1", "key2": "value2"},
|
||||||
AWSDynamoDBTable: "custom-table",
|
AWSDynamoDBTable: "custom-table",
|
||||||
AzureConfigFile: "azure.json",
|
AzureConfigFile: "azure.json",
|
||||||
AzureResourceGroup: "arg",
|
AzureResourceGroup: "arg",
|
||||||
AzureSubscriptionID: "arg",
|
AzureSubscriptionID: "arg",
|
||||||
CloudflareProxied: true,
|
CloudflareProxied: true,
|
||||||
CloudflareDNSRecordsPerPage: 5000,
|
CloudflareCustomHostnames: true,
|
||||||
CloudflareRegionKey: "us",
|
CloudflareCustomHostnamesMinTLSVersion: "1.3",
|
||||||
CoreDNSPrefix: "/coredns/",
|
CloudflareCustomHostnamesCertificateAuthority: "google",
|
||||||
AkamaiServiceConsumerDomain: "oooo-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net",
|
CloudflareDNSRecordsPerPage: 5000,
|
||||||
AkamaiClientToken: "o184671d5307a388180fbf7f11dbdf46",
|
CloudflareRegionKey: "us",
|
||||||
AkamaiClientSecret: "o184671d5307a388180fbf7f11dbdf46",
|
CoreDNSPrefix: "/coredns/",
|
||||||
AkamaiAccessToken: "o184671d5307a388180fbf7f11dbdf46",
|
AkamaiServiceConsumerDomain: "oooo-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net",
|
||||||
AkamaiEdgercPath: "/home/test/.edgerc",
|
AkamaiClientToken: "o184671d5307a388180fbf7f11dbdf46",
|
||||||
AkamaiEdgercSection: "default",
|
AkamaiClientSecret: "o184671d5307a388180fbf7f11dbdf46",
|
||||||
OCIConfigFile: "oci.yaml",
|
AkamaiAccessToken: "o184671d5307a388180fbf7f11dbdf46",
|
||||||
OCIZoneScope: "PRIVATE",
|
AkamaiEdgercPath: "/home/test/.edgerc",
|
||||||
OCIZoneCacheDuration: 30 * time.Second,
|
AkamaiEdgercSection: "default",
|
||||||
InMemoryZones: []string{"example.org", "company.com"},
|
OCIConfigFile: "oci.yaml",
|
||||||
OVHEndpoint: "ovh-ca",
|
OCIZoneScope: "PRIVATE",
|
||||||
OVHApiRateLimit: 42,
|
OCIZoneCacheDuration: 30 * time.Second,
|
||||||
PDNSServer: "http://ns.example.com:8081",
|
InMemoryZones: []string{"example.org", "company.com"},
|
||||||
PDNSServerID: "localhost",
|
OVHEndpoint: "ovh-ca",
|
||||||
PDNSAPIKey: "some-secret-key",
|
OVHApiRateLimit: 42,
|
||||||
PDNSSkipTLSVerify: true,
|
PDNSServer: "http://ns.example.com:8081",
|
||||||
TLSCA: "/path/to/ca.crt",
|
PDNSServerID: "localhost",
|
||||||
TLSClientCert: "/path/to/cert.pem",
|
PDNSAPIKey: "some-secret-key",
|
||||||
TLSClientCertKey: "/path/to/key.pem",
|
PDNSSkipTLSVerify: true,
|
||||||
PodSourceDomain: "example.org",
|
TLSCA: "/path/to/ca.crt",
|
||||||
Policy: "upsert-only",
|
TLSClientCert: "/path/to/cert.pem",
|
||||||
Registry: "noop",
|
TLSClientCertKey: "/path/to/key.pem",
|
||||||
TXTOwnerID: "owner-1",
|
PodSourceDomain: "example.org",
|
||||||
TXTPrefix: "associated-txt-record",
|
Policy: "upsert-only",
|
||||||
TXTCacheInterval: 12 * time.Hour,
|
Registry: "noop",
|
||||||
TXTNewFormatOnly: true,
|
TXTOwnerID: "owner-1",
|
||||||
Interval: 10 * time.Minute,
|
TXTPrefix: "associated-txt-record",
|
||||||
MinEventSyncInterval: 50 * time.Second,
|
TXTCacheInterval: 12 * time.Hour,
|
||||||
Once: true,
|
TXTNewFormatOnly: true,
|
||||||
DryRun: true,
|
Interval: 10 * time.Minute,
|
||||||
UpdateEvents: true,
|
MinEventSyncInterval: 50 * time.Second,
|
||||||
LogFormat: "json",
|
Once: true,
|
||||||
MetricsAddress: "127.0.0.1:9099",
|
DryRun: true,
|
||||||
LogLevel: logrus.DebugLevel.String(),
|
UpdateEvents: true,
|
||||||
ConnectorSourceServer: "localhost:8081",
|
LogFormat: "json",
|
||||||
ExoscaleAPIEnvironment: "api1",
|
MetricsAddress: "127.0.0.1:9099",
|
||||||
ExoscaleAPIZone: "zone1",
|
LogLevel: logrus.DebugLevel.String(),
|
||||||
ExoscaleAPIKey: "1",
|
ConnectorSourceServer: "localhost:8081",
|
||||||
ExoscaleAPISecret: "2",
|
ExoscaleAPIEnvironment: "api1",
|
||||||
CRDSourceAPIVersion: "test.k8s.io/v1alpha1",
|
ExoscaleAPIZone: "zone1",
|
||||||
CRDSourceKind: "Endpoint",
|
ExoscaleAPIKey: "1",
|
||||||
NS1Endpoint: "https://api.example.com/v1",
|
ExoscaleAPISecret: "2",
|
||||||
NS1IgnoreSSL: true,
|
CRDSourceAPIVersion: "test.k8s.io/v1alpha1",
|
||||||
TransIPAccountName: "transip",
|
CRDSourceKind: "Endpoint",
|
||||||
TransIPPrivateKeyFile: "/path/to/transip.key",
|
NS1Endpoint: "https://api.example.com/v1",
|
||||||
DigitalOceanAPIPageSize: 100,
|
NS1IgnoreSSL: true,
|
||||||
ManagedDNSRecordTypes: []string{endpoint.RecordTypeA, endpoint.RecordTypeAAAA, endpoint.RecordTypeCNAME, endpoint.RecordTypeNS},
|
TransIPAccountName: "transip",
|
||||||
RFC2136BatchChangeSize: 100,
|
TransIPPrivateKeyFile: "/path/to/transip.key",
|
||||||
RFC2136Host: []string{"rfc2136-host1", "rfc2136-host2"},
|
DigitalOceanAPIPageSize: 100,
|
||||||
RFC2136LoadBalancingStrategy: "round-robin",
|
ManagedDNSRecordTypes: []string{endpoint.RecordTypeA, endpoint.RecordTypeAAAA, endpoint.RecordTypeCNAME, endpoint.RecordTypeNS},
|
||||||
IBMCloudProxied: true,
|
RFC2136BatchChangeSize: 100,
|
||||||
IBMCloudConfigFile: "ibmcloud.json",
|
RFC2136Host: []string{"rfc2136-host1", "rfc2136-host2"},
|
||||||
TencentCloudConfigFile: "tencent-cloud.json",
|
RFC2136LoadBalancingStrategy: "round-robin",
|
||||||
TencentCloudZoneType: "private",
|
IBMCloudProxied: true,
|
||||||
WebhookProviderURL: "http://localhost:8888",
|
IBMCloudConfigFile: "ibmcloud.json",
|
||||||
WebhookProviderReadTimeout: 5 * time.Second,
|
TencentCloudConfigFile: "tencent-cloud.json",
|
||||||
WebhookProviderWriteTimeout: 10 * time.Second,
|
TencentCloudZoneType: "private",
|
||||||
|
WebhookProviderURL: "http://localhost:8888",
|
||||||
|
WebhookProviderReadTimeout: 5 * time.Second,
|
||||||
|
WebhookProviderWriteTimeout: 10 * time.Second,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -287,6 +293,9 @@ func TestParseFlags(t *testing.T) {
|
|||||||
"--azure-resource-group=arg",
|
"--azure-resource-group=arg",
|
||||||
"--azure-subscription-id=arg",
|
"--azure-subscription-id=arg",
|
||||||
"--cloudflare-proxied",
|
"--cloudflare-proxied",
|
||||||
|
"--cloudflare-custom-hostnames",
|
||||||
|
"--cloudflare-custom-hostnames-min-tls-version=1.3",
|
||||||
|
"--cloudflare-custom-hostnames-certificate-authority=google",
|
||||||
"--cloudflare-dns-records-per-page=5000",
|
"--cloudflare-dns-records-per-page=5000",
|
||||||
"--cloudflare-region-key=us",
|
"--cloudflare-region-key=us",
|
||||||
"--coredns-prefix=/coredns/",
|
"--coredns-prefix=/coredns/",
|
||||||
@ -390,112 +399,115 @@ func TestParseFlags(t *testing.T) {
|
|||||||
title: "override everything via environment variables",
|
title: "override everything via environment variables",
|
||||||
args: []string{},
|
args: []string{},
|
||||||
envVars: map[string]string{
|
envVars: map[string]string{
|
||||||
"EXTERNAL_DNS_SERVER": "http://127.0.0.1:8080",
|
"EXTERNAL_DNS_SERVER": "http://127.0.0.1:8080",
|
||||||
"EXTERNAL_DNS_KUBECONFIG": "/some/path",
|
"EXTERNAL_DNS_KUBECONFIG": "/some/path",
|
||||||
"EXTERNAL_DNS_REQUEST_TIMEOUT": "77s",
|
"EXTERNAL_DNS_REQUEST_TIMEOUT": "77s",
|
||||||
"EXTERNAL_DNS_CONTOUR_LOAD_BALANCER": "heptio-contour-other/contour-other",
|
"EXTERNAL_DNS_CONTOUR_LOAD_BALANCER": "heptio-contour-other/contour-other",
|
||||||
"EXTERNAL_DNS_GLOO_NAMESPACE": "gloo-not-system\ngloo-second-system",
|
"EXTERNAL_DNS_GLOO_NAMESPACE": "gloo-not-system\ngloo-second-system",
|
||||||
"EXTERNAL_DNS_SKIPPER_ROUTEGROUP_GROUPVERSION": "zalando.org/v2",
|
"EXTERNAL_DNS_SKIPPER_ROUTEGROUP_GROUPVERSION": "zalando.org/v2",
|
||||||
"EXTERNAL_DNS_SOURCE": "service\ningress\nconnector",
|
"EXTERNAL_DNS_SOURCE": "service\ningress\nconnector",
|
||||||
"EXTERNAL_DNS_NAMESPACE": "namespace",
|
"EXTERNAL_DNS_NAMESPACE": "namespace",
|
||||||
"EXTERNAL_DNS_FQDN_TEMPLATE": "{{.Name}}.service.example.com",
|
"EXTERNAL_DNS_FQDN_TEMPLATE": "{{.Name}}.service.example.com",
|
||||||
"EXTERNAL_DNS_IGNORE_NON_HOST_NETWORK_PODS": "0",
|
"EXTERNAL_DNS_IGNORE_NON_HOST_NETWORK_PODS": "0",
|
||||||
"EXTERNAL_DNS_IGNORE_HOSTNAME_ANNOTATION": "1",
|
"EXTERNAL_DNS_IGNORE_HOSTNAME_ANNOTATION": "1",
|
||||||
"EXTERNAL_DNS_IGNORE_INGRESS_TLS_SPEC": "1",
|
"EXTERNAL_DNS_IGNORE_INGRESS_TLS_SPEC": "1",
|
||||||
"EXTERNAL_DNS_IGNORE_INGRESS_RULES_SPEC": "1",
|
"EXTERNAL_DNS_IGNORE_INGRESS_RULES_SPEC": "1",
|
||||||
"EXTERNAL_DNS_COMPATIBILITY": "mate",
|
"EXTERNAL_DNS_COMPATIBILITY": "mate",
|
||||||
"EXTERNAL_DNS_PROVIDER": "google",
|
"EXTERNAL_DNS_PROVIDER": "google",
|
||||||
"EXTERNAL_DNS_GOOGLE_PROJECT": "project",
|
"EXTERNAL_DNS_GOOGLE_PROJECT": "project",
|
||||||
"EXTERNAL_DNS_GOOGLE_BATCH_CHANGE_SIZE": "100",
|
"EXTERNAL_DNS_GOOGLE_BATCH_CHANGE_SIZE": "100",
|
||||||
"EXTERNAL_DNS_GOOGLE_BATCH_CHANGE_INTERVAL": "2s",
|
"EXTERNAL_DNS_GOOGLE_BATCH_CHANGE_INTERVAL": "2s",
|
||||||
"EXTERNAL_DNS_GOOGLE_ZONE_VISIBILITY": "private",
|
"EXTERNAL_DNS_GOOGLE_ZONE_VISIBILITY": "private",
|
||||||
"EXTERNAL_DNS_AZURE_CONFIG_FILE": "azure.json",
|
"EXTERNAL_DNS_AZURE_CONFIG_FILE": "azure.json",
|
||||||
"EXTERNAL_DNS_AZURE_RESOURCE_GROUP": "arg",
|
"EXTERNAL_DNS_AZURE_RESOURCE_GROUP": "arg",
|
||||||
"EXTERNAL_DNS_AZURE_SUBSCRIPTION_ID": "arg",
|
"EXTERNAL_DNS_AZURE_SUBSCRIPTION_ID": "arg",
|
||||||
"EXTERNAL_DNS_CLOUDFLARE_PROXIED": "1",
|
"EXTERNAL_DNS_CLOUDFLARE_PROXIED": "1",
|
||||||
"EXTERNAL_DNS_CLOUDFLARE_DNS_RECORDS_PER_PAGE": "5000",
|
"EXTERNAL_DNS_CLOUDFLARE_CUSTOM_HOSTNAMES": "1",
|
||||||
"EXTERNAL_DNS_CLOUDFLARE_REGION_KEY": "us",
|
"EXTERNAL_DNS_CLOUDFLARE_CUSTOM_HOSTNAMES_MIN_TLS_VERSION": "1.3",
|
||||||
"EXTERNAL_DNS_COREDNS_PREFIX": "/coredns/",
|
"EXTERNAL_DNS_CLOUDFLARE_CUSTOM_HOSTNAMES_CERTIFICATE_AUTHORITY": "google",
|
||||||
"EXTERNAL_DNS_AKAMAI_SERVICECONSUMERDOMAIN": "oooo-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net",
|
"EXTERNAL_DNS_CLOUDFLARE_DNS_RECORDS_PER_PAGE": "5000",
|
||||||
"EXTERNAL_DNS_AKAMAI_CLIENT_TOKEN": "o184671d5307a388180fbf7f11dbdf46",
|
"EXTERNAL_DNS_CLOUDFLARE_REGION_KEY": "us",
|
||||||
"EXTERNAL_DNS_AKAMAI_CLIENT_SECRET": "o184671d5307a388180fbf7f11dbdf46",
|
"EXTERNAL_DNS_COREDNS_PREFIX": "/coredns/",
|
||||||
"EXTERNAL_DNS_AKAMAI_ACCESS_TOKEN": "o184671d5307a388180fbf7f11dbdf46",
|
"EXTERNAL_DNS_AKAMAI_SERVICECONSUMERDOMAIN": "oooo-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net",
|
||||||
"EXTERNAL_DNS_AKAMAI_EDGERC_PATH": "/home/test/.edgerc",
|
"EXTERNAL_DNS_AKAMAI_CLIENT_TOKEN": "o184671d5307a388180fbf7f11dbdf46",
|
||||||
"EXTERNAL_DNS_AKAMAI_EDGERC_SECTION": "default",
|
"EXTERNAL_DNS_AKAMAI_CLIENT_SECRET": "o184671d5307a388180fbf7f11dbdf46",
|
||||||
"EXTERNAL_DNS_OCI_CONFIG_FILE": "oci.yaml",
|
"EXTERNAL_DNS_AKAMAI_ACCESS_TOKEN": "o184671d5307a388180fbf7f11dbdf46",
|
||||||
"EXTERNAL_DNS_OCI_ZONE_SCOPE": "PRIVATE",
|
"EXTERNAL_DNS_AKAMAI_EDGERC_PATH": "/home/test/.edgerc",
|
||||||
"EXTERNAL_DNS_OCI_ZONES_CACHE_DURATION": "30s",
|
"EXTERNAL_DNS_AKAMAI_EDGERC_SECTION": "default",
|
||||||
"EXTERNAL_DNS_INMEMORY_ZONE": "example.org\ncompany.com",
|
"EXTERNAL_DNS_OCI_CONFIG_FILE": "oci.yaml",
|
||||||
"EXTERNAL_DNS_OVH_ENDPOINT": "ovh-ca",
|
"EXTERNAL_DNS_OCI_ZONE_SCOPE": "PRIVATE",
|
||||||
"EXTERNAL_DNS_OVH_API_RATE_LIMIT": "42",
|
"EXTERNAL_DNS_OCI_ZONES_CACHE_DURATION": "30s",
|
||||||
"EXTERNAL_DNS_POD_SOURCE_DOMAIN": "example.org",
|
"EXTERNAL_DNS_INMEMORY_ZONE": "example.org\ncompany.com",
|
||||||
"EXTERNAL_DNS_DOMAIN_FILTER": "example.org\ncompany.com",
|
"EXTERNAL_DNS_OVH_ENDPOINT": "ovh-ca",
|
||||||
"EXTERNAL_DNS_EXCLUDE_DOMAINS": "xapi.example.org\nxapi.company.com",
|
"EXTERNAL_DNS_OVH_API_RATE_LIMIT": "42",
|
||||||
"EXTERNAL_DNS_REGEX_DOMAIN_FILTER": "(example\\.org|company\\.com)$",
|
"EXTERNAL_DNS_POD_SOURCE_DOMAIN": "example.org",
|
||||||
"EXTERNAL_DNS_REGEX_DOMAIN_EXCLUSION": "xapi\\.(example\\.org|company\\.com)$",
|
"EXTERNAL_DNS_DOMAIN_FILTER": "example.org\ncompany.com",
|
||||||
"EXTERNAL_DNS_TARGET_NET_FILTER": "10.0.0.0/9\n10.1.0.0/9",
|
"EXTERNAL_DNS_EXCLUDE_DOMAINS": "xapi.example.org\nxapi.company.com",
|
||||||
"EXTERNAL_DNS_EXCLUDE_TARGET_NET": "1.0.0.0/9\n1.1.0.0/9",
|
"EXTERNAL_DNS_REGEX_DOMAIN_FILTER": "(example\\.org|company\\.com)$",
|
||||||
"EXTERNAL_DNS_PDNS_SERVER": "http://ns.example.com:8081",
|
"EXTERNAL_DNS_REGEX_DOMAIN_EXCLUSION": "xapi\\.(example\\.org|company\\.com)$",
|
||||||
"EXTERNAL_DNS_PDNS_ID": "localhost",
|
"EXTERNAL_DNS_TARGET_NET_FILTER": "10.0.0.0/9\n10.1.0.0/9",
|
||||||
"EXTERNAL_DNS_PDNS_API_KEY": "some-secret-key",
|
"EXTERNAL_DNS_EXCLUDE_TARGET_NET": "1.0.0.0/9\n1.1.0.0/9",
|
||||||
"EXTERNAL_DNS_PDNS_SKIP_TLS_VERIFY": "1",
|
"EXTERNAL_DNS_PDNS_SERVER": "http://ns.example.com:8081",
|
||||||
"EXTERNAL_DNS_RDNS_ROOT_DOMAIN": "lb.rancher.cloud",
|
"EXTERNAL_DNS_PDNS_ID": "localhost",
|
||||||
"EXTERNAL_DNS_TLS_CA": "/path/to/ca.crt",
|
"EXTERNAL_DNS_PDNS_API_KEY": "some-secret-key",
|
||||||
"EXTERNAL_DNS_TLS_CLIENT_CERT": "/path/to/cert.pem",
|
"EXTERNAL_DNS_PDNS_SKIP_TLS_VERIFY": "1",
|
||||||
"EXTERNAL_DNS_TLS_CLIENT_CERT_KEY": "/path/to/key.pem",
|
"EXTERNAL_DNS_RDNS_ROOT_DOMAIN": "lb.rancher.cloud",
|
||||||
"EXTERNAL_DNS_ZONE_NAME_FILTER": "yapi.example.org\nyapi.company.com",
|
"EXTERNAL_DNS_TLS_CA": "/path/to/ca.crt",
|
||||||
"EXTERNAL_DNS_ZONE_ID_FILTER": "/hostedzone/ZTST1\n/hostedzone/ZTST2",
|
"EXTERNAL_DNS_TLS_CLIENT_CERT": "/path/to/cert.pem",
|
||||||
"EXTERNAL_DNS_AWS_ZONE_TYPE": "private",
|
"EXTERNAL_DNS_TLS_CLIENT_CERT_KEY": "/path/to/key.pem",
|
||||||
"EXTERNAL_DNS_AWS_ZONE_TAGS": "tag=foo",
|
"EXTERNAL_DNS_ZONE_NAME_FILTER": "yapi.example.org\nyapi.company.com",
|
||||||
"EXTERNAL_DNS_AWS_ZONE_MATCH_PARENT": "true",
|
"EXTERNAL_DNS_ZONE_ID_FILTER": "/hostedzone/ZTST1\n/hostedzone/ZTST2",
|
||||||
"EXTERNAL_DNS_AWS_ASSUME_ROLE": "some-other-role",
|
"EXTERNAL_DNS_AWS_ZONE_TYPE": "private",
|
||||||
"EXTERNAL_DNS_AWS_ASSUME_ROLE_EXTERNAL_ID": "pg2000",
|
"EXTERNAL_DNS_AWS_ZONE_TAGS": "tag=foo",
|
||||||
"EXTERNAL_DNS_AWS_BATCH_CHANGE_SIZE": "100",
|
"EXTERNAL_DNS_AWS_ZONE_MATCH_PARENT": "true",
|
||||||
"EXTERNAL_DNS_AWS_BATCH_CHANGE_SIZE_BYTES": "16000",
|
"EXTERNAL_DNS_AWS_ASSUME_ROLE": "some-other-role",
|
||||||
"EXTERNAL_DNS_AWS_BATCH_CHANGE_SIZE_VALUES": "100",
|
"EXTERNAL_DNS_AWS_ASSUME_ROLE_EXTERNAL_ID": "pg2000",
|
||||||
"EXTERNAL_DNS_AWS_BATCH_CHANGE_INTERVAL": "2s",
|
"EXTERNAL_DNS_AWS_BATCH_CHANGE_SIZE": "100",
|
||||||
"EXTERNAL_DNS_AWS_EVALUATE_TARGET_HEALTH": "0",
|
"EXTERNAL_DNS_AWS_BATCH_CHANGE_SIZE_BYTES": "16000",
|
||||||
"EXTERNAL_DNS_AWS_API_RETRIES": "13",
|
"EXTERNAL_DNS_AWS_BATCH_CHANGE_SIZE_VALUES": "100",
|
||||||
"EXTERNAL_DNS_AWS_PREFER_CNAME": "true",
|
"EXTERNAL_DNS_AWS_BATCH_CHANGE_INTERVAL": "2s",
|
||||||
"EXTERNAL_DNS_AWS_PROFILE": "profile1\nprofile2",
|
"EXTERNAL_DNS_AWS_EVALUATE_TARGET_HEALTH": "0",
|
||||||
"EXTERNAL_DNS_AWS_ZONES_CACHE_DURATION": "10s",
|
"EXTERNAL_DNS_AWS_API_RETRIES": "13",
|
||||||
"EXTERNAL_DNS_AWS_SD_SERVICE_CLEANUP": "true",
|
"EXTERNAL_DNS_AWS_PREFER_CNAME": "true",
|
||||||
"EXTERNAL_DNS_AWS_SD_CREATE_TAG": "key1=value1\nkey2=value2",
|
"EXTERNAL_DNS_AWS_PROFILE": "profile1\nprofile2",
|
||||||
"EXTERNAL_DNS_DYNAMODB_TABLE": "custom-table",
|
"EXTERNAL_DNS_AWS_ZONES_CACHE_DURATION": "10s",
|
||||||
"EXTERNAL_DNS_POLICY": "upsert-only",
|
"EXTERNAL_DNS_AWS_SD_SERVICE_CLEANUP": "true",
|
||||||
"EXTERNAL_DNS_REGISTRY": "noop",
|
"EXTERNAL_DNS_AWS_SD_CREATE_TAG": "key1=value1\nkey2=value2",
|
||||||
"EXTERNAL_DNS_TXT_OWNER_ID": "owner-1",
|
"EXTERNAL_DNS_DYNAMODB_TABLE": "custom-table",
|
||||||
"EXTERNAL_DNS_TXT_PREFIX": "associated-txt-record",
|
"EXTERNAL_DNS_POLICY": "upsert-only",
|
||||||
"EXTERNAL_DNS_TXT_CACHE_INTERVAL": "12h",
|
"EXTERNAL_DNS_REGISTRY": "noop",
|
||||||
"EXTERNAL_DNS_TXT_NEW_FORMAT_ONLY": "1",
|
"EXTERNAL_DNS_TXT_OWNER_ID": "owner-1",
|
||||||
"EXTERNAL_DNS_INTERVAL": "10m",
|
"EXTERNAL_DNS_TXT_PREFIX": "associated-txt-record",
|
||||||
"EXTERNAL_DNS_MIN_EVENT_SYNC_INTERVAL": "50s",
|
"EXTERNAL_DNS_TXT_CACHE_INTERVAL": "12h",
|
||||||
"EXTERNAL_DNS_ONCE": "1",
|
"EXTERNAL_DNS_TXT_NEW_FORMAT_ONLY": "1",
|
||||||
"EXTERNAL_DNS_DRY_RUN": "1",
|
"EXTERNAL_DNS_INTERVAL": "10m",
|
||||||
"EXTERNAL_DNS_EVENTS": "1",
|
"EXTERNAL_DNS_MIN_EVENT_SYNC_INTERVAL": "50s",
|
||||||
"EXTERNAL_DNS_LOG_FORMAT": "json",
|
"EXTERNAL_DNS_ONCE": "1",
|
||||||
"EXTERNAL_DNS_METRICS_ADDRESS": "127.0.0.1:9099",
|
"EXTERNAL_DNS_DRY_RUN": "1",
|
||||||
"EXTERNAL_DNS_LOG_LEVEL": "debug",
|
"EXTERNAL_DNS_EVENTS": "1",
|
||||||
"EXTERNAL_DNS_CONNECTOR_SOURCE_SERVER": "localhost:8081",
|
"EXTERNAL_DNS_LOG_FORMAT": "json",
|
||||||
"EXTERNAL_DNS_EXOSCALE_APIENV": "api1",
|
"EXTERNAL_DNS_METRICS_ADDRESS": "127.0.0.1:9099",
|
||||||
"EXTERNAL_DNS_EXOSCALE_APIZONE": "zone1",
|
"EXTERNAL_DNS_LOG_LEVEL": "debug",
|
||||||
"EXTERNAL_DNS_EXOSCALE_APIKEY": "1",
|
"EXTERNAL_DNS_CONNECTOR_SOURCE_SERVER": "localhost:8081",
|
||||||
"EXTERNAL_DNS_EXOSCALE_APISECRET": "2",
|
"EXTERNAL_DNS_EXOSCALE_APIENV": "api1",
|
||||||
"EXTERNAL_DNS_CRD_SOURCE_APIVERSION": "test.k8s.io/v1alpha1",
|
"EXTERNAL_DNS_EXOSCALE_APIZONE": "zone1",
|
||||||
"EXTERNAL_DNS_CRD_SOURCE_KIND": "Endpoint",
|
"EXTERNAL_DNS_EXOSCALE_APIKEY": "1",
|
||||||
"EXTERNAL_DNS_NS1_ENDPOINT": "https://api.example.com/v1",
|
"EXTERNAL_DNS_EXOSCALE_APISECRET": "2",
|
||||||
"EXTERNAL_DNS_NS1_IGNORESSL": "1",
|
"EXTERNAL_DNS_CRD_SOURCE_APIVERSION": "test.k8s.io/v1alpha1",
|
||||||
"EXTERNAL_DNS_TRANSIP_ACCOUNT": "transip",
|
"EXTERNAL_DNS_CRD_SOURCE_KIND": "Endpoint",
|
||||||
"EXTERNAL_DNS_TRANSIP_KEYFILE": "/path/to/transip.key",
|
"EXTERNAL_DNS_NS1_ENDPOINT": "https://api.example.com/v1",
|
||||||
"EXTERNAL_DNS_DIGITALOCEAN_API_PAGE_SIZE": "100",
|
"EXTERNAL_DNS_NS1_IGNORESSL": "1",
|
||||||
"EXTERNAL_DNS_MANAGED_RECORD_TYPES": "A\nAAAA\nCNAME\nNS",
|
"EXTERNAL_DNS_TRANSIP_ACCOUNT": "transip",
|
||||||
"EXTERNAL_DNS_RFC2136_BATCH_CHANGE_SIZE": "100",
|
"EXTERNAL_DNS_TRANSIP_KEYFILE": "/path/to/transip.key",
|
||||||
"EXTERNAL_DNS_RFC2136_LOAD_BALANCING_STRATEGY": "round-robin",
|
"EXTERNAL_DNS_DIGITALOCEAN_API_PAGE_SIZE": "100",
|
||||||
"EXTERNAL_DNS_RFC2136_HOST": "rfc2136-host1\nrfc2136-host2",
|
"EXTERNAL_DNS_MANAGED_RECORD_TYPES": "A\nAAAA\nCNAME\nNS",
|
||||||
"EXTERNAL_DNS_IBMCLOUD_PROXIED": "1",
|
"EXTERNAL_DNS_RFC2136_BATCH_CHANGE_SIZE": "100",
|
||||||
"EXTERNAL_DNS_IBMCLOUD_CONFIG_FILE": "ibmcloud.json",
|
"EXTERNAL_DNS_RFC2136_LOAD_BALANCING_STRATEGY": "round-robin",
|
||||||
"EXTERNAL_DNS_TENCENT_CLOUD_CONFIG_FILE": "tencent-cloud.json",
|
"EXTERNAL_DNS_RFC2136_HOST": "rfc2136-host1\nrfc2136-host2",
|
||||||
"EXTERNAL_DNS_TENCENT_CLOUD_ZONE_TYPE": "private",
|
"EXTERNAL_DNS_IBMCLOUD_PROXIED": "1",
|
||||||
|
"EXTERNAL_DNS_IBMCLOUD_CONFIG_FILE": "ibmcloud.json",
|
||||||
|
"EXTERNAL_DNS_TENCENT_CLOUD_CONFIG_FILE": "tencent-cloud.json",
|
||||||
|
"EXTERNAL_DNS_TENCENT_CLOUD_ZONE_TYPE": "private",
|
||||||
},
|
},
|
||||||
expected: overriddenConfig,
|
expected: overriddenConfig,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -64,6 +64,12 @@ var recordTypeProxyNotSupported = map[string]bool{
|
|||||||
"SRV": true,
|
"SRV": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CustomHostnamesConfig struct {
|
||||||
|
Enabled bool
|
||||||
|
MinTLSVersion string
|
||||||
|
CertificateAuthority string
|
||||||
|
}
|
||||||
|
|
||||||
var recordTypeCustomHostnameSupported = map[string]bool{
|
var recordTypeCustomHostnameSupported = map[string]bool{
|
||||||
"A": true,
|
"A": true,
|
||||||
"CNAME": true,
|
"CNAME": true,
|
||||||
@ -149,20 +155,22 @@ type CloudFlareProvider struct {
|
|||||||
provider.BaseProvider
|
provider.BaseProvider
|
||||||
Client cloudFlareDNS
|
Client cloudFlareDNS
|
||||||
// only consider hosted zones managing domains ending in this suffix
|
// only consider hosted zones managing domains ending in this suffix
|
||||||
domainFilter endpoint.DomainFilter
|
domainFilter endpoint.DomainFilter
|
||||||
zoneIDFilter provider.ZoneIDFilter
|
zoneIDFilter provider.ZoneIDFilter
|
||||||
proxiedByDefault bool
|
proxiedByDefault bool
|
||||||
DryRun bool
|
CustomHostnamesConfig CustomHostnamesConfig
|
||||||
DNSRecordsPerPage int
|
DryRun bool
|
||||||
RegionKey string
|
DNSRecordsPerPage int
|
||||||
|
RegionKey string
|
||||||
}
|
}
|
||||||
|
|
||||||
// cloudFlareChange differentiates between ChangActions
|
// cloudFlareChange differentiates between ChangActions
|
||||||
type cloudFlareChange struct {
|
type cloudFlareChange struct {
|
||||||
Action string
|
Action string
|
||||||
ResourceRecord cloudflare.DNSRecord
|
ResourceRecord cloudflare.DNSRecord
|
||||||
RegionalHostname cloudflare.RegionalHostname
|
RegionalHostname cloudflare.RegionalHostname
|
||||||
CustomHostname cloudflare.CustomHostname
|
CustomHostname cloudflare.CustomHostname
|
||||||
|
CustomHostnamePrev string
|
||||||
}
|
}
|
||||||
|
|
||||||
// RecordParamsTypes is a typeset of the possible Record Params that can be passed to cloudflare-go library
|
// RecordParamsTypes is a typeset of the possible Record Params that can be passed to cloudflare-go library
|
||||||
@ -201,7 +209,7 @@ func getCreateDNSRecordParam(cfc cloudFlareChange) cloudflare.CreateDNSRecordPar
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewCloudFlareProvider initializes a new CloudFlare DNS based Provider.
|
// NewCloudFlareProvider initializes a new CloudFlare DNS based Provider.
|
||||||
func NewCloudFlareProvider(domainFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, proxiedByDefault bool, dryRun bool, dnsRecordsPerPage int, regionKey string) (*CloudFlareProvider, error) {
|
func NewCloudFlareProvider(domainFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, proxiedByDefault bool, dryRun bool, dnsRecordsPerPage int, regionKey string, customHostnamesConfig CustomHostnamesConfig) (*CloudFlareProvider, error) {
|
||||||
// initialize via chosen auth method and returns new API object
|
// initialize via chosen auth method and returns new API object
|
||||||
var (
|
var (
|
||||||
config *cloudflare.API
|
config *cloudflare.API
|
||||||
@ -225,13 +233,14 @@ func NewCloudFlareProvider(domainFilter endpoint.DomainFilter, zoneIDFilter prov
|
|||||||
}
|
}
|
||||||
provider := &CloudFlareProvider{
|
provider := &CloudFlareProvider{
|
||||||
// Client: config,
|
// Client: config,
|
||||||
Client: zoneService{config},
|
Client: zoneService{config},
|
||||||
domainFilter: domainFilter,
|
domainFilter: domainFilter,
|
||||||
zoneIDFilter: zoneIDFilter,
|
zoneIDFilter: zoneIDFilter,
|
||||||
proxiedByDefault: proxiedByDefault,
|
proxiedByDefault: proxiedByDefault,
|
||||||
DryRun: dryRun,
|
CustomHostnamesConfig: customHostnamesConfig,
|
||||||
DNSRecordsPerPage: dnsRecordsPerPage,
|
DryRun: dryRun,
|
||||||
RegionKey: regionKey,
|
DNSRecordsPerPage: dnsRecordsPerPage,
|
||||||
|
RegionKey: regionKey,
|
||||||
}
|
}
|
||||||
return provider, nil
|
return provider, nil
|
||||||
}
|
}
|
||||||
@ -319,7 +328,7 @@ func (p *CloudFlareProvider) ApplyChanges(ctx context.Context, changes *plan.Cha
|
|||||||
|
|
||||||
for _, endpoint := range changes.Create {
|
for _, endpoint := range changes.Create {
|
||||||
for _, target := range endpoint.Targets {
|
for _, target := range endpoint.Targets {
|
||||||
cloudflareChanges = append(cloudflareChanges, p.newCloudFlareChange(cloudFlareCreate, endpoint, target))
|
cloudflareChanges = append(cloudflareChanges, p.newCloudFlareChange(cloudFlareCreate, endpoint, target, nil))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,21 +338,21 @@ func (p *CloudFlareProvider) ApplyChanges(ctx context.Context, changes *plan.Cha
|
|||||||
add, remove, leave := provider.Difference(current.Targets, desired.Targets)
|
add, remove, leave := provider.Difference(current.Targets, desired.Targets)
|
||||||
|
|
||||||
for _, a := range remove {
|
for _, a := range remove {
|
||||||
cloudflareChanges = append(cloudflareChanges, p.newCloudFlareChange(cloudFlareDelete, current, a))
|
cloudflareChanges = append(cloudflareChanges, p.newCloudFlareChange(cloudFlareDelete, current, a, current))
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, a := range add {
|
for _, a := range add {
|
||||||
cloudflareChanges = append(cloudflareChanges, p.newCloudFlareChange(cloudFlareCreate, desired, a))
|
cloudflareChanges = append(cloudflareChanges, p.newCloudFlareChange(cloudFlareCreate, desired, a, current))
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, a := range leave {
|
for _, a := range leave {
|
||||||
cloudflareChanges = append(cloudflareChanges, p.newCloudFlareChange(cloudFlareUpdate, desired, a))
|
cloudflareChanges = append(cloudflareChanges, p.newCloudFlareChange(cloudFlareUpdate, desired, a, current))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, endpoint := range changes.Delete {
|
for _, endpoint := range changes.Delete {
|
||||||
for _, target := range endpoint.Targets {
|
for _, target := range endpoint.Targets {
|
||||||
cloudflareChanges = append(cloudflareChanges, p.newCloudFlareChange(cloudFlareDelete, endpoint, target))
|
cloudflareChanges = append(cloudflareChanges, p.newCloudFlareChange(cloudFlareDelete, endpoint, target, nil))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,16 +376,6 @@ func (p *CloudFlareProvider) submitChanges(ctx context.Context, changes []*cloud
|
|||||||
|
|
||||||
var failedZones []string
|
var failedZones []string
|
||||||
for zoneID, changes := range changesByZone {
|
for zoneID, changes := range changesByZone {
|
||||||
records, err := p.listDNSRecordsWithAutoPagination(ctx, zoneID)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not fetch records from zone, %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
chs, chErr := p.listCustomHostnamesWithPagination(ctx, zoneID)
|
|
||||||
if chErr != nil {
|
|
||||||
return fmt.Errorf("could not fetch custom hostnames from zone, %v", chErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
var failedChange bool
|
var failedChange bool
|
||||||
for _, change := range changes {
|
for _, change := range changes {
|
||||||
logFields := log.Fields{
|
logFields := log.Fields{
|
||||||
@ -394,34 +393,37 @@ func (p *CloudFlareProvider) submitChanges(ctx context.Context, changes []*cloud
|
|||||||
}
|
}
|
||||||
|
|
||||||
resourceContainer := cloudflare.ZoneIdentifier(zoneID)
|
resourceContainer := cloudflare.ZoneIdentifier(zoneID)
|
||||||
|
records, err := p.listDNSRecordsWithAutoPagination(ctx, zoneID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not fetch records from zone, %v", err)
|
||||||
|
}
|
||||||
|
chs, chErr := p.listCustomHostnamesWithPagination(ctx, zoneID)
|
||||||
|
if chErr != nil {
|
||||||
|
return fmt.Errorf("could not fetch custom hostnames from zone, %v", chErr)
|
||||||
|
}
|
||||||
if change.Action == cloudFlareUpdate {
|
if change.Action == cloudFlareUpdate {
|
||||||
if recordTypeCustomHostnameSupported[change.ResourceRecord.Type] {
|
if recordTypeCustomHostnameSupported[change.ResourceRecord.Type] {
|
||||||
chID, oldCh := p.getCustomHostnameIDbyOrigin(chs, change.ResourceRecord.Name)
|
prevCh := change.CustomHostnamePrev
|
||||||
if chID == "" && change.CustomHostname.Hostname != "" {
|
newCh := change.CustomHostname.Hostname
|
||||||
log.WithFields(logFields).Infof("Adding custom hostname %v", change.CustomHostname.Hostname)
|
if prevCh != "" {
|
||||||
_, chErr := p.Client.CreateCustomHostname(ctx, zoneID, change.CustomHostname)
|
prevChID, _ := p.getCustomHostnameOrigin(chs, prevCh)
|
||||||
if chErr != nil {
|
if prevChID != "" && prevCh != newCh {
|
||||||
failedChange = true
|
log.WithFields(logFields).Infof("Removing previous custom hostname %v/%v", prevChID, prevCh)
|
||||||
log.WithFields(logFields).Errorf("failed to add custom hostname %v: %v", change.CustomHostname.Hostname, chErr)
|
chErr := p.Client.DeleteCustomHostname(ctx, zoneID, prevChID)
|
||||||
|
if chErr != nil {
|
||||||
|
failedChange = true
|
||||||
|
log.WithFields(logFields).Errorf("failed to remove previous custom hostname %v/%v: %v", prevChID, prevCh, chErr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if chID != "" && oldCh != "" && change.CustomHostname.Hostname == "" {
|
}
|
||||||
log.WithFields(logFields).Infof("Removing custom hostname %v", change.CustomHostname.Hostname)
|
if newCh != "" {
|
||||||
chErr := p.Client.DeleteCustomHostname(ctx, zoneID, chID)
|
if prevCh != newCh {
|
||||||
if chErr != nil {
|
log.WithFields(logFields).Infof("Adding custom hostname %v", newCh)
|
||||||
failedChange = true
|
_, chErr := p.Client.CreateCustomHostname(ctx, zoneID, change.CustomHostname)
|
||||||
log.WithFields(logFields).Errorf("failed to remove custom hostname %v: %v", change.CustomHostname.Hostname, chErr)
|
if chErr != nil {
|
||||||
}
|
failedChange = true
|
||||||
} else if chID != "" && change.CustomHostname.Hostname != "" && oldCh != change.CustomHostname.Hostname {
|
log.WithFields(logFields).Errorf("failed to add custom hostname %v: %v", newCh, chErr)
|
||||||
log.WithFields(logFields).Infof("Replacing custom hostname: %v/%v to %v", chID, oldCh, change.CustomHostname.Hostname)
|
}
|
||||||
chDelErr := p.Client.DeleteCustomHostname(ctx, zoneID, chID)
|
|
||||||
if chDelErr != nil {
|
|
||||||
failedChange = true
|
|
||||||
log.WithFields(logFields).Errorf("failed to remove replacing custom hostname %v/%v: %v", chID, oldCh, chDelErr)
|
|
||||||
}
|
|
||||||
_, chAddErr := p.Client.CreateCustomHostname(ctx, zoneID, change.CustomHostname)
|
|
||||||
if chAddErr != nil {
|
|
||||||
failedChange = true
|
|
||||||
log.WithFields(logFields).Errorf("failed to add replacing custom hostname %v: %v", change.CustomHostname.Hostname, chAddErr)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -455,14 +457,19 @@ func (p *CloudFlareProvider) submitChanges(ctx context.Context, changes []*cloud
|
|||||||
failedChange = true
|
failedChange = true
|
||||||
log.WithFields(logFields).Errorf("failed to delete record: %v", err)
|
log.WithFields(logFields).Errorf("failed to delete record: %v", err)
|
||||||
}
|
}
|
||||||
chID, oldCh := p.getCustomHostnameIDbyOrigin(chs, change.ResourceRecord.Name)
|
if change.CustomHostname.Hostname == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.WithFields(logFields).Infof("Deleting custom hostname %v", change.CustomHostname.Hostname)
|
||||||
|
chID, _ := p.getCustomHostnameOrigin(chs, change.CustomHostname.Hostname)
|
||||||
if chID == "" {
|
if chID == "" {
|
||||||
|
log.WithFields(logFields).Infof("Custom hostname %v not found", change.CustomHostname.Hostname)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
chErr := p.Client.DeleteCustomHostname(ctx, zoneID, chID)
|
chErr := p.Client.DeleteCustomHostname(ctx, zoneID, chID)
|
||||||
if chErr != nil {
|
if chErr != nil {
|
||||||
failedChange = true
|
failedChange = true
|
||||||
log.WithFields(logFields).Errorf("failed to delete custom hostname %v/%v: %v", chID, oldCh, chErr)
|
log.WithFields(logFields).Errorf("failed to delete custom hostname %v/%v: %v", chID, change.CustomHostname.Hostname, chErr)
|
||||||
}
|
}
|
||||||
} else if change.Action == cloudFlareCreate {
|
} else if change.Action == cloudFlareCreate {
|
||||||
recordParam := getCreateDNSRecordParam(*change)
|
recordParam := getCreateDNSRecordParam(*change)
|
||||||
@ -471,7 +478,16 @@ func (p *CloudFlareProvider) submitChanges(ctx context.Context, changes []*cloud
|
|||||||
failedChange = true
|
failedChange = true
|
||||||
log.WithFields(logFields).Errorf("failed to create record: %v", err)
|
log.WithFields(logFields).Errorf("failed to create record: %v", err)
|
||||||
}
|
}
|
||||||
|
if change.CustomHostname.Hostname == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
log.WithFields(logFields).Infof("Creating custom hostname %v", change.CustomHostname.Hostname)
|
log.WithFields(logFields).Infof("Creating custom hostname %v", change.CustomHostname.Hostname)
|
||||||
|
chID, chOrigin := p.getCustomHostnameOrigin(chs, change.CustomHostname.Hostname)
|
||||||
|
if chID != "" {
|
||||||
|
failedChange = true
|
||||||
|
log.WithFields(logFields).Errorf("failed to create custom hostname, %v already exists for origin %v", change.CustomHostname.Hostname, chOrigin)
|
||||||
|
continue
|
||||||
|
}
|
||||||
_, chErr := p.Client.CreateCustomHostname(ctx, zoneID, change.CustomHostname)
|
_, chErr := p.Client.CreateCustomHostname(ctx, zoneID, change.CustomHostname)
|
||||||
if chErr != nil {
|
if chErr != nil {
|
||||||
failedChange = true
|
failedChange = true
|
||||||
@ -537,16 +553,16 @@ func (p *CloudFlareProvider) getRecordID(records []cloudflare.DNSRecord, record
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *CloudFlareProvider) getCustomHostnameIDbyOrigin(chs []cloudflare.CustomHostname, origin string) (string, string) {
|
func (p *CloudFlareProvider) getCustomHostnameOrigin(chs []cloudflare.CustomHostname, hostname string) (string, string) {
|
||||||
for _, zoneCh := range chs {
|
for _, zoneCh := range chs {
|
||||||
if zoneCh.CustomOriginServer == origin {
|
if zoneCh.Hostname == hostname {
|
||||||
return zoneCh.ID, zoneCh.Hostname
|
return zoneCh.ID, zoneCh.CustomOriginServer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", ""
|
return "", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *CloudFlareProvider) newCloudFlareChange(action string, endpoint *endpoint.Endpoint, target string) *cloudFlareChange {
|
func (p *CloudFlareProvider) newCloudFlareChange(action string, endpoint *endpoint.Endpoint, target string, current *endpoint.Endpoint) *cloudFlareChange {
|
||||||
ttl := defaultCloudFlareRecordTTL
|
ttl := defaultCloudFlareRecordTTL
|
||||||
proxied := shouldBeProxied(endpoint, p.proxiedByDefault)
|
proxied := shouldBeProxied(endpoint, p.proxiedByDefault)
|
||||||
|
|
||||||
@ -554,6 +570,19 @@ func (p *CloudFlareProvider) newCloudFlareChange(action string, endpoint *endpoi
|
|||||||
ttl = int(endpoint.RecordTTL)
|
ttl = int(endpoint.RecordTTL)
|
||||||
}
|
}
|
||||||
dt := time.Now()
|
dt := time.Now()
|
||||||
|
|
||||||
|
customHostnamePrev := ""
|
||||||
|
newCustomHostname := cloudflare.CustomHostname{}
|
||||||
|
if p.CustomHostnamesConfig.Enabled {
|
||||||
|
if current != nil {
|
||||||
|
customHostnamePrev = getEndpointCustomHostname(current)
|
||||||
|
}
|
||||||
|
newCustomHostname = cloudflare.CustomHostname{
|
||||||
|
Hostname: getEndpointCustomHostname(endpoint),
|
||||||
|
CustomOriginServer: endpoint.DNSName,
|
||||||
|
SSL: getCustomHostnamesSSLOptions(endpoint, p.CustomHostnamesConfig),
|
||||||
|
}
|
||||||
|
}
|
||||||
return &cloudFlareChange{
|
return &cloudFlareChange{
|
||||||
Action: action,
|
Action: action,
|
||||||
ResourceRecord: cloudflare.DNSRecord{
|
ResourceRecord: cloudflare.DNSRecord{
|
||||||
@ -573,19 +602,8 @@ func (p *CloudFlareProvider) newCloudFlareChange(action string, endpoint *endpoi
|
|||||||
RegionKey: p.RegionKey,
|
RegionKey: p.RegionKey,
|
||||||
CreatedOn: &dt,
|
CreatedOn: &dt,
|
||||||
},
|
},
|
||||||
CustomHostname: cloudflare.CustomHostname{
|
CustomHostnamePrev: customHostnamePrev,
|
||||||
Hostname: getEndpointCustomHostname(endpoint),
|
CustomHostname: newCustomHostname,
|
||||||
CustomOriginServer: endpoint.DNSName,
|
|
||||||
SSL: &cloudflare.CustomHostnameSSL{
|
|
||||||
Type: "dv",
|
|
||||||
Method: "http",
|
|
||||||
CertificateAuthority: "google",
|
|
||||||
BundleMethod: "ubiquitous",
|
|
||||||
Settings: cloudflare.CustomHostnameSSLSettings{
|
|
||||||
MinTLSVersion: "1.0",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -618,6 +636,9 @@ func (p *CloudFlareProvider) listDNSRecordsWithAutoPagination(ctx context.Contex
|
|||||||
|
|
||||||
// listCustomHostnamesWithPagination performs automatic pagination of results on requests to cloudflare.CustomHostnames
|
// listCustomHostnamesWithPagination performs automatic pagination of results on requests to cloudflare.CustomHostnames
|
||||||
func (p *CloudFlareProvider) listCustomHostnamesWithPagination(ctx context.Context, zoneID string) ([]cloudflare.CustomHostname, error) {
|
func (p *CloudFlareProvider) listCustomHostnamesWithPagination(ctx context.Context, zoneID string) ([]cloudflare.CustomHostname, error) {
|
||||||
|
if !p.CustomHostnamesConfig.Enabled {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
var chs []cloudflare.CustomHostname
|
var chs []cloudflare.CustomHostname
|
||||||
resultInfo := cloudflare.ResultInfo{Page: 1}
|
resultInfo := cloudflare.ResultInfo{Page: 1}
|
||||||
for {
|
for {
|
||||||
@ -643,6 +664,18 @@ func (p *CloudFlareProvider) listCustomHostnamesWithPagination(ctx context.Conte
|
|||||||
return chs, nil
|
return chs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getCustomHostnamesSSLOptions(endpoint *endpoint.Endpoint, customHostnamesConfig CustomHostnamesConfig) *cloudflare.CustomHostnameSSL {
|
||||||
|
return &cloudflare.CustomHostnameSSL{
|
||||||
|
Type: "dv",
|
||||||
|
Method: "http",
|
||||||
|
CertificateAuthority: customHostnamesConfig.CertificateAuthority,
|
||||||
|
BundleMethod: "ubiquitous",
|
||||||
|
Settings: cloudflare.CustomHostnameSSLSettings{
|
||||||
|
MinTLSVersion: customHostnamesConfig.MinTLSVersion,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func shouldBeProxied(endpoint *endpoint.Endpoint, proxiedByDefault bool) bool {
|
func shouldBeProxied(endpoint *endpoint.Endpoint, proxiedByDefault bool) bool {
|
||||||
proxied := proxiedByDefault
|
proxied := proxiedByDefault
|
||||||
|
|
||||||
@ -695,7 +728,7 @@ func groupByNameAndTypeWithCustomHostnames(records []cloudflare.DNSRecord, chs [
|
|||||||
// map custom origin to custom hostname, custom origin should match to a dns record
|
// map custom origin to custom hostname, custom origin should match to a dns record
|
||||||
customOriginServers := map[string]string{}
|
customOriginServers := map[string]string{}
|
||||||
|
|
||||||
// only one latest custom hostname for a dns record would work
|
// only one latest custom hostname for a dns record would work; noop (chs is empty) if custom hostnames feature is not in use
|
||||||
for _, c := range chs {
|
for _, c := range chs {
|
||||||
customOriginServers[c.CustomOriginServer] = c.Hostname
|
customOriginServers[c.CustomOriginServer] = c.Hostname
|
||||||
}
|
}
|
||||||
@ -721,9 +754,10 @@ func groupByNameAndTypeWithCustomHostnames(records []cloudflare.DNSRecord, chs [
|
|||||||
if ep == nil {
|
if ep == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ep.WithProviderSpecific(source.CloudflareProxiedKey, strconv.FormatBool(proxied))
|
ep = ep.WithProviderSpecific(source.CloudflareProxiedKey, strconv.FormatBool(proxied))
|
||||||
|
// noop (customOriginServers is empty) if custom hostnames feature is not in use
|
||||||
if customHostname, ok := customOriginServers[records[0].Name]; ok {
|
if customHostname, ok := customOriginServers[records[0].Name]; ok {
|
||||||
ep.WithProviderSpecific(source.CloudflareCustomHostnameKey, customHostname)
|
ep = ep.WithProviderSpecific(source.CloudflareCustomHostnameKey, customHostname)
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoints = append(endpoints, ep)
|
endpoints = append(endpoints, ep)
|
||||||
|
|||||||
@ -26,10 +26,12 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
cloudflare "github.com/cloudflare/cloudflare-go"
|
cloudflare "github.com/cloudflare/cloudflare-go"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/maxatome/go-testdeep/td"
|
"github.com/maxatome/go-testdeep/td"
|
||||||
"sigs.k8s.io/external-dns/endpoint"
|
"sigs.k8s.io/external-dns/endpoint"
|
||||||
|
"sigs.k8s.io/external-dns/internal/testutils"
|
||||||
"sigs.k8s.io/external-dns/plan"
|
"sigs.k8s.io/external-dns/plan"
|
||||||
"sigs.k8s.io/external-dns/provider"
|
"sigs.k8s.io/external-dns/provider"
|
||||||
)
|
)
|
||||||
@ -112,6 +114,7 @@ func getDNSRecordFromRecordParams(rp any) cloudflare.DNSRecord {
|
|||||||
switch params := rp.(type) {
|
switch params := rp.(type) {
|
||||||
case cloudflare.CreateDNSRecordParams:
|
case cloudflare.CreateDNSRecordParams:
|
||||||
return cloudflare.DNSRecord{
|
return cloudflare.DNSRecord{
|
||||||
|
ID: params.ID,
|
||||||
Name: params.Name,
|
Name: params.Name,
|
||||||
TTL: params.TTL,
|
TTL: params.TTL,
|
||||||
Proxied: params.Proxied,
|
Proxied: params.Proxied,
|
||||||
@ -120,6 +123,7 @@ func getDNSRecordFromRecordParams(rp any) cloudflare.DNSRecord {
|
|||||||
}
|
}
|
||||||
case cloudflare.UpdateDNSRecordParams:
|
case cloudflare.UpdateDNSRecordParams:
|
||||||
return cloudflare.DNSRecord{
|
return cloudflare.DNSRecord{
|
||||||
|
ID: params.ID,
|
||||||
Name: params.Name,
|
Name: params.Name,
|
||||||
TTL: params.TTL,
|
TTL: params.TTL,
|
||||||
Proxied: params.Proxied,
|
Proxied: params.Proxied,
|
||||||
@ -131,16 +135,23 @@ func getDNSRecordFromRecordParams(rp any) cloudflare.DNSRecord {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func generateDNSRecordID(rrtype string, name string, content string) string {
|
||||||
|
return fmt.Sprintf("%s-%s-%s", name, rrtype, content)
|
||||||
|
}
|
||||||
|
|
||||||
func (m *mockCloudFlareClient) CreateDNSRecord(ctx context.Context, rc *cloudflare.ResourceContainer, rp cloudflare.CreateDNSRecordParams) (cloudflare.DNSRecord, error) {
|
func (m *mockCloudFlareClient) CreateDNSRecord(ctx context.Context, rc *cloudflare.ResourceContainer, rp cloudflare.CreateDNSRecordParams) (cloudflare.DNSRecord, error) {
|
||||||
recordData := getDNSRecordFromRecordParams(rp)
|
recordData := getDNSRecordFromRecordParams(rp)
|
||||||
|
if recordData.ID == "" {
|
||||||
|
recordData.ID = generateDNSRecordID(recordData.Type, recordData.Name, recordData.Content)
|
||||||
|
}
|
||||||
m.Actions = append(m.Actions, MockAction{
|
m.Actions = append(m.Actions, MockAction{
|
||||||
Name: "Create",
|
Name: "Create",
|
||||||
ZoneId: rc.Identifier,
|
ZoneId: rc.Identifier,
|
||||||
RecordId: rp.ID,
|
RecordId: recordData.ID,
|
||||||
RecordData: recordData,
|
RecordData: recordData,
|
||||||
})
|
})
|
||||||
if zone, ok := m.Records[rc.Identifier]; ok {
|
if zone, ok := m.Records[rc.Identifier]; ok {
|
||||||
zone[rp.ID] = recordData
|
zone[recordData.ID] = recordData
|
||||||
}
|
}
|
||||||
|
|
||||||
if recordData.Name == "newerror.bar.com" {
|
if recordData.Name == "newerror.bar.com" {
|
||||||
@ -156,6 +167,10 @@ func (m *mockCloudFlareClient) ListDNSRecords(ctx context.Context, rc *cloudflar
|
|||||||
result := []cloudflare.DNSRecord{}
|
result := []cloudflare.DNSRecord{}
|
||||||
if zone, ok := m.Records[rc.Identifier]; ok {
|
if zone, ok := m.Records[rc.Identifier]; ok {
|
||||||
for _, record := range zone {
|
for _, record := range zone {
|
||||||
|
if strings.HasPrefix(record.Name, "newerror-list-") {
|
||||||
|
m.DeleteDNSRecord(ctx, rc, record.ID)
|
||||||
|
return nil, &cloudflare.ResultInfo{}, errors.New("failed to list erroring DNS record")
|
||||||
|
}
|
||||||
result = append(result, record)
|
result = append(result, record)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -200,6 +215,9 @@ func (m *mockCloudFlareClient) UpdateDNSRecord(ctx context.Context, rc *cloudfla
|
|||||||
})
|
})
|
||||||
if zone, ok := m.Records[rc.Identifier]; ok {
|
if zone, ok := m.Records[rc.Identifier]; ok {
|
||||||
if _, ok := zone[rp.ID]; ok {
|
if _, ok := zone[rp.ID]; ok {
|
||||||
|
if strings.HasPrefix(recordData.Name, "newerror-update-") {
|
||||||
|
return errors.New("failed to update erroring DNS record")
|
||||||
|
}
|
||||||
zone[rp.ID] = recordData
|
zone[rp.ID] = recordData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -226,7 +244,11 @@ func (m *mockCloudFlareClient) DeleteDNSRecord(ctx context.Context, rc *cloudfla
|
|||||||
})
|
})
|
||||||
if zone, ok := m.Records[rc.Identifier]; ok {
|
if zone, ok := m.Records[rc.Identifier]; ok {
|
||||||
if _, ok := zone[recordID]; ok {
|
if _, ok := zone[recordID]; ok {
|
||||||
|
name := zone[recordID].Name
|
||||||
delete(zone, recordID)
|
delete(zone, recordID)
|
||||||
|
if strings.HasPrefix(name, "newerror-delete-") {
|
||||||
|
return errors.New("failed to delete erroring DNS record")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -240,6 +262,10 @@ func (m *mockCloudFlareClient) UserDetails(ctx context.Context) (cloudflare.User
|
|||||||
func (m *mockCloudFlareClient) CustomHostnames(ctx context.Context, zoneID string, page int, filter cloudflare.CustomHostname) ([]cloudflare.CustomHostname, cloudflare.ResultInfo, error) {
|
func (m *mockCloudFlareClient) CustomHostnames(ctx context.Context, zoneID string, page int, filter cloudflare.CustomHostname) ([]cloudflare.CustomHostname, cloudflare.ResultInfo, error) {
|
||||||
var err error = nil
|
var err error = nil
|
||||||
|
|
||||||
|
if strings.HasPrefix(zoneID, "newerror-") {
|
||||||
|
return nil, cloudflare.ResultInfo{}, errors.New("failed to list custom hostnames")
|
||||||
|
}
|
||||||
|
|
||||||
if page != 1 || filter.Hostname != "" {
|
if page != 1 || filter.Hostname != "" {
|
||||||
err = errors.New("pages and filters are not supported for custom hostnames mock test")
|
err = errors.New("pages and filters are not supported for custom hostnames mock test")
|
||||||
}
|
}
|
||||||
@ -247,6 +273,10 @@ func (m *mockCloudFlareClient) CustomHostnames(ctx context.Context, zoneID strin
|
|||||||
result := []cloudflare.CustomHostname{}
|
result := []cloudflare.CustomHostname{}
|
||||||
if zone, ok := m.customHostnames[zoneID]; ok {
|
if zone, ok := m.customHostnames[zoneID]; ok {
|
||||||
for _, ch := range zone {
|
for _, ch := range zone {
|
||||||
|
if strings.HasPrefix(ch.Hostname, "newerror-list-") {
|
||||||
|
m.DeleteCustomHostname(ctx, zoneID, ch.ID)
|
||||||
|
return nil, cloudflare.ResultInfo{}, errors.New("failed to list erroring custom hostname")
|
||||||
|
}
|
||||||
result = append(result, ch)
|
result = append(result, ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -262,10 +292,15 @@ func (m *mockCloudFlareClient) CustomHostnames(ctx context.Context, zoneID strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockCloudFlareClient) CreateCustomHostname(ctx context.Context, zoneID string, ch cloudflare.CustomHostname) (*cloudflare.CustomHostnameResponse, error) {
|
func (m *mockCloudFlareClient) CreateCustomHostname(ctx context.Context, zoneID string, ch cloudflare.CustomHostname) (*cloudflare.CustomHostnameResponse, error) {
|
||||||
|
if ch.Hostname == "" || ch.CustomOriginServer == "" || ch.Hostname == "newerror-create.foo.fancybar.com" {
|
||||||
|
return nil, fmt.Errorf("Invalid custom hostname or origin hostname")
|
||||||
|
}
|
||||||
if _, ok := m.customHostnames[zoneID]; !ok {
|
if _, ok := m.customHostnames[zoneID]; !ok {
|
||||||
m.customHostnames[zoneID] = map[string]cloudflare.CustomHostname{}
|
m.customHostnames[zoneID] = map[string]cloudflare.CustomHostname{}
|
||||||
}
|
}
|
||||||
m.customHostnames[zoneID][ch.ID] = ch
|
var newCustomHostname cloudflare.CustomHostname = ch
|
||||||
|
newCustomHostname.ID = fmt.Sprintf("ID-%s", ch.Hostname)
|
||||||
|
m.customHostnames[zoneID][newCustomHostname.ID] = newCustomHostname
|
||||||
return &cloudflare.CustomHostnameResponse{}, nil
|
return &cloudflare.CustomHostnameResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,9 +308,11 @@ func (m *mockCloudFlareClient) DeleteCustomHostname(ctx context.Context, zoneID
|
|||||||
if zone, ok := m.customHostnames[zoneID]; ok {
|
if zone, ok := m.customHostnames[zoneID]; ok {
|
||||||
if _, ok := zone[customHostnameID]; ok {
|
if _, ok := zone[customHostnameID]; ok {
|
||||||
delete(zone, customHostnameID)
|
delete(zone, customHostnameID)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if customHostnameID == "ID-newerror-delete.foo.fancybar.com" {
|
||||||
|
return fmt.Errorf("Invalid custom hostname to delete")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,6 +379,16 @@ func (m *mockCloudFlareClient) ZoneDetails(ctx context.Context, zoneID string) (
|
|||||||
return cloudflare.Zone{}, errors.New("Unknown zoneID: " + zoneID)
|
return cloudflare.Zone{}, errors.New("Unknown zoneID: " + zoneID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *CloudFlareProvider) getCustomHostnameIDbyCustomHostnameAndOrigin(chs []cloudflare.CustomHostname, customHostname string, origin string) (string, string) {
|
||||||
|
for _, zoneCh := range chs {
|
||||||
|
if zoneCh.Hostname == customHostname && zoneCh.CustomOriginServer == origin {
|
||||||
|
return zoneCh.ID, zoneCh.Hostname
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
|
||||||
func AssertActions(t *testing.T, provider *CloudFlareProvider, endpoints []*endpoint.Endpoint, actions []MockAction, managedRecords []string, args ...interface{}) {
|
func AssertActions(t *testing.T, provider *CloudFlareProvider, endpoints []*endpoint.Endpoint, actions []MockAction, managedRecords []string, args ...interface{}) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
@ -399,9 +446,11 @@ func TestCloudflareA(t *testing.T) {
|
|||||||
|
|
||||||
AssertActions(t, &CloudFlareProvider{}, endpoints, []MockAction{
|
AssertActions(t, &CloudFlareProvider{}, endpoints, []MockAction{
|
||||||
{
|
{
|
||||||
Name: "Create",
|
Name: "Create",
|
||||||
ZoneId: "001",
|
ZoneId: "001",
|
||||||
|
RecordId: generateDNSRecordID("A", "bar.com", "127.0.0.1"),
|
||||||
RecordData: cloudflare.DNSRecord{
|
RecordData: cloudflare.DNSRecord{
|
||||||
|
ID: generateDNSRecordID("A", "bar.com", "127.0.0.1"),
|
||||||
Type: "A",
|
Type: "A",
|
||||||
Name: "bar.com",
|
Name: "bar.com",
|
||||||
Content: "127.0.0.1",
|
Content: "127.0.0.1",
|
||||||
@ -410,9 +459,11 @@ func TestCloudflareA(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Create",
|
Name: "Create",
|
||||||
ZoneId: "001",
|
ZoneId: "001",
|
||||||
|
RecordId: generateDNSRecordID("A", "bar.com", "127.0.0.2"),
|
||||||
RecordData: cloudflare.DNSRecord{
|
RecordData: cloudflare.DNSRecord{
|
||||||
|
ID: generateDNSRecordID("A", "bar.com", "127.0.0.2"),
|
||||||
Type: "A",
|
Type: "A",
|
||||||
Name: "bar.com",
|
Name: "bar.com",
|
||||||
Content: "127.0.0.2",
|
Content: "127.0.0.2",
|
||||||
@ -436,9 +487,11 @@ func TestCloudflareCname(t *testing.T) {
|
|||||||
|
|
||||||
AssertActions(t, &CloudFlareProvider{}, endpoints, []MockAction{
|
AssertActions(t, &CloudFlareProvider{}, endpoints, []MockAction{
|
||||||
{
|
{
|
||||||
Name: "Create",
|
Name: "Create",
|
||||||
ZoneId: "001",
|
ZoneId: "001",
|
||||||
|
RecordId: generateDNSRecordID("CNAME", "cname.bar.com", "google.com"),
|
||||||
RecordData: cloudflare.DNSRecord{
|
RecordData: cloudflare.DNSRecord{
|
||||||
|
ID: generateDNSRecordID("CNAME", "cname.bar.com", "google.com"),
|
||||||
Type: "CNAME",
|
Type: "CNAME",
|
||||||
Name: "cname.bar.com",
|
Name: "cname.bar.com",
|
||||||
Content: "google.com",
|
Content: "google.com",
|
||||||
@ -447,9 +500,11 @@ func TestCloudflareCname(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Create",
|
Name: "Create",
|
||||||
ZoneId: "001",
|
ZoneId: "001",
|
||||||
|
RecordId: generateDNSRecordID("CNAME", "cname.bar.com", "facebook.com"),
|
||||||
RecordData: cloudflare.DNSRecord{
|
RecordData: cloudflare.DNSRecord{
|
||||||
|
ID: generateDNSRecordID("CNAME", "cname.bar.com", "facebook.com"),
|
||||||
Type: "CNAME",
|
Type: "CNAME",
|
||||||
Name: "cname.bar.com",
|
Name: "cname.bar.com",
|
||||||
Content: "facebook.com",
|
Content: "facebook.com",
|
||||||
@ -474,9 +529,11 @@ func TestCloudflareCustomTTL(t *testing.T) {
|
|||||||
|
|
||||||
AssertActions(t, &CloudFlareProvider{}, endpoints, []MockAction{
|
AssertActions(t, &CloudFlareProvider{}, endpoints, []MockAction{
|
||||||
{
|
{
|
||||||
Name: "Create",
|
Name: "Create",
|
||||||
ZoneId: "001",
|
ZoneId: "001",
|
||||||
|
RecordId: generateDNSRecordID("A", "ttl.bar.com", "127.0.0.1"),
|
||||||
RecordData: cloudflare.DNSRecord{
|
RecordData: cloudflare.DNSRecord{
|
||||||
|
ID: generateDNSRecordID("A", "ttl.bar.com", "127.0.0.1"),
|
||||||
Type: "A",
|
Type: "A",
|
||||||
Name: "ttl.bar.com",
|
Name: "ttl.bar.com",
|
||||||
Content: "127.0.0.1",
|
Content: "127.0.0.1",
|
||||||
@ -500,9 +557,11 @@ func TestCloudflareProxiedDefault(t *testing.T) {
|
|||||||
|
|
||||||
AssertActions(t, &CloudFlareProvider{proxiedByDefault: true}, endpoints, []MockAction{
|
AssertActions(t, &CloudFlareProvider{proxiedByDefault: true}, endpoints, []MockAction{
|
||||||
{
|
{
|
||||||
Name: "Create",
|
Name: "Create",
|
||||||
ZoneId: "001",
|
ZoneId: "001",
|
||||||
|
RecordId: generateDNSRecordID("A", "bar.com", "127.0.0.1"),
|
||||||
RecordData: cloudflare.DNSRecord{
|
RecordData: cloudflare.DNSRecord{
|
||||||
|
ID: generateDNSRecordID("A", "bar.com", "127.0.0.1"),
|
||||||
Type: "A",
|
Type: "A",
|
||||||
Name: "bar.com",
|
Name: "bar.com",
|
||||||
Content: "127.0.0.1",
|
Content: "127.0.0.1",
|
||||||
@ -532,9 +591,11 @@ func TestCloudflareProxiedOverrideTrue(t *testing.T) {
|
|||||||
|
|
||||||
AssertActions(t, &CloudFlareProvider{}, endpoints, []MockAction{
|
AssertActions(t, &CloudFlareProvider{}, endpoints, []MockAction{
|
||||||
{
|
{
|
||||||
Name: "Create",
|
Name: "Create",
|
||||||
ZoneId: "001",
|
ZoneId: "001",
|
||||||
|
RecordId: generateDNSRecordID("A", "bar.com", "127.0.0.1"),
|
||||||
RecordData: cloudflare.DNSRecord{
|
RecordData: cloudflare.DNSRecord{
|
||||||
|
ID: generateDNSRecordID("A", "bar.com", "127.0.0.1"),
|
||||||
Type: "A",
|
Type: "A",
|
||||||
Name: "bar.com",
|
Name: "bar.com",
|
||||||
Content: "127.0.0.1",
|
Content: "127.0.0.1",
|
||||||
@ -564,9 +625,11 @@ func TestCloudflareProxiedOverrideFalse(t *testing.T) {
|
|||||||
|
|
||||||
AssertActions(t, &CloudFlareProvider{proxiedByDefault: true}, endpoints, []MockAction{
|
AssertActions(t, &CloudFlareProvider{proxiedByDefault: true}, endpoints, []MockAction{
|
||||||
{
|
{
|
||||||
Name: "Create",
|
Name: "Create",
|
||||||
ZoneId: "001",
|
ZoneId: "001",
|
||||||
|
RecordId: generateDNSRecordID("A", "bar.com", "127.0.0.1"),
|
||||||
RecordData: cloudflare.DNSRecord{
|
RecordData: cloudflare.DNSRecord{
|
||||||
|
ID: generateDNSRecordID("A", "bar.com", "127.0.0.1"),
|
||||||
Type: "A",
|
Type: "A",
|
||||||
Name: "bar.com",
|
Name: "bar.com",
|
||||||
Content: "127.0.0.1",
|
Content: "127.0.0.1",
|
||||||
@ -596,9 +659,11 @@ func TestCloudflareProxiedOverrideIllegal(t *testing.T) {
|
|||||||
|
|
||||||
AssertActions(t, &CloudFlareProvider{proxiedByDefault: true}, endpoints, []MockAction{
|
AssertActions(t, &CloudFlareProvider{proxiedByDefault: true}, endpoints, []MockAction{
|
||||||
{
|
{
|
||||||
Name: "Create",
|
Name: "Create",
|
||||||
ZoneId: "001",
|
ZoneId: "001",
|
||||||
|
RecordId: generateDNSRecordID("A", "bar.com", "127.0.0.1"),
|
||||||
RecordData: cloudflare.DNSRecord{
|
RecordData: cloudflare.DNSRecord{
|
||||||
|
ID: generateDNSRecordID("A", "bar.com", "127.0.0.1"),
|
||||||
Type: "A",
|
Type: "A",
|
||||||
Name: "bar.com",
|
Name: "bar.com",
|
||||||
Content: "127.0.0.1",
|
Content: "127.0.0.1",
|
||||||
@ -631,11 +696,12 @@ func TestCloudflareSetProxied(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
|
target := "127.0.0.1"
|
||||||
endpoints := []*endpoint.Endpoint{
|
endpoints := []*endpoint.Endpoint{
|
||||||
{
|
{
|
||||||
RecordType: testCase.recordType,
|
RecordType: testCase.recordType,
|
||||||
DNSName: testCase.domain,
|
DNSName: testCase.domain,
|
||||||
Targets: endpoint.Targets{"127.0.0.1"},
|
Targets: endpoint.Targets{target},
|
||||||
ProviderSpecific: endpoint.ProviderSpecific{
|
ProviderSpecific: endpoint.ProviderSpecific{
|
||||||
endpoint.ProviderSpecificProperty{
|
endpoint.ProviderSpecificProperty{
|
||||||
Name: "external-dns.alpha.kubernetes.io/cloudflare-proxied",
|
Name: "external-dns.alpha.kubernetes.io/cloudflare-proxied",
|
||||||
@ -644,12 +710,14 @@ func TestCloudflareSetProxied(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
expectedID := fmt.Sprintf("%s-%s-%s", testCase.domain, testCase.recordType, target)
|
||||||
AssertActions(t, &CloudFlareProvider{}, endpoints, []MockAction{
|
AssertActions(t, &CloudFlareProvider{}, endpoints, []MockAction{
|
||||||
{
|
{
|
||||||
Name: "Create",
|
Name: "Create",
|
||||||
ZoneId: "001",
|
ZoneId: "001",
|
||||||
|
RecordId: expectedID,
|
||||||
RecordData: cloudflare.DNSRecord{
|
RecordData: cloudflare.DNSRecord{
|
||||||
|
ID: expectedID,
|
||||||
Type: testCase.recordType,
|
Type: testCase.recordType,
|
||||||
Name: testCase.domain,
|
Name: testCase.domain,
|
||||||
Content: "127.0.0.1",
|
Content: "127.0.0.1",
|
||||||
@ -795,7 +863,8 @@ func TestCloudflareProvider(t *testing.T) {
|
|||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
5000,
|
5000,
|
||||||
"")
|
"",
|
||||||
|
CustomHostnamesConfig{Enabled: false})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("should not fail, %s", err)
|
t.Errorf("should not fail, %s", err)
|
||||||
}
|
}
|
||||||
@ -812,7 +881,8 @@ func TestCloudflareProvider(t *testing.T) {
|
|||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
5000,
|
5000,
|
||||||
"")
|
"",
|
||||||
|
CustomHostnamesConfig{Enabled: false})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("should not fail, %s", err)
|
t.Errorf("should not fail, %s", err)
|
||||||
}
|
}
|
||||||
@ -826,7 +896,8 @@ func TestCloudflareProvider(t *testing.T) {
|
|||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
5000,
|
5000,
|
||||||
"")
|
"",
|
||||||
|
CustomHostnamesConfig{Enabled: false})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("should not fail, %s", err)
|
t.Errorf("should not fail, %s", err)
|
||||||
}
|
}
|
||||||
@ -839,7 +910,8 @@ func TestCloudflareProvider(t *testing.T) {
|
|||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
5000,
|
5000,
|
||||||
"")
|
"",
|
||||||
|
CustomHostnamesConfig{Enabled: false})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("expected to fail")
|
t.Errorf("expected to fail")
|
||||||
}
|
}
|
||||||
@ -877,9 +949,11 @@ func TestCloudflareApplyChanges(t *testing.T) {
|
|||||||
|
|
||||||
td.Cmp(t, client.Actions, []MockAction{
|
td.Cmp(t, client.Actions, []MockAction{
|
||||||
{
|
{
|
||||||
Name: "Create",
|
Name: "Create",
|
||||||
ZoneId: "001",
|
ZoneId: "001",
|
||||||
|
RecordId: generateDNSRecordID("", "new.bar.com", "target"),
|
||||||
RecordData: cloudflare.DNSRecord{
|
RecordData: cloudflare.DNSRecord{
|
||||||
|
ID: generateDNSRecordID("", "new.bar.com", "target"),
|
||||||
Name: "new.bar.com",
|
Name: "new.bar.com",
|
||||||
Content: "target",
|
Content: "target",
|
||||||
TTL: 1,
|
TTL: 1,
|
||||||
@ -887,9 +961,11 @@ func TestCloudflareApplyChanges(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Create",
|
Name: "Create",
|
||||||
ZoneId: "001",
|
ZoneId: "001",
|
||||||
|
RecordId: generateDNSRecordID("", "foobar.bar.com", "target-new"),
|
||||||
RecordData: cloudflare.DNSRecord{
|
RecordData: cloudflare.DNSRecord{
|
||||||
|
ID: generateDNSRecordID("", "foobar.bar.com", "target-new"),
|
||||||
Name: "foobar.bar.com",
|
Name: "foobar.bar.com",
|
||||||
Content: "target-new",
|
Content: "target-new",
|
||||||
TTL: 1,
|
TTL: 1,
|
||||||
@ -1366,9 +1442,11 @@ func TestCloudflareComplexUpdate(t *testing.T) {
|
|||||||
RecordId: "2345678901",
|
RecordId: "2345678901",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Create",
|
Name: "Create",
|
||||||
ZoneId: "001",
|
ZoneId: "001",
|
||||||
|
RecordId: generateDNSRecordID("A", "foobar.bar.com", "2.3.4.5"),
|
||||||
RecordData: cloudflare.DNSRecord{
|
RecordData: cloudflare.DNSRecord{
|
||||||
|
ID: generateDNSRecordID("A", "foobar.bar.com", "2.3.4.5"),
|
||||||
Name: "foobar.bar.com",
|
Name: "foobar.bar.com",
|
||||||
Type: "A",
|
Type: "A",
|
||||||
Content: "2.3.4.5",
|
Content: "2.3.4.5",
|
||||||
@ -1381,6 +1459,7 @@ func TestCloudflareComplexUpdate(t *testing.T) {
|
|||||||
ZoneId: "001",
|
ZoneId: "001",
|
||||||
RecordId: "1234567890",
|
RecordId: "1234567890",
|
||||||
RecordData: cloudflare.DNSRecord{
|
RecordData: cloudflare.DNSRecord{
|
||||||
|
ID: "1234567890",
|
||||||
Name: "foobar.bar.com",
|
Name: "foobar.bar.com",
|
||||||
Type: "A",
|
Type: "A",
|
||||||
Content: "1.2.3.4",
|
Content: "1.2.3.4",
|
||||||
@ -1451,7 +1530,14 @@ func TestCustomTTLWithEnabledProxyNotChanged(t *testing.T) {
|
|||||||
func TestCloudFlareProvider_Region(t *testing.T) {
|
func TestCloudFlareProvider_Region(t *testing.T) {
|
||||||
_ = os.Setenv("CF_API_TOKEN", "abc123def")
|
_ = os.Setenv("CF_API_TOKEN", "abc123def")
|
||||||
_ = os.Setenv("CF_API_EMAIL", "test@test.com")
|
_ = os.Setenv("CF_API_EMAIL", "test@test.com")
|
||||||
provider, err := NewCloudFlareProvider(endpoint.NewDomainFilter([]string{"example.com"}), provider.ZoneIDFilter{}, true, false, 50, "us")
|
provider, err := NewCloudFlareProvider(
|
||||||
|
endpoint.NewDomainFilter([]string{"example.com"}),
|
||||||
|
provider.ZoneIDFilter{},
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
50,
|
||||||
|
"us",
|
||||||
|
CustomHostnamesConfig{Enabled: false})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -1482,7 +1568,14 @@ func TestCloudFlareProvider_updateDataLocalizationRegionalHostnameParams(t *test
|
|||||||
func TestCloudFlareProvider_newCloudFlareChange(t *testing.T) {
|
func TestCloudFlareProvider_newCloudFlareChange(t *testing.T) {
|
||||||
_ = os.Setenv("CF_API_KEY", "xxxxxxxxxxxxxxxxx")
|
_ = os.Setenv("CF_API_KEY", "xxxxxxxxxxxxxxxxx")
|
||||||
_ = os.Setenv("CF_API_EMAIL", "test@test.com")
|
_ = os.Setenv("CF_API_EMAIL", "test@test.com")
|
||||||
provider, err := NewCloudFlareProvider(endpoint.NewDomainFilter([]string{"example.com"}), provider.ZoneIDFilter{}, true, false, 50, "us")
|
provider, err := NewCloudFlareProvider(
|
||||||
|
endpoint.NewDomainFilter([]string{"example.com"}),
|
||||||
|
provider.ZoneIDFilter{},
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
50,
|
||||||
|
"us",
|
||||||
|
CustomHostnamesConfig{Enabled: false})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -1492,7 +1585,7 @@ func TestCloudFlareProvider_newCloudFlareChange(t *testing.T) {
|
|||||||
Targets: []string{"192.0.2.1"},
|
Targets: []string{"192.0.2.1"},
|
||||||
}
|
}
|
||||||
|
|
||||||
change := provider.newCloudFlareChange(cloudFlareCreate, endpoint, endpoint.Targets[0])
|
change := provider.newCloudFlareChange(cloudFlareCreate, endpoint, endpoint.Targets[0], nil)
|
||||||
if change.RegionalHostname.RegionKey != "us" {
|
if change.RegionalHostname.RegionKey != "us" {
|
||||||
t.Errorf("expected region key to be 'us', but got '%s'", change.RegionalHostname.RegionKey)
|
t.Errorf("expected region key to be 'us', but got '%s'", change.RegionalHostname.RegionKey)
|
||||||
}
|
}
|
||||||
@ -1621,33 +1714,353 @@ func TestCloudFlareProvider_submitChangesApex(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCloudflareCustomHostnameOperations(t *testing.T) {
|
func TestCloudflareZoneRecordsFail(t *testing.T) {
|
||||||
client := NewMockCloudFlareClientWithRecords(map[string][]cloudflare.DNSRecord{
|
client := &mockCloudFlareClient{
|
||||||
"001": ExampleDomain,
|
Zones: map[string]string{
|
||||||
})
|
"newerror-001": "bar.com",
|
||||||
provider := &CloudFlareProvider{
|
},
|
||||||
Client: client,
|
Records: map[string]map[string]cloudflare.DNSRecord{},
|
||||||
|
customHostnames: map[string]map[string]cloudflare.CustomHostname{},
|
||||||
|
}
|
||||||
|
failingProvider := &CloudFlareProvider{
|
||||||
|
Client: client,
|
||||||
|
CustomHostnamesConfig: CustomHostnamesConfig{Enabled: true},
|
||||||
}
|
}
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
records, err := provider.Records(ctx)
|
_, err := failingProvider.Records(ctx)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
t.Errorf("should not fail, %s", err)
|
t.Errorf("should fail - invalid zone id, %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCloudflareDNSRecordsOperationsFail(t *testing.T) {
|
||||||
|
client := NewMockCloudFlareClient()
|
||||||
|
provider := &CloudFlareProvider{
|
||||||
|
Client: client,
|
||||||
|
CustomHostnamesConfig: CustomHostnamesConfig{Enabled: true},
|
||||||
|
}
|
||||||
|
ctx := context.Background()
|
||||||
|
domainFilter := endpoint.NewDomainFilter([]string{"bar.com"})
|
||||||
|
|
||||||
|
testFailCases := []struct {
|
||||||
|
Name string
|
||||||
|
Endpoints []*endpoint.Endpoint
|
||||||
|
ExpectedCustomHostnames map[string]string
|
||||||
|
shouldFail bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Name: "failing to create dns record",
|
||||||
|
Endpoints: []*endpoint.Endpoint{
|
||||||
|
{
|
||||||
|
DNSName: "newerror.bar.com",
|
||||||
|
Targets: endpoint.Targets{"1.2.3.4"},
|
||||||
|
RecordType: endpoint.RecordTypeA,
|
||||||
|
RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL),
|
||||||
|
Labels: endpoint.Labels{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "failing to list DNS record",
|
||||||
|
Endpoints: []*endpoint.Endpoint{
|
||||||
|
{
|
||||||
|
DNSName: "newerror-list-1.foo.bar.com",
|
||||||
|
Targets: endpoint.Targets{"1.2.3.4"},
|
||||||
|
RecordType: endpoint.RecordTypeA,
|
||||||
|
RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL),
|
||||||
|
Labels: endpoint.Labels{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "create failing to update DNS record",
|
||||||
|
Endpoints: []*endpoint.Endpoint{
|
||||||
|
{
|
||||||
|
DNSName: "newerror-update-1.foo.bar.com",
|
||||||
|
Targets: endpoint.Targets{"1.2.3.4"},
|
||||||
|
RecordType: endpoint.RecordTypeA,
|
||||||
|
RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL),
|
||||||
|
Labels: endpoint.Labels{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "failing to update DNS record",
|
||||||
|
Endpoints: []*endpoint.Endpoint{
|
||||||
|
{
|
||||||
|
DNSName: "newerror-update-1.foo.bar.com",
|
||||||
|
Targets: endpoint.Targets{"1.2.3.4"},
|
||||||
|
RecordType: endpoint.RecordTypeA,
|
||||||
|
RecordTTL: 1234,
|
||||||
|
Labels: endpoint.Labels{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "create failing to delete DNS record",
|
||||||
|
Endpoints: []*endpoint.Endpoint{
|
||||||
|
{
|
||||||
|
DNSName: "newerror-delete-1.foo.bar.com",
|
||||||
|
Targets: endpoint.Targets{"1.2.3.4"},
|
||||||
|
RecordType: endpoint.RecordTypeA,
|
||||||
|
RecordTTL: 1234,
|
||||||
|
Labels: endpoint.Labels{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "failing to delete erroring DNS record",
|
||||||
|
Endpoints: []*endpoint.Endpoint{},
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, tc := range testFailCases {
|
||||||
|
records, err := provider.Records(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("should not fail, %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoints, err := provider.AdjustEndpoints(tc.Endpoints)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
plan := &plan.Plan{
|
||||||
|
Current: records,
|
||||||
|
Desired: endpoints,
|
||||||
|
DomainFilter: endpoint.MatchAllDomainFilters{&domainFilter},
|
||||||
|
ManagedRecords: []string{endpoint.RecordTypeA, endpoint.RecordTypeCNAME},
|
||||||
|
}
|
||||||
|
|
||||||
|
planned := plan.Calculate()
|
||||||
|
|
||||||
|
err = provider.ApplyChanges(context.Background(), planned.Changes)
|
||||||
|
if err == nil && tc.shouldFail {
|
||||||
|
t.Errorf("should fail - %s, %s", tc.Name, err)
|
||||||
|
} else if err != nil && !tc.shouldFail {
|
||||||
|
t.Errorf("should not fail - %s, %s", tc.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCloudflareCustomHostnameOperations(t *testing.T) {
|
||||||
|
client := NewMockCloudFlareClient()
|
||||||
|
provider := &CloudFlareProvider{
|
||||||
|
Client: client,
|
||||||
|
CustomHostnamesConfig: CustomHostnamesConfig{Enabled: true},
|
||||||
|
}
|
||||||
|
ctx := context.Background()
|
||||||
domainFilter := endpoint.NewDomainFilter([]string{"bar.com"})
|
domainFilter := endpoint.NewDomainFilter([]string{"bar.com"})
|
||||||
|
|
||||||
|
testFailCases := []struct {
|
||||||
|
Name string
|
||||||
|
Endpoints []*endpoint.Endpoint
|
||||||
|
ExpectedCustomHostnames map[string]string
|
||||||
|
shouldFail bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Name: "failing to create custom hostname on record creation",
|
||||||
|
Endpoints: []*endpoint.Endpoint{
|
||||||
|
{
|
||||||
|
DNSName: "create.foo.bar.com",
|
||||||
|
Targets: endpoint.Targets{"1.2.3.4"},
|
||||||
|
RecordType: endpoint.RecordTypeA,
|
||||||
|
RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL),
|
||||||
|
Labels: endpoint.Labels{},
|
||||||
|
ProviderSpecific: endpoint.ProviderSpecific{
|
||||||
|
{
|
||||||
|
Name: "external-dns.alpha.kubernetes.io/cloudflare-custom-hostname",
|
||||||
|
Value: "newerror-create.foo.fancybar.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "add custom hostname to more than one endpoint",
|
||||||
|
Endpoints: []*endpoint.Endpoint{
|
||||||
|
{
|
||||||
|
DNSName: "fail.foo.bar.com",
|
||||||
|
Targets: endpoint.Targets{"1.2.3.4", "2.3.4.5"},
|
||||||
|
RecordType: endpoint.RecordTypeA,
|
||||||
|
RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL),
|
||||||
|
Labels: endpoint.Labels{},
|
||||||
|
ProviderSpecific: endpoint.ProviderSpecific{
|
||||||
|
{
|
||||||
|
Name: "external-dns.alpha.kubernetes.io/cloudflare-custom-hostname",
|
||||||
|
Value: "fail.foo.fancybar.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "failing to update custom hostname",
|
||||||
|
Endpoints: []*endpoint.Endpoint{
|
||||||
|
{
|
||||||
|
DNSName: "fail.foo.bar.com",
|
||||||
|
Targets: endpoint.Targets{"1.2.3.4"},
|
||||||
|
RecordType: endpoint.RecordTypeA,
|
||||||
|
RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL),
|
||||||
|
Labels: endpoint.Labels{},
|
||||||
|
ProviderSpecific: endpoint.ProviderSpecific{
|
||||||
|
{
|
||||||
|
Name: "external-dns.alpha.kubernetes.io/cloudflare-custom-hostname",
|
||||||
|
Value: "newerror-create.foo.fancybar.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "adding failing to list custom hostname",
|
||||||
|
Endpoints: []*endpoint.Endpoint{
|
||||||
|
{
|
||||||
|
DNSName: "fail.list.foo.bar.com",
|
||||||
|
Targets: endpoint.Targets{"1.2.3.4"},
|
||||||
|
RecordType: endpoint.RecordTypeA,
|
||||||
|
RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL),
|
||||||
|
Labels: endpoint.Labels{},
|
||||||
|
ProviderSpecific: endpoint.ProviderSpecific{
|
||||||
|
{
|
||||||
|
Name: "external-dns.alpha.kubernetes.io/cloudflare-custom-hostname",
|
||||||
|
Value: "newerror-list-1.foo.fancybar.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "adding normal custom hostname",
|
||||||
|
Endpoints: []*endpoint.Endpoint{
|
||||||
|
{
|
||||||
|
DNSName: "b.foo.bar.com",
|
||||||
|
Targets: endpoint.Targets{"1.2.3.4"},
|
||||||
|
RecordType: endpoint.RecordTypeA,
|
||||||
|
RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL),
|
||||||
|
Labels: endpoint.Labels{},
|
||||||
|
ProviderSpecific: endpoint.ProviderSpecific{
|
||||||
|
{
|
||||||
|
Name: "external-dns.alpha.kubernetes.io/cloudflare-custom-hostname",
|
||||||
|
Value: "b.foo.fancybar.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "updating to erroring custom hostname",
|
||||||
|
Endpoints: []*endpoint.Endpoint{
|
||||||
|
{
|
||||||
|
DNSName: "b.foo.bar.com",
|
||||||
|
Targets: endpoint.Targets{"1.2.3.4"},
|
||||||
|
RecordType: endpoint.RecordTypeA,
|
||||||
|
RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL),
|
||||||
|
Labels: endpoint.Labels{},
|
||||||
|
ProviderSpecific: endpoint.ProviderSpecific{
|
||||||
|
{
|
||||||
|
Name: "external-dns.alpha.kubernetes.io/cloudflare-custom-hostname",
|
||||||
|
Value: "newerror-create.foo.fancybar.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "set to custom hostname which would error on removing",
|
||||||
|
Endpoints: []*endpoint.Endpoint{
|
||||||
|
{
|
||||||
|
DNSName: "b.foo.bar.com",
|
||||||
|
Targets: endpoint.Targets{"1.2.3.4"},
|
||||||
|
RecordType: endpoint.RecordTypeA,
|
||||||
|
RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL),
|
||||||
|
Labels: endpoint.Labels{},
|
||||||
|
ProviderSpecific: endpoint.ProviderSpecific{
|
||||||
|
{
|
||||||
|
Name: "external-dns.alpha.kubernetes.io/cloudflare-custom-hostname",
|
||||||
|
Value: "newerror-delete.foo.fancybar.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "delete erroring on remove custom hostname",
|
||||||
|
Endpoints: []*endpoint.Endpoint{
|
||||||
|
{
|
||||||
|
DNSName: "b.foo.bar.com",
|
||||||
|
Targets: endpoint.Targets{"1.2.3.4"},
|
||||||
|
RecordType: endpoint.RecordTypeA,
|
||||||
|
RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL),
|
||||||
|
Labels: endpoint.Labels{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "create erroring to remove custom hostname on record deletion",
|
||||||
|
Endpoints: []*endpoint.Endpoint{
|
||||||
|
{
|
||||||
|
DNSName: "b.foo.bar.com",
|
||||||
|
Targets: endpoint.Targets{"1.2.3.4"},
|
||||||
|
RecordType: endpoint.RecordTypeA,
|
||||||
|
RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL),
|
||||||
|
Labels: endpoint.Labels{},
|
||||||
|
ProviderSpecific: endpoint.ProviderSpecific{
|
||||||
|
{
|
||||||
|
Name: "external-dns.alpha.kubernetes.io/cloudflare-custom-hostname",
|
||||||
|
Value: "newerror-delete.foo.fancybar.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "failing to remove custom hostname on record deletion",
|
||||||
|
Endpoints: []*endpoint.Endpoint{},
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
Name string
|
Name string
|
||||||
Endpoints []*endpoint.Endpoint
|
Endpoints []*endpoint.Endpoint
|
||||||
ExpectedCustomHostnames map[string]string
|
ExpectedCustomHostnames map[string]string
|
||||||
}{
|
}{
|
||||||
|
{
|
||||||
|
Name: "add A record without custom hostname",
|
||||||
|
Endpoints: []*endpoint.Endpoint{
|
||||||
|
{
|
||||||
|
DNSName: "nocustomhostname.foo.bar.com",
|
||||||
|
Targets: endpoint.Targets{"1.2.3.4"},
|
||||||
|
RecordType: endpoint.RecordTypeA,
|
||||||
|
RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL),
|
||||||
|
Labels: endpoint.Labels{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ExpectedCustomHostnames: map[string]string{
|
||||||
|
"nocustomhostname.foo.bar.com": "",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "add custom hostname",
|
Name: "add custom hostname",
|
||||||
Endpoints: []*endpoint.Endpoint{
|
Endpoints: []*endpoint.Endpoint{
|
||||||
{
|
{
|
||||||
DNSName: "a.foo.bar.com",
|
DNSName: "a.foo.bar.com",
|
||||||
Targets: endpoint.Targets{"1.2.3.4", "2.3.4.5"},
|
Targets: endpoint.Targets{"1.2.3.4"},
|
||||||
RecordType: endpoint.RecordTypeA,
|
RecordType: endpoint.RecordTypeA,
|
||||||
RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL),
|
RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL),
|
||||||
Labels: endpoint.Labels{},
|
Labels: endpoint.Labels{},
|
||||||
@ -1682,7 +2095,7 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
|
|||||||
Endpoints: []*endpoint.Endpoint{
|
Endpoints: []*endpoint.Endpoint{
|
||||||
{
|
{
|
||||||
DNSName: "a.foo.bar.com",
|
DNSName: "a.foo.bar.com",
|
||||||
Targets: endpoint.Targets{"1.2.3.4", "2.3.4.5"},
|
Targets: endpoint.Targets{"1.2.3.4"},
|
||||||
RecordType: endpoint.RecordTypeA,
|
RecordType: endpoint.RecordTypeA,
|
||||||
RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL),
|
RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL),
|
||||||
Labels: endpoint.Labels{},
|
Labels: endpoint.Labels{},
|
||||||
@ -1694,24 +2107,60 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ExpectedCustomHostnames: map[string]string{"a.foo.bar.com": "a2.foo.fancybar.com"},
|
ExpectedCustomHostnames: map[string]string{
|
||||||
|
"a.foo.bar.com": "a2.foo.fancybar.com",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "delete custom hostname",
|
Name: "delete custom hostname",
|
||||||
Endpoints: []*endpoint.Endpoint{
|
Endpoints: []*endpoint.Endpoint{
|
||||||
|
|
||||||
{
|
{
|
||||||
DNSName: "a.foo.bar.com",
|
DNSName: "a.foo.bar.com",
|
||||||
Targets: endpoint.Targets{"1.2.3.4", "2.3.4.5"},
|
Targets: endpoint.Targets{"1.2.3.4"},
|
||||||
RecordType: endpoint.RecordTypeA,
|
RecordType: endpoint.RecordTypeA,
|
||||||
RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL),
|
RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL),
|
||||||
Labels: endpoint.Labels{},
|
Labels: endpoint.Labels{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ExpectedCustomHostnames: map[string]string{"a.foo.bar.com": ""},
|
ExpectedCustomHostnames: map[string]string{
|
||||||
|
"a.foo.bar.com": "",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, tc := range testFailCases {
|
||||||
|
records, err := provider.Records(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("should not fail, %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoints, err := provider.AdjustEndpoints(tc.Endpoints)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
plan := &plan.Plan{
|
||||||
|
Current: records,
|
||||||
|
Desired: endpoints,
|
||||||
|
DomainFilter: endpoint.MatchAllDomainFilters{&domainFilter},
|
||||||
|
ManagedRecords: []string{endpoint.RecordTypeA, endpoint.RecordTypeCNAME},
|
||||||
|
}
|
||||||
|
|
||||||
|
planned := plan.Calculate()
|
||||||
|
|
||||||
|
err = provider.ApplyChanges(context.Background(), planned.Changes)
|
||||||
|
if err == nil && tc.shouldFail {
|
||||||
|
t.Errorf("should fail - %s, %s", tc.Name, err)
|
||||||
|
} else if err != nil && !tc.shouldFail {
|
||||||
|
t.Errorf("should not fail - %s, %s", tc.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
records, err := provider.Records(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("should not fail, %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
endpoints, err := provider.AdjustEndpoints(tc.Endpoints)
|
endpoints, err := provider.AdjustEndpoints(tc.Endpoints)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@ -1726,17 +2175,106 @@ func TestCloudflareCustomHostnameOperations(t *testing.T) {
|
|||||||
|
|
||||||
err = provider.ApplyChanges(context.Background(), planned.Changes)
|
err = provider.ApplyChanges(context.Background(), planned.Changes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("should not fail, %s", err)
|
t.Errorf("should not fail - %s, %s", tc.Name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
chs, chErr := provider.listCustomHostnamesWithPagination(ctx, "001")
|
chs, chErr := provider.listCustomHostnamesWithPagination(ctx, "001")
|
||||||
if chErr != nil {
|
if chErr != nil {
|
||||||
t.Errorf("should not fail, %s", chErr)
|
t.Errorf("should not fail - %s, %s", tc.Name, chErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range tc.ExpectedCustomHostnames {
|
for expectedOrigin, expectedCustomHostname := range tc.ExpectedCustomHostnames {
|
||||||
_, ch := provider.getCustomHostnameIDbyOrigin(chs, k)
|
_, ch := provider.getCustomHostnameIDbyCustomHostnameAndOrigin(chs, expectedCustomHostname, expectedOrigin)
|
||||||
assert.Equal(t, v, ch)
|
assert.Equal(t, expectedCustomHostname, ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCloudflareCustomHostnameNotFoundOnRecordDeletion(t *testing.T) {
|
||||||
|
client := NewMockCloudFlareClient()
|
||||||
|
provider := &CloudFlareProvider{
|
||||||
|
Client: client,
|
||||||
|
CustomHostnamesConfig: CustomHostnamesConfig{Enabled: true},
|
||||||
|
}
|
||||||
|
ctx := context.Background()
|
||||||
|
zoneID := "001"
|
||||||
|
domainFilter := endpoint.NewDomainFilter([]string{"bar.com"})
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
Name string
|
||||||
|
Endpoints []*endpoint.Endpoint
|
||||||
|
ExpectedCustomHostnames map[string]string
|
||||||
|
preApplyHook bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Name: "create DNS record with custom hostname",
|
||||||
|
Endpoints: []*endpoint.Endpoint{
|
||||||
|
{
|
||||||
|
DNSName: "create.foo.bar.com",
|
||||||
|
Targets: endpoint.Targets{"1.2.3.4"},
|
||||||
|
RecordType: endpoint.RecordTypeA,
|
||||||
|
RecordTTL: endpoint.TTL(defaultCloudFlareRecordTTL),
|
||||||
|
Labels: endpoint.Labels{},
|
||||||
|
ProviderSpecific: endpoint.ProviderSpecific{
|
||||||
|
{
|
||||||
|
Name: "external-dns.alpha.kubernetes.io/cloudflare-custom-hostname",
|
||||||
|
Value: "newerror-getCustomHostnameOrigin.foo.fancybar.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
preApplyHook: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "remove DNS record with unexpectedly missing custom hostname",
|
||||||
|
Endpoints: []*endpoint.Endpoint{},
|
||||||
|
preApplyHook: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
b := testutils.LogsToBuffer(log.InfoLevel, t)
|
||||||
|
for _, tc := range testCases {
|
||||||
|
records, err := provider.Records(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("should not fail, %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoints, err := provider.AdjustEndpoints(tc.Endpoints)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
plan := &plan.Plan{
|
||||||
|
Current: records,
|
||||||
|
Desired: endpoints,
|
||||||
|
DomainFilter: endpoint.MatchAllDomainFilters{&domainFilter},
|
||||||
|
ManagedRecords: []string{endpoint.RecordTypeA, endpoint.RecordTypeCNAME},
|
||||||
|
}
|
||||||
|
|
||||||
|
planned := plan.Calculate()
|
||||||
|
|
||||||
|
// manually corrupt custom hostname before the deletion step
|
||||||
|
// the purpose is to cause getCustomHostnameOrigin() to fail on change.Action == cloudFlareDelete
|
||||||
|
if tc.preApplyHook {
|
||||||
|
chs, chErr := provider.listCustomHostnamesWithPagination(ctx, zoneID)
|
||||||
|
if chErr != nil {
|
||||||
|
t.Errorf("should not fail - %s, %s", tc.Name, chErr)
|
||||||
|
}
|
||||||
|
chID, _ := provider.getCustomHostnameOrigin(chs, "newerror-getCustomHostnameOrigin.foo.fancybar.com")
|
||||||
|
if chID != "" {
|
||||||
|
t.Logf("corrupting custom hostname %v", chID)
|
||||||
|
oldCh := client.customHostnames[zoneID][chID]
|
||||||
|
ch := cloudflare.CustomHostname{
|
||||||
|
Hostname: "corrupted-newerror-getCustomHostnameOrigin.foo.fancybar.com",
|
||||||
|
CustomOriginServer: oldCh.CustomOriginServer,
|
||||||
|
SSL: oldCh.SSL,
|
||||||
|
}
|
||||||
|
client.customHostnames[zoneID][chID] = ch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = provider.ApplyChanges(context.Background(), planned.Changes)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("should not fail - %s, %s", tc.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.Contains(t, b.String(), "level=info msg=\"Custom hostname newerror-getCustomHostnameOrigin.foo.fancybar.com not found\" action=DELETE record=create.foo.bar.com")
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user