mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2025-08-06 01:26:59 +02:00
Merge pull request #5463 from mloiseleur/chore/unmaintained-providers
chore!: remove unmaintained providers
This commit is contained in:
commit
ef7e1af8c7
2
OWNERS
2
OWNERS
@ -51,6 +51,6 @@ filters:
|
||||
"provider/cloudflare":
|
||||
labels:
|
||||
- provider/cloudflare
|
||||
"provider/(akamai|alibabacloud|civo|designate|digitalocean|dnsimple|exoscale|gandi|godaddy|ibmcloud|linode|ns1|oci|ovh|pihole|plural|scaleway|tencentcloud|transip|ultradns)":
|
||||
"provider/(akamai|alibabacloud|civo|designate|digitalocean|dnsimple|exoscale|gandi|godaddy|linode|ns1|oci|ovh|pihole|plural|scaleway|transip)":
|
||||
labels:
|
||||
- provider
|
||||
|
@ -63,8 +63,6 @@ ExternalDNS allows you to keep selected zones (via `--domain-filter`) synchroniz
|
||||
- [GoDaddy](https://www.godaddy.com)
|
||||
- [Gandi](https://www.gandi.net)
|
||||
- [IBM Cloud DNS](https://www.ibm.com/cloud/dns)
|
||||
- [TencentCloud PrivateDNS](https://cloud.tencent.com/product/privatedns)
|
||||
- [TencentCloud DNSPod](https://cloud.tencent.com/product/cns)
|
||||
- [Plural](https://www.plural.sh/)
|
||||
- [Pi-hole](https://pi-hole.net/)
|
||||
|
||||
@ -149,11 +147,8 @@ The following table clarifies the current status of the providers according to t
|
||||
| TransIP | Alpha | |
|
||||
| OVHcloud | Beta | @rbeuque74 |
|
||||
| Scaleway DNS | Alpha | @Sh4d1 |
|
||||
| UltraDNS | Alpha | |
|
||||
| GoDaddy | Alpha | |
|
||||
| Gandi | Alpha | @packi |
|
||||
| IBMCloud | Alpha | @hughhuangzh |
|
||||
| TencentCloud | Alpha | @Hyzhou |
|
||||
| Plural | Alpha | @michaeljguarino |
|
||||
| Pi-hole | Alpha | @tinyzimmer |
|
||||
|
||||
@ -211,12 +206,9 @@ The following tutorials are provided:
|
||||
- [TransIP](docs/tutorials/transip.md)
|
||||
- [OVHcloud](docs/tutorials/ovh.md)
|
||||
- [Scaleway](docs/tutorials/scaleway.md)
|
||||
- [UltraDNS](docs/tutorials/ultradns.md)
|
||||
- [GoDaddy](docs/tutorials/godaddy.md)
|
||||
- [Gandi](docs/tutorials/gandi.md)
|
||||
- [IBM Cloud](docs/tutorials/ibmcloud.md)
|
||||
- [Nodes as source](docs/sources/nodes.md)
|
||||
- [TencentCloud](docs/tutorials/tencentcloud.md)
|
||||
- [Plural](docs/tutorials/plural.md)
|
||||
- [Pi-hole](docs/tutorials/pihole.md)
|
||||
|
||||
|
@ -53,7 +53,6 @@ import (
|
||||
"sigs.k8s.io/external-dns/provider/gandi"
|
||||
"sigs.k8s.io/external-dns/provider/godaddy"
|
||||
"sigs.k8s.io/external-dns/provider/google"
|
||||
"sigs.k8s.io/external-dns/provider/ibmcloud"
|
||||
"sigs.k8s.io/external-dns/provider/inmemory"
|
||||
"sigs.k8s.io/external-dns/provider/linode"
|
||||
"sigs.k8s.io/external-dns/provider/ns1"
|
||||
@ -64,9 +63,7 @@ import (
|
||||
"sigs.k8s.io/external-dns/provider/plural"
|
||||
"sigs.k8s.io/external-dns/provider/rfc2136"
|
||||
"sigs.k8s.io/external-dns/provider/scaleway"
|
||||
"sigs.k8s.io/external-dns/provider/tencentcloud"
|
||||
"sigs.k8s.io/external-dns/provider/transip"
|
||||
"sigs.k8s.io/external-dns/provider/ultradns"
|
||||
"sigs.k8s.io/external-dns/provider/webhook"
|
||||
webhookapi "sigs.k8s.io/external-dns/provider/webhook/api"
|
||||
"sigs.k8s.io/external-dns/registry"
|
||||
@ -189,8 +186,6 @@ func Execute() {
|
||||
p, err = azure.NewAzureProvider(cfg.AzureConfigFile, domainFilter, zoneNameFilter, zoneIDFilter, cfg.AzureSubscriptionID, cfg.AzureResourceGroup, cfg.AzureUserAssignedIdentityClientID, cfg.AzureActiveDirectoryAuthorityHost, cfg.AzureZonesCacheDuration, cfg.AzureMaxRetriesCount, cfg.DryRun)
|
||||
case "azure-private-dns":
|
||||
p, err = azure.NewAzurePrivateDNSProvider(cfg.AzureConfigFile, domainFilter, zoneNameFilter, zoneIDFilter, cfg.AzureSubscriptionID, cfg.AzureResourceGroup, cfg.AzureUserAssignedIdentityClientID, cfg.AzureActiveDirectoryAuthorityHost, cfg.AzureZonesCacheDuration, cfg.AzureMaxRetriesCount, cfg.DryRun)
|
||||
case "ultradns":
|
||||
p, err = ultradns.NewUltraDNSProvider(domainFilter, cfg.DryRun)
|
||||
case "civo":
|
||||
p, err = civo.NewCivoProvider(domainFilter, cfg.DryRun)
|
||||
case "cloudflare":
|
||||
@ -307,12 +302,8 @@ func Execute() {
|
||||
APIVersion: cfg.PiholeApiVersion,
|
||||
},
|
||||
)
|
||||
case "ibmcloud":
|
||||
p, err = ibmcloud.NewIBMCloudProvider(cfg.IBMCloudConfigFile, domainFilter, zoneIDFilter, endpointsSource, cfg.IBMCloudProxied, cfg.DryRun)
|
||||
case "plural":
|
||||
p, err = plural.NewPluralProvider(cfg.PluralCluster, cfg.PluralProvider)
|
||||
case "tencentcloud":
|
||||
p, err = tencentcloud.NewTencentCloudProvider(domainFilter, zoneIDFilter, cfg.TencentCloudConfigFile, cfg.TencentCloudZoneType, cfg.DryRun)
|
||||
case "webhook":
|
||||
p, err = webhook.NewWebhookProvider(cfg.WebhookProviderURL)
|
||||
default:
|
||||
|
@ -43,7 +43,6 @@ TTL must be a positive value.
|
||||
- [x] Linode
|
||||
- [x] TransIP
|
||||
- [x] RFC2136
|
||||
- [x] UltraDNS
|
||||
|
||||
PRs welcome!
|
||||
|
||||
@ -90,7 +89,3 @@ The Linode Provider default TTL is used when the TTL is 0. The default is 24 hou
|
||||
### TransIP Provider
|
||||
|
||||
The TransIP Provider minimal TTL is used when the TTL is 0. The minimal TTL is 60s.
|
||||
|
||||
### UltraDNS
|
||||
|
||||
The UltraDNS provider minimal TTL is used when the TTL is not provided. The default TTL is account level default TTL, if defined, otherwise 24 hours.
|
||||
|
@ -107,7 +107,6 @@ Some providers define their own annotations. Cloud-specific annotations have key
|
||||
|------------|------------------------------------------------|
|
||||
| AWS | `external-dns.alpha.kubernetes.io/aws-` |
|
||||
| CloudFlare | `external-dns.alpha.kubernetes.io/cloudflare-` |
|
||||
| IBM Cloud | `external-dns.alpha.kubernetes.io/ibmcloud-` |
|
||||
| Scaleway | `external-dns.alpha.kubernetes.io/scw-` |
|
||||
|
||||
Additional annotations that are currently implemented only by AWS are:
|
||||
|
@ -51,7 +51,7 @@
|
||||
| `--target-net-filter=TARGET-NET-FILTER` | Limit possible targets by a net filter; specify multiple times for multiple possible nets (optional) |
|
||||
| `--[no-]traefik-disable-legacy` | Disable listeners on Resources under the traefik.containo.us API Group |
|
||||
| `--[no-]traefik-disable-new` | Disable listeners on Resources under the traefik.io API Group |
|
||||
| `--provider=provider` | The DNS provider where the DNS records will be created (required, options: akamai, alibabacloud, aws, aws-sd, azure, azure-dns, azure-private-dns, civo, cloudflare, coredns, digitalocean, dnsimple, exoscale, gandi, godaddy, google, ibmcloud, inmemory, linode, ns1, oci, ovh, pdns, pihole, plural, rfc2136, scaleway, skydns, tencentcloud, transip, ultradns, webhook) |
|
||||
| `--provider=provider` | The DNS provider where the DNS records will be created (required, options: akamai, alibabacloud, aws, aws-sd, azure, azure-dns, azure-private-dns, civo, cloudflare, coredns, digitalocean, dnsimple, exoscale, gandi, godaddy, google, inmemory, linode, ns1, oci, ovh, pdns, pihole, plural, rfc2136, scaleway, skydns, transip, webhook) |
|
||||
| `--provider-cache-time=0s` | The time to cache the DNS provider record list requests. |
|
||||
| `--domain-filter=` | Limit possible target zones by a domain suffix; specify multiple times for multiple domains (optional) |
|
||||
| `--exclude-domains=` | Exclude subdomains (optional) |
|
||||
@ -87,8 +87,6 @@
|
||||
| `--azure-user-assigned-identity-client-id=""` | When using the Azure provider, override the client id of user assigned identity in config file (optional) |
|
||||
| `--azure-zones-cache-duration=0s` | When using the Azure provider, set the zones list cache TTL (0s to disable). |
|
||||
| `--azure-maxretries-count=3` | When using the Azure provider, set the number of retries for API calls (When less than 0, it disables retries). (optional) |
|
||||
| `--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) |
|
||||
| `--[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) |
|
||||
@ -120,8 +118,6 @@
|
||||
| `--[no-]ns1-ignoressl` | When using the NS1 provider, specify whether to verify the SSL certificate (default: false) |
|
||||
| `--ns1-min-ttl=NS1-MIN-TTL` | Minimal TTL (in seconds) for records. This value will be used if the provided TTL for a service/ingress is lower than this. |
|
||||
| `--digitalocean-api-page-size=50` | Configure the page size used when querying the DigitalOcean API. |
|
||||
| `--ibmcloud-config-file="/etc/kubernetes/ibmcloud.json"` | When using the IBM Cloud provider, specify the IBM Cloud configuration file (required when --provider=ibmcloud |
|
||||
| `--[no-]ibmcloud-proxied` | When using the IBM provider, specify if the proxy mode must be enabled (default: disabled) |
|
||||
| `--godaddy-api-key=""` | When using the GoDaddy provider, specify the API Key (required when --provider=godaddy) |
|
||||
| `--godaddy-api-secret=""` | When using the GoDaddy provider, specify the API secret (required when --provider=godaddy) |
|
||||
| `--godaddy-api-ttl=GODADDY-API-TTL` | TTL (in seconds) for records. This value will be used if the provided TTL for a service/ingress is not provided. |
|
||||
|
@ -18,7 +18,6 @@ Provider supported configurations
|
||||
| Gandi | n/a | no | 600 |
|
||||
| GoDaddy | n/a | yes | 600 |
|
||||
| Google GCP | n/a | yes | 300 |
|
||||
| IBMCloud | n/a | yes | 1 |
|
||||
| InMemory | n/a | n/a | n/a |
|
||||
| Linode | n/a | n/a | n/a |
|
||||
| NS1 | n/a | yes | 10 |
|
||||
@ -29,7 +28,5 @@ Provider supported configurations
|
||||
| Plural | n/a | n/a | n/a |
|
||||
| RFC2136 | n/a | yes | n/a |
|
||||
| Scaleway | n/a | n/a | 300 |
|
||||
| TencentCloud | n/a | n/a | n/a |
|
||||
| Transip | n/a | yes | 60 |
|
||||
| Ultradns | n/a | yes | n/a |
|
||||
| Webhook | n/a | n/a | n/a |
|
||||
|
@ -1,277 +0,0 @@
|
||||
# IBMCloud
|
||||
|
||||
This tutorial describes how to setup ExternalDNS for usage within a Kubernetes cluster using IBMCloud DNS.
|
||||
|
||||
This tutorial uses [IBMCloud CLI](https://cloud.ibm.com/docs/cli?topic=cli-getting-started) for all
|
||||
IBM Cloud commands and assumes that the Kubernetes cluster was created via IBM Cloud Kubernetes Service and `kubectl` commands
|
||||
are being run on an orchestration node.
|
||||
|
||||
## Creating a IBMCloud DNS zone
|
||||
|
||||
The IBMCloud provider for ExternalDNS will find suitable zones for domains it manages; it will
|
||||
not automatically create zones.
|
||||
For public zone, This tutorial assume that the [IBMCloud Internet Services](https://cloud.ibm.com/catalog/services/internet-services) was provisioned and the [cis cli plugin](https://cloud.ibm.com/docs/cis?topic=cis-cli-plugin-cis-cli) was installed with IBMCloud CLI
|
||||
For private zone, This tutorial assume that the [IBMCloud DNS Services](https://cloud.ibm.com/catalog/services/dns-services) was provisioned and the [dns cli plugin](https://cloud.ibm.com/docs/dns-svcs?topic=dns-svcs-cli-plugin-dns-services-cli-commands) was installed with IBMCloud CLI
|
||||
|
||||
### Public Zone
|
||||
|
||||
For this tutorial, we create public zone named `example.com` on IBMCloud Internet Services instance `external-dns-public`
|
||||
|
||||
```sh
|
||||
ibmcloud cis domain-add example.com -i external-dns-public
|
||||
```
|
||||
|
||||
Follow [step](https://cloud.ibm.com/docs/cis?topic=cis-getting-started#configure-your-name-servers-with-the-registrar-or-existing-dns-provider) to active your zone
|
||||
|
||||
### Private Zone
|
||||
|
||||
For this tutorial, we create private zone named `example.com` on IBMCloud DNS Services instance `external-dns-private`
|
||||
|
||||
```sh
|
||||
ibmcloud dns zone-create example.com -i external-dns-private
|
||||
```
|
||||
|
||||
## Creating configuration file
|
||||
|
||||
The preferred way to inject the configuration file is by using a Kubernetes secret. The secret should contain an object named azure.json with content similar to this:
|
||||
|
||||
```json
|
||||
{
|
||||
"apiKey": "1234567890abcdefghijklmnopqrstuvwxyz",
|
||||
"instanceCrn": "crn:v1:bluemix:public:internet-svcs:global:a/bcf1865e99742d38d2d5fc3fb80a5496:b950da8a-5be6-4691-810e-36388c77b0a3::"
|
||||
}
|
||||
```
|
||||
|
||||
You can create or find the `apiKey` in your ibmcloud IAM --> [API Keys page](https://cloud.ibm.com/iam/apikeys)
|
||||
|
||||
You can find the `instanceCrn` in your service instance details
|
||||
|
||||
Now you can create a file named 'ibmcloud.json' with values gathered above and with the structure of the example above. Use this file to create a Kubernetes secret:
|
||||
|
||||
```sh
|
||||
kubectl create secret generic ibmcloud-config-file --from-file=/local/path/to/ibmcloud.json
|
||||
```
|
||||
|
||||
## Deploy ExternalDNS
|
||||
|
||||
Connect your `kubectl` client to the cluster you want to test ExternalDNS with.
|
||||
Then apply one of the following manifests file to deploy ExternalDNS.
|
||||
|
||||
### Manifest (for clusters without RBAC enabled)
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: external-dns
|
||||
spec:
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
app: external-dns
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: external-dns
|
||||
spec:
|
||||
containers:
|
||||
- name: external-dns
|
||||
image: registry.k8s.io/external-dns/external-dns:v0.17.0
|
||||
args:
|
||||
- --source=service # ingress is also possible
|
||||
- --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above.
|
||||
- --provider=ibmcloud
|
||||
- --ibmcloud-proxied # (optional) enable the proxy feature of IBMCloud
|
||||
volumeMounts:
|
||||
- name: ibmcloud-config-file
|
||||
mountPath: /etc/kubernetes
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: ibmcloud-config-file
|
||||
secret:
|
||||
secretName: ibmcloud-config-file
|
||||
items:
|
||||
- key: externaldns-config.json
|
||||
path: ibmcloud.json
|
||||
```
|
||||
|
||||
### Manifest (for clusters with RBAC enabled)
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: external-dns
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: external-dns
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["services","endpoints","pods"]
|
||||
verbs: ["get","watch","list"]
|
||||
- apiGroups: ["extensions","networking.k8s.io"]
|
||||
resources: ["ingresses"]
|
||||
verbs: ["get","watch","list"]
|
||||
- apiGroups: [""]
|
||||
resources: ["nodes"]
|
||||
verbs: ["list", "watch"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: external-dns-viewer
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: external-dns
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: external-dns
|
||||
namespace: default
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: external-dns
|
||||
spec:
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
app: external-dns
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: external-dns
|
||||
spec:
|
||||
serviceAccountName: external-dns
|
||||
containers:
|
||||
- name: external-dns
|
||||
image: registry.k8s.io/external-dns/external-dns:v0.17.0
|
||||
args:
|
||||
- --source=service # ingress is also possible
|
||||
- --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above.
|
||||
- --provider=ibmcloud
|
||||
- --ibmcloud-proxied # (optional) enable the proxy feature of IBMCloud public zone
|
||||
volumeMounts:
|
||||
- name: ibmcloud-config-file
|
||||
mountPath: /etc/kubernetes
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: ibmcloud-config-file
|
||||
secret:
|
||||
secretName: ibmcloud-config-file
|
||||
items:
|
||||
- key: externaldns-config.json
|
||||
path: ibmcloud.json
|
||||
```
|
||||
|
||||
## Deploying an Nginx Service
|
||||
|
||||
Create a service file called `nginx.yaml` with the following contents:
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx
|
||||
name: nginx
|
||||
ports:
|
||||
- containerPort: 80
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nginx
|
||||
annotations:
|
||||
external-dns.alpha.kubernetes.io/hostname: www.example.com
|
||||
external-dns.alpha.kubernetes.io/ttl: "120" #optional
|
||||
spec:
|
||||
selector:
|
||||
app: nginx
|
||||
type: LoadBalancer
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
targetPort: 80
|
||||
```
|
||||
|
||||
Note the annotation on the service; use the hostname as the IBMCloud DNS zone created above. The annotation may also be a subdomain
|
||||
of the DNS zone (e.g. 'www.example.com').
|
||||
|
||||
By setting the TTL annotation on the service, you have to pass a valid TTL, which must be 120 or above.
|
||||
This annotation is optional, if you won't set it, it will be 1 (automatic) which is 300.
|
||||
|
||||
ExternalDNS uses this annotation to determine what services should be registered with DNS. Removing the annotation
|
||||
will cause ExternalDNS to remove the corresponding DNS records.
|
||||
|
||||
Create the deployment and service:
|
||||
|
||||
```sh
|
||||
kubectl create -f nginx.yaml
|
||||
```
|
||||
|
||||
Depending where you run your service it can take a little while for your cloud provider to create an external IP for the service.
|
||||
|
||||
Once the service has an external IP assigned, ExternalDNS will notice the new service IP address and synchronize
|
||||
the IBMCloud DNS records.
|
||||
|
||||
## Verifying IBMCloud DNS records
|
||||
|
||||
Run the following command to view the A records:
|
||||
|
||||
### Public Zone
|
||||
|
||||
```sh
|
||||
# Get the domain ID with below command on IBMCloud Internet Services instance `external-dns-public`
|
||||
$ ibmcloud cis domains -i external-dns-public
|
||||
# Get the records with domain ID
|
||||
$ ibmcloud cis dns-records DOMAIN_ID -i external-dns-public
|
||||
```
|
||||
|
||||
### Private Zone
|
||||
|
||||
```sh
|
||||
# Get the domain ID with below command on IBMCloud DNS Services instance `external-dns-private`
|
||||
$ ibmcloud dns zones -i external-dns-private
|
||||
# Get the records with domain ID
|
||||
$ ibmcloud dns resource-records ZONE_ID -i external-dns-public
|
||||
```
|
||||
|
||||
This should show the external IP address of the service as the A record for your domain.
|
||||
|
||||
## Cleanup
|
||||
|
||||
Now that we have verified that ExternalDNS will automatically manage IBMCloud DNS records, we can delete the tutorial's example:
|
||||
|
||||
```sh
|
||||
kubectl delete -f nginx.yaml
|
||||
kubectl delete -f externaldns.yaml
|
||||
```
|
||||
|
||||
## Setting proxied records on public zone
|
||||
|
||||
Using the `external-dns.alpha.kubernetes.io/ibmcloud-proxied: "true"` annotation on your ingress or service, you can specify if the proxy feature of IBMCloud public DNS should be enabled for that record. This setting will override the global `--ibmcloud-proxied` setting.
|
||||
|
||||
## Active priviate zone with VPC allocated
|
||||
|
||||
By default, IBMCloud DNS Services don't active your private zone with new zone added.
|
||||
With External DNS, you can use `external-dns.alpha.kubernetes.io/ibmcloud-vpc: "crn:v1:bluemix:public:is:us-south:a/bcf1865e99742d38d2d5fc3fb80a5496::vpc:r006-74353823-a60d-42e4-97c5-5e2551278435"` annotation on your ingress or service.
|
||||
It will active your private zone with in specific VPC for that record created in.
|
||||
This setting won't work if the private zone was active already.
|
||||
|
||||
Note: the annotaion value is the VPC CRN, every IBM Cloud service have a valid CRN.
|
@ -1,216 +0,0 @@
|
||||
# Tencent Cloud
|
||||
|
||||
## External Dns Version
|
||||
|
||||
* Make sure to use **>=0.13.1** version of ExternalDNS for this tutorial
|
||||
|
||||
## Set up PrivateDns or DNSPod
|
||||
|
||||
Tencent Cloud DNSPod Service is the domain name resolution and management service for public access.
|
||||
Tencent Cloud PrivateDNS Service is the domain name resolution and management service for VPC internal access.
|
||||
|
||||
* If you want to use internal dns service in Tencent Cloud.
|
||||
|
||||
1. Set up the args `--tencent-cloud-zone-type=private`
|
||||
2. Create a DNS domain in PrivateDNS console. DNS domain which will contain the managed DNS records.
|
||||
|
||||
* If you want to use public dns service in Tencent Cloud.
|
||||
|
||||
1. Set up the args `--tencent-cloud-zone-type=public`
|
||||
2. Create a Domain in DnsPod console. DNS domain which will contain the managed DNS records.
|
||||
|
||||
## Set up CAM for API Key
|
||||
|
||||
In Tencent CAM Console. you may get the secretId and secretKey pair. make sure the key pair has those Policy.
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "2.0",
|
||||
"statement": [
|
||||
{
|
||||
"effect": "allow",
|
||||
"action": [
|
||||
"dnspod:ModifyRecord",
|
||||
"dnspod:DeleteRecord",
|
||||
"dnspod:CreateRecord",
|
||||
"dnspod:DescribeRecordList",
|
||||
"dnspod:DescribeDomainList"
|
||||
],
|
||||
"resource": [
|
||||
"*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "allow",
|
||||
"action": [
|
||||
"privatedns:DescribePrivateZoneList",
|
||||
"privatedns:DescribePrivateZoneRecordList",
|
||||
"privatedns:CreatePrivateZoneRecord",
|
||||
"privatedns:DeletePrivateZoneRecord",
|
||||
"privatedns:ModifyPrivateZoneRecord"
|
||||
],
|
||||
"resource": [
|
||||
"*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Deploy ExternalDNS
|
||||
|
||||
### Manifest (for clusters with RBAC enabled)
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: external-dns
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: external-dns
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["services","endpoints","pods"]
|
||||
verbs: ["get","watch","list"]
|
||||
- apiGroups: ["extensions","networking.k8s.io"]
|
||||
resources: ["ingresses"]
|
||||
verbs: ["get","watch","list"]
|
||||
- apiGroups: [""]
|
||||
resources: ["nodes"]
|
||||
verbs: ["list"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: external-dns-viewer
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: external-dns
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: external-dns
|
||||
namespace: default
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: external-dns
|
||||
data:
|
||||
tencent-cloud.json: |
|
||||
{
|
||||
"regionId": "ap-shanghai",
|
||||
"secretId": "******",
|
||||
"secretKey": "******",
|
||||
"vpcId": "vpc-******",
|
||||
"internetEndpoint": false # Default: false. Access the Tencent API through the intranet. If you need to deploy on the public network, you need to change to true
|
||||
}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: external-dns
|
||||
spec:
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
app: external-dns
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: external-dns
|
||||
spec:
|
||||
containers:
|
||||
- args:
|
||||
- --source=service
|
||||
- --source=ingress
|
||||
- --domain-filter=external-dns-test.com # will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones
|
||||
- --provider=tencentcloud
|
||||
- --policy=sync # set `upsert-only` would prevent ExternalDNS from deleting any records
|
||||
- --tencent-cloud-zone-type=private # only look at private hosted zones. set `public` to use the public dns service.
|
||||
- --tencent-cloud-config-file=/etc/kubernetes/tencent-cloud.json
|
||||
image: registry.k8s.io/external-dns/external-dns:v0.17.0
|
||||
imagePullPolicy: Always
|
||||
name: external-dns
|
||||
resources: {}
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
volumeMounts:
|
||||
- mountPath: /etc/kubernetes
|
||||
name: config-volume
|
||||
readOnly: true
|
||||
dnsPolicy: ClusterFirst
|
||||
hostAliases:
|
||||
- hostnames:
|
||||
- privatedns.internal.tencentcloudapi.com
|
||||
- dnspod.internal.tencentcloudapi.com
|
||||
ip: 169.254.0.95
|
||||
restartPolicy: Always
|
||||
schedulerName: default-scheduler
|
||||
securityContext: {}
|
||||
serviceAccount: external-dns
|
||||
serviceAccountName: external-dns
|
||||
terminationGracePeriodSeconds: 30
|
||||
volumes:
|
||||
- configMap:
|
||||
defaultMode: 420
|
||||
items:
|
||||
- key: tencent-cloud.json
|
||||
path: tencent-cloud.json
|
||||
name: external-dns
|
||||
name: config-volume
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
### Service
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nginx
|
||||
annotations:
|
||||
external-dns.alpha.kubernetes.io/hostname: nginx.external-dns-test.com
|
||||
external-dns.alpha.kubernetes.io/internal-hostname: nginx-internal.external-dns-test.com
|
||||
external-dns.alpha.kubernetes.io/ttl: "600"
|
||||
spec:
|
||||
type: LoadBalancer
|
||||
ports:
|
||||
- port: 80
|
||||
name: http
|
||||
targetPort: 80
|
||||
selector:
|
||||
app: nginx
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx
|
||||
name: nginx
|
||||
ports:
|
||||
- containerPort: 80
|
||||
name: http
|
||||
```
|
||||
|
||||
`nginx.external-dns-test.com` will record to the Loadbalancer VIP.
|
||||
`nginx-internal.external-dns-test.com` will record to the ClusterIP.
|
||||
all of the DNS Record ttl will be 600.
|
||||
|
||||
> [!WARNING]
|
||||
> This makes ExternalDNS safe for running in environments where there are other records managed via other means.
|
@ -1,665 +0,0 @@
|
||||
# UltraDNS
|
||||
|
||||
This tutorial describes how to setup ExternalDNS for usage within a Kubernetes cluster using UltraDNS.
|
||||
|
||||
For this tutorial, please make sure that you are using a version **> 0.7.2** of ExternalDNS.
|
||||
|
||||
## Managing DNS with UltraDNS
|
||||
|
||||
If you would like to read-up on the UltraDNS service, you can find additional details here: [Introduction to UltraDNS](https://docs.ultradns.com/)
|
||||
|
||||
Before proceeding, please create a new DNS Zone that you will create your records in for this tutorial process. For the examples in this tutorial, we will be using `example.com` as our Zone.
|
||||
|
||||
## Setting Up UltraDNS Credentials
|
||||
|
||||
The following environment variables will be needed to run ExternalDNS with UltraDNS.
|
||||
|
||||
`ULTRADNS_USERNAME`,`ULTRADNS_PASSWORD`, &`ULTRADNS_BASEURL`
|
||||
`ULTRADNS_ACCOUNTNAME`(optional variable).
|
||||
|
||||
## Deploying ExternalDNS
|
||||
|
||||
Connect your `kubectl` client to the cluster you want to test ExternalDNS with.
|
||||
Then, apply one of the following manifests file to deploy ExternalDNS.
|
||||
|
||||
- Note: We are assuming the zone is already present within UltraDNS.
|
||||
- Note: While creating CNAMES as target endpoints, the `--txt-prefix` option is mandatory.
|
||||
|
||||
### Manifest (for clusters without RBAC enabled)
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: external-dns
|
||||
spec:
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
app: external-dns
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: external-dns
|
||||
spec:
|
||||
containers:
|
||||
- name: external-dns
|
||||
image: registry.k8s.io/external-dns/external-dns:v0.17.0
|
||||
args:
|
||||
- --source=service
|
||||
- --source=ingress # ingress is also possible
|
||||
- --domain-filter=example.com # (Recommended) We recommend to use this filter as it minimize the time to propagate changes, as there are less number of zones to look into..
|
||||
- --provider=ultradns
|
||||
- --txt-prefix=txt-
|
||||
env:
|
||||
- name: ULTRADNS_USERNAME
|
||||
value: ""
|
||||
- name: ULTRADNS_PASSWORD # The password is required to be BASE64 encrypted.
|
||||
value: ""
|
||||
- name: ULTRADNS_BASEURL
|
||||
value: "https://api.ultradns.com/"
|
||||
- name: ULTRADNS_ACCOUNTNAME
|
||||
value: ""
|
||||
```
|
||||
|
||||
### Manifest (for clusters with RBAC enabled)
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: external-dns
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: external-dns
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["services","endpoints","pods"]
|
||||
verbs: ["get","watch","list"]
|
||||
- apiGroups: ["extensions"]
|
||||
resources: ["ingresses"]
|
||||
verbs: ["get","watch","list"]
|
||||
- apiGroups: [""]
|
||||
resources: ["nodes"]
|
||||
verbs: ["list","watch"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: external-dns-viewer
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: external-dns
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: external-dns
|
||||
namespace: default
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: external-dns
|
||||
spec:
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
app: external-dns
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: external-dns
|
||||
spec:
|
||||
serviceAccountName: external-dns
|
||||
containers:
|
||||
- name: external-dns
|
||||
image: registry.k8s.io/external-dns/external-dns:v0.17.0
|
||||
args:
|
||||
- --source=service
|
||||
- --source=ingress
|
||||
- --domain-filter=example.com #(Recommended) We recommend to use this filter as it minimize the time to propagate changes, as there are less number of zones to look into..
|
||||
- --provider=ultradns
|
||||
- --txt-prefix=txt-
|
||||
env:
|
||||
- name: ULTRADNS_USERNAME
|
||||
value: ""
|
||||
- name: ULTRADNS_PASSWORD # The password is required to be BASE64 encrypted.
|
||||
value: ""
|
||||
- name: ULTRADNS_BASEURL
|
||||
value: "https://api.ultradns.com/"
|
||||
- name: ULTRADNS_ACCOUNTNAME
|
||||
value: ""
|
||||
```
|
||||
|
||||
## Deploying an Nginx Service
|
||||
|
||||
Create a service file called 'nginx.yaml' with the following contents:
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx
|
||||
name: nginx
|
||||
ports:
|
||||
- containerPort: 80
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nginx
|
||||
annotations:
|
||||
external-dns.alpha.kubernetes.io/hostname: my-app.example.com.
|
||||
spec:
|
||||
selector:
|
||||
app: nginx
|
||||
type: LoadBalancer
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
targetPort: 80
|
||||
```
|
||||
|
||||
Please note the annotation on the service. Use the same hostname as the UltraDNS zone created above.
|
||||
|
||||
ExternalDNS uses this annotation to determine what services should be registered with DNS. Removing the annotation will cause ExternalDNS to remove the corresponding DNS records.
|
||||
|
||||
## Creating the Deployment and Service
|
||||
|
||||
```console
|
||||
kubectl create -f nginx.yaml
|
||||
kubectl create -f external-dns.yaml
|
||||
```
|
||||
|
||||
Depending on where you run your service from, it can take a few minutes for your cloud provider to create an external IP for the service.
|
||||
|
||||
Once the service has an external IP assigned, ExternalDNS will notice the new service IP address and will synchronize the UltraDNS records.
|
||||
|
||||
## Verifying UltraDNS Records
|
||||
|
||||
Please verify on the [UltraDNS UI](https://portal.ultradns.com/login) that the records are created under the zone "example.com".
|
||||
|
||||
For more information on UltraDNS UI, refer to (https://docs.ultradns.com/Content/MSP_User_Guide/Content/User%20Guides/MSP_User_Guide/Navigation/Moving%20Around%20the%20UI.htm#_Toc2780722).
|
||||
|
||||
Select the zone that was created above (or select the appropriate zone if a different zone was used.)
|
||||
|
||||
The external IP address will be displayed as a CNAME record for your zone.
|
||||
|
||||
## Cleaning Up the Deployment and Service
|
||||
|
||||
Now that we have verified that ExternalDNS will automatically manage your UltraDNS records, you can delete example zones that you created in this tutorial:
|
||||
|
||||
```sh
|
||||
kubectl delete service -f nginx.yaml
|
||||
kubectl delete service -f externaldns.yaml
|
||||
```
|
||||
|
||||
## Examples to Manage your Records
|
||||
|
||||
### Creating Multiple A Records Target
|
||||
|
||||
- First, you want to create a service file called 'apple-banana-echo.yaml'
|
||||
|
||||
```yaml
|
||||
---
|
||||
kind: Pod
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: example-app
|
||||
labels:
|
||||
app: apple
|
||||
spec:
|
||||
containers:
|
||||
- name: example-app
|
||||
image: hashicorp/http-echo
|
||||
args:
|
||||
- "-text=apple"
|
||||
---
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: example-service
|
||||
spec:
|
||||
selector:
|
||||
app: apple
|
||||
ports:
|
||||
- port: 5678 # Default port for image
|
||||
```
|
||||
|
||||
- Then, create service file called 'expose-apple-banana-app.yaml' to expose the services. For more information to deploy ingress controller, refer to (https://kubernetes.github.io/ingress-nginx/deploy/)
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: example-ingress
|
||||
annotations:
|
||||
ingress.kubernetes.io/rewrite-target: /
|
||||
ingress.kubernetes.io/scheme: internet-facing
|
||||
external-dns.alpha.kubernetes.io/hostname: apple.example.com.
|
||||
external-dns.alpha.kubernetes.io/target: 10.10.10.1,10.10.10.23
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /apple
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: example-service
|
||||
port:
|
||||
number: 5678
|
||||
```
|
||||
|
||||
- Then, create the deployment and service:
|
||||
|
||||
```console
|
||||
kubectl create -f apple-banana-echo.yaml
|
||||
kubectl create -f expose-apple-banana-app.yaml
|
||||
kubectl create -f external-dns.yaml
|
||||
```
|
||||
|
||||
- Depending on where you run your service from, it can take a few minutes for your cloud provider to create an external IP for the service.
|
||||
- Please verify on the [UltraDNS UI](https://portal.ultradns.com/login) that the records have been created under the zone "example.com".
|
||||
- Finally, you will need to clean up the deployment and service. Please verify on the UI afterwards that the records have been deleted from the zone "example.com":
|
||||
|
||||
```console
|
||||
kubectl delete -f apple-banana-echo.yaml
|
||||
kubectl delete -f expose-apple-banana-app.yaml
|
||||
kubectl delete -f external-dns.yaml
|
||||
```
|
||||
|
||||
### Creating CNAME Record
|
||||
|
||||
- Please note, that prior to deploying the external-dns service, you will need to add the option –txt-prefix=txt- into external-dns.yaml. If this not provided, your records will not be created.
|
||||
- First, create a service file called 'apple-banana-echo.yaml'
|
||||
- _Config File Example – kubernetes cluster is on-premise not on cloud_
|
||||
|
||||
```yaml
|
||||
---
|
||||
kind: Pod
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: example-app
|
||||
labels:
|
||||
app: apple
|
||||
spec:
|
||||
containers:
|
||||
- name: example-app
|
||||
image: hashicorp/http-echo
|
||||
args:
|
||||
- "-text=apple"
|
||||
---
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: example-service
|
||||
spec:
|
||||
selector:
|
||||
app: apple
|
||||
ports:
|
||||
- port: 5678 # Default port for image
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: example-ingress
|
||||
annotations:
|
||||
ingress.kubernetes.io/rewrite-target: /
|
||||
ingress.kubernetes.io/scheme: internet-facing
|
||||
external-dns.alpha.kubernetes.io/hostname: apple.example.com.
|
||||
external-dns.alpha.kubernetes.io/target: apple.cname.com.
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /apple
|
||||
backend:
|
||||
service:
|
||||
name: example-service
|
||||
port:
|
||||
number: 5678
|
||||
```
|
||||
|
||||
- _Config File Example – Kubernetes cluster service from different cloud vendors_
|
||||
|
||||
```yaml
|
||||
---
|
||||
kind: Pod
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: example-app
|
||||
labels:
|
||||
app: apple
|
||||
spec:
|
||||
containers:
|
||||
- name: example-app
|
||||
image: hashicorp/http-echo
|
||||
args:
|
||||
- "-text=apple"
|
||||
---
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: example-service
|
||||
annotations:
|
||||
external-dns.alpha.kubernetes.io/hostname: my-app.example.com.
|
||||
spec:
|
||||
selector:
|
||||
app: apple
|
||||
type: LoadBalancer
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 5678
|
||||
targetPort: 5678
|
||||
```
|
||||
|
||||
- Then, create the deployment and service:
|
||||
|
||||
```console
|
||||
kubectl create -f apple-banana-echo.yaml
|
||||
kubectl create -f external-dns.yaml
|
||||
```
|
||||
|
||||
- Depending on where you run your service from, it can take a few minutes for your cloud provider to create an external IP for the service.
|
||||
- Please verify on the [UltraDNS UI](https://portal.ultradns.com/login), that the records have been created under the zone "example.com".
|
||||
- Finally, you will need to clean up the deployment and service. Please verify on the UI afterwards that the records have been deleted from the zone "example.com":
|
||||
|
||||
```console
|
||||
kubectl delete -f apple-banana-echo.yaml
|
||||
kubectl delete -f external-dns.yaml
|
||||
```
|
||||
|
||||
### Creating Multiple Types Of Records
|
||||
|
||||
- Please note, that prior to deploying the external-dns service, you will need to add the option –txt-prefix=txt- into external-dns.yaml. Since you will also be created a CNAME record, If this not provided, your records will not be created.
|
||||
- First, create a service file called 'apple-banana-echo.yaml'
|
||||
- _Config File Example – kubernetes cluster is on-premise not on cloud_
|
||||
|
||||
```yaml
|
||||
---
|
||||
kind: Pod
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: example-app
|
||||
labels:
|
||||
app: apple
|
||||
spec:
|
||||
containers:
|
||||
- name: example-app
|
||||
image: hashicorp/http-echo
|
||||
args:
|
||||
- "-text=apple"
|
||||
---
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: example-service
|
||||
spec:
|
||||
selector:
|
||||
app: apple
|
||||
ports:
|
||||
- port: 5678 # Default port for image
|
||||
---
|
||||
kind: Pod
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: example-app1
|
||||
labels:
|
||||
app: apple1
|
||||
spec:
|
||||
containers:
|
||||
- name: example-app1
|
||||
image: hashicorp/http-echo
|
||||
args:
|
||||
- "-text=apple"
|
||||
---
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: example-service1
|
||||
spec:
|
||||
selector:
|
||||
app: apple1
|
||||
ports:
|
||||
- port: 5679 # Default port for image
|
||||
---
|
||||
kind: Pod
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: example-app2
|
||||
labels:
|
||||
app: apple2
|
||||
spec:
|
||||
containers:
|
||||
- name: example-app2
|
||||
image: hashicorp/http-echo
|
||||
args:
|
||||
- "-text=apple"
|
||||
---
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: example-service2
|
||||
spec:
|
||||
selector:
|
||||
app: apple2
|
||||
ports:
|
||||
- port: 5680 # Default port for image
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: example-ingress
|
||||
annotations:
|
||||
ingress.kubernetes.io/rewrite-target: /
|
||||
ingress.kubernetes.io/scheme: internet-facing
|
||||
external-dns.alpha.kubernetes.io/hostname: apple.example.com.
|
||||
external-dns.alpha.kubernetes.io/target: apple.cname.com.
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /apple
|
||||
backend:
|
||||
service:
|
||||
name: example-service
|
||||
port:
|
||||
number: 5678
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: example-ingress1
|
||||
annotations:
|
||||
ingress.kubernetes.io/rewrite-target: /
|
||||
ingress.kubernetes.io/scheme: internet-facing
|
||||
external-dns.alpha.kubernetes.io/hostname: apple-banana.example.com.
|
||||
external-dns.alpha.kubernetes.io/target: 10.10.10.3
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /apple
|
||||
backend:
|
||||
service:
|
||||
name: example-service1
|
||||
port:
|
||||
number: 5679
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: example-ingress2
|
||||
annotations:
|
||||
ingress.kubernetes.io/rewrite-target: /
|
||||
ingress.kubernetes.io/scheme: internet-facing
|
||||
external-dns.alpha.kubernetes.io/hostname: banana.example.com.
|
||||
external-dns.alpha.kubernetes.io/target: 10.10.10.3,10.10.10.20
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /apple
|
||||
backend:
|
||||
service:
|
||||
name: example-service2
|
||||
port:
|
||||
number: 5680
|
||||
```
|
||||
|
||||
- _Config File Example – Kubernetes cluster service from different cloud vendors_
|
||||
|
||||
```yaml
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx
|
||||
name: nginx
|
||||
ports:
|
||||
- containerPort: 80
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nginx
|
||||
annotations:
|
||||
external-dns.alpha.kubernetes.io/hostname: my-app.example.com.
|
||||
spec:
|
||||
selector:
|
||||
app: nginx
|
||||
type: LoadBalancer
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
targetPort: 80
|
||||
---
|
||||
kind: Pod
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: example-app
|
||||
labels:
|
||||
app: apple
|
||||
spec:
|
||||
containers:
|
||||
- name: example-app
|
||||
image: hashicorp/http-echo
|
||||
args:
|
||||
- "-text=apple"
|
||||
---
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: example-service
|
||||
spec:
|
||||
selector:
|
||||
app: apple
|
||||
ports:
|
||||
- port: 5678 # Default port for image
|
||||
---
|
||||
kind: Pod
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: example-app1
|
||||
labels:
|
||||
app: apple1
|
||||
spec:
|
||||
containers:
|
||||
- name: example-app1
|
||||
image: hashicorp/http-echo
|
||||
args:
|
||||
- "-text=apple"
|
||||
---
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: example-service1
|
||||
spec:
|
||||
selector:
|
||||
app: apple1
|
||||
ports:
|
||||
- port: 5679 # Default port for image
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: example-ingress
|
||||
annotations:
|
||||
ingress.kubernetes.io/rewrite-target: /
|
||||
ingress.kubernetes.io/scheme: internet-facing
|
||||
external-dns.alpha.kubernetes.io/hostname: apple.example.com.
|
||||
external-dns.alpha.kubernetes.io/target: 10.10.10.3,10.10.10.25
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /apple
|
||||
backend:
|
||||
service:
|
||||
name: example-service
|
||||
port:
|
||||
number: 5678
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: example-ingress1
|
||||
annotations:
|
||||
ingress.kubernetes.io/rewrite-target: /
|
||||
ingress.kubernetes.io/scheme: internet-facing
|
||||
external-dns.alpha.kubernetes.io/hostname: apple-banana.example.com.
|
||||
external-dns.alpha.kubernetes.io/target: 10.10.10.3
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /apple
|
||||
backend:
|
||||
service:
|
||||
name: example-service1
|
||||
port:
|
||||
number: 5679
|
||||
```
|
||||
|
||||
- Then, create the deployment and service:
|
||||
|
||||
```console
|
||||
kubectl create -f apple-banana-echo.yaml
|
||||
kubectl create -f external-dns.yaml
|
||||
```
|
||||
|
||||
- Depending on where you run your service from, it can take a few minutes for your cloud provider to create an external IP for the service.
|
||||
- Please verify on the [UltraDNS UI](https://portal.ultradns.com/login), that the records have been created under the zone "example.com".
|
||||
- Finally, you will need to clean up the deployment and service. Please verify on the UI afterwards that the records have been deleted from the zone "example.com":
|
||||
|
||||
```console
|
||||
kubectl delete -f apple-banana-echo.yaml
|
||||
kubectl delete -f external-dns.yaml```
|
27
go.mod
27
go.mod
@ -9,9 +9,6 @@ require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.3.0
|
||||
github.com/F5Networks/k8s-bigip-ctlr/v2 v2.19.1
|
||||
github.com/IBM-Cloud/ibm-cloud-cli-sdk v1.7.2
|
||||
github.com/IBM/go-sdk-core/v5 v5.19.1
|
||||
github.com/IBM/networking-go-sdk v0.51.5
|
||||
github.com/Yamashou/gqlgenc v0.32.1
|
||||
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2
|
||||
github.com/alecthomas/kingpin/v2 v2.4.0
|
||||
@ -44,7 +41,6 @@ require (
|
||||
github.com/linode/linodego v1.50.0
|
||||
github.com/maxatome/go-testdeep v1.14.0
|
||||
github.com/miekg/dns v1.1.66
|
||||
github.com/onsi/ginkgo v1.16.5
|
||||
github.com/openshift/api v0.0.0-20230607130528-611114dca681
|
||||
github.com/openshift/client-go v0.0.0-20230607134213-3cd0021bbee3
|
||||
github.com/oracle/oci-go-sdk/v65 v65.91.0
|
||||
@ -56,11 +52,7 @@ require (
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1166
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1165
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.1145
|
||||
github.com/transip/gotransip/v6 v6.26.0
|
||||
github.com/ultradns/ultradns-sdk-go v1.3.7
|
||||
go.etcd.io/etcd/client/v3 v3.6.0
|
||||
go.uber.org/ratelimit v0.3.1
|
||||
golang.org/x/net v0.40.0
|
||||
@ -76,6 +68,7 @@ require (
|
||||
k8s.io/apimachinery v0.33.1
|
||||
k8s.io/client-go v0.33.1
|
||||
k8s.io/klog/v2 v2.130.1
|
||||
sigs.k8s.io/controller-runtime v0.20.4
|
||||
sigs.k8s.io/gateway-api v1.3.0
|
||||
)
|
||||
|
||||
@ -89,7 +82,6 @@ require (
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
|
||||
github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
|
||||
@ -109,20 +101,12 @@ require (
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/deepmap/oapi-codegen v1.9.1 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.1 // indirect
|
||||
github.com/fatih/structs v1.1.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/errors v0.22.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/strfmt v0.23.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.26.0 // indirect
|
||||
github.com/go-resty/resty/v2 v2.16.5 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/gofrs/flock v0.8.1 // indirect
|
||||
@ -153,17 +137,14 @@ require (
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mailru/easyjson v0.9.0 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/nxadm/tail v1.4.8 // indirect
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||
github.com/openshift/gssapi v0.0.0-20161010215902-5fb4217df13b // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
|
||||
github.com/peterhellberg/link v1.1.0 // indirect
|
||||
@ -180,14 +161,12 @@ require (
|
||||
github.com/sosodev/duration v1.3.1 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
github.com/terra-farm/udnssdk v1.3.5 // indirect
|
||||
github.com/vektah/gqlparser/v2 v2.5.25 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.6.0 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.0 // indirect
|
||||
go.mongodb.org/mongo-driver v1.17.2 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
|
||||
go.opentelemetry.io/otel v1.35.0 // indirect
|
||||
@ -208,13 +187,11 @@ require (
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
|
||||
k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect
|
||||
moul.io/http2curl v1.0.0 // indirect
|
||||
sigs.k8s.io/controller-runtime v0.20.4 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
|
||||
|
45
go.sum
45
go.sum
@ -51,12 +51,6 @@ github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q
|
||||
github.com/F5Networks/k8s-bigip-ctlr/v2 v2.19.1 h1:NHWjSBeXbL8mlx+0QyCl4OrUvytCZ3nkEIRqX7t97wQ=
|
||||
github.com/F5Networks/k8s-bigip-ctlr/v2 v2.19.1/go.mod h1:JwdtGjHFTmUM1zjzvvCotCCyP55S146IuVPOJZ7D/Jw=
|
||||
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
|
||||
github.com/IBM-Cloud/ibm-cloud-cli-sdk v1.7.2 h1:eW5o8NpblAyqPjwOlZ+XISdhlYynjf7B7dsCmsvfC/s=
|
||||
github.com/IBM-Cloud/ibm-cloud-cli-sdk v1.7.2/go.mod h1:HulyrJLLc9FSZlwKQ9vu5Jq83thNlUfg1afonOdhrRA=
|
||||
github.com/IBM/go-sdk-core/v5 v5.19.1 h1:sleVks1O4XjgF4YEGvyDh6PZbP6iZhlTPeDkQc8nWDs=
|
||||
github.com/IBM/go-sdk-core/v5 v5.19.1/go.mod h1:Q3BYO6iDA2zweQPDGbNTtqft5tDcEpm6RTuqMlPcvbw=
|
||||
github.com/IBM/networking-go-sdk v0.51.5 h1:75lKAx17y++hirXK5GcEM23mTRhHnhsv6gmhz70ex1Q=
|
||||
github.com/IBM/networking-go-sdk v0.51.5/go.mod h1:wyEnRnBnROgGmSn5UrryycIrbBujHKXf0PmI1NSwcjY=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E=
|
||||
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
@ -116,8 +110,6 @@ github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:l
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
|
||||
github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
|
||||
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
@ -306,8 +298,6 @@ github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwo
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/ffledgling/pdns-go v0.0.0-20180219074714-524e7daccd99 h1:jmwW6QWvUO2OPe22YfgFvBaaZlSr8Rlrac5lZvG6IdM=
|
||||
@ -321,8 +311,6 @@ github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/
|
||||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
||||
github.com/getkin/kin-openapi v0.87.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
|
||||
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
@ -360,8 +348,6 @@ github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2
|
||||
github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
|
||||
github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
|
||||
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
|
||||
github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w=
|
||||
github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE=
|
||||
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
|
||||
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
@ -394,8 +380,6 @@ github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pL
|
||||
github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
|
||||
github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
|
||||
github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
|
||||
github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c=
|
||||
github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4=
|
||||
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
|
||||
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
@ -407,20 +391,12 @@ github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+
|
||||
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
|
||||
github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||
github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
||||
github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
|
||||
github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
|
||||
github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM=
|
||||
github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
@ -632,8 +608,6 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
@ -686,8 +660,6 @@ github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtB
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y=
|
||||
github.com/lestrrat-go/blackmagic v1.0.0/go.mod h1:TNgH//0vYSs8VXDCfkZLgIrVTTXQELZffUV0tz3MtdQ=
|
||||
github.com/lestrrat-go/codegen v1.0.2/go.mod h1:JhJw6OQAuPEfVKUCLItpaVLumDGWQznd1VaXrBk9TdM=
|
||||
@ -766,8 +738,6 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
|
||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@ -799,7 +769,6 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
|
||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
@ -1021,16 +990,6 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1145/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1165/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1166 h1:WgdCsNxde/flDGxOy+dXZqm2wrUQA/4kzaaY69XC/2A=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1166/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1165 h1:bHT5sLou90UwrVm7Km2nQ7hyBk0+LK4xi7JOZXoDQ2c=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1165/go.mod h1:6pN5Nh0PuYJ+XHkjiV7SQqXgc1gecB9FHd456W9ZNdE=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.1145 h1:K5N0Uxqm9kM7KU6DFBekCTKbldlXq6UD1ekOyXn4zEc=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns v1.0.1145/go.mod h1:mgwxarWzLxIylWtHmkoMg0dX8aqhO5lwfrHkK4IGLKE=
|
||||
github.com/terra-farm/udnssdk v1.3.5 h1:MNR3adfuuEK/l04+jzo8WW/0fnorY+nW515qb3vEr6I=
|
||||
github.com/terra-farm/udnssdk v1.3.5/go.mod h1:8RnM56yZTR7mYyUIvrDgXzdRaEyFIzqdEi7+um26Sv8=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
@ -1047,8 +1006,6 @@ github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljT
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
|
||||
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||
github.com/ultradns/ultradns-sdk-go v1.3.7 h1:P4CaM+npeXIybbLL27ezR316NnyILI1Y8IvfZtNE+Co=
|
||||
github.com/ultradns/ultradns-sdk-go v1.3.7/go.mod h1:43vmy6GEvRuVMpGEWfJ/JoEM6RIqUQI1/tb8JqZR1zI=
|
||||
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
@ -1092,8 +1049,6 @@ go.etcd.io/etcd/client/v3 v3.6.0/go.mod h1:Jzk/Knqe06pkOZPHXsQ0+vNDvMQrgIqJ0W8Dw
|
||||
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
||||
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
||||
go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
||||
go.mongodb.org/mongo-driver v1.17.2 h1:gvZyk8352qSfzyZ2UMWcpDpMSGEr1eqE4T793SqyhzM=
|
||||
go.mongodb.org/mongo-driver v1.17.2/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
|
||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
|
@ -199,10 +199,6 @@ type Config struct {
|
||||
GoDaddyTTL int64
|
||||
GoDaddyOTE bool
|
||||
OCPRouterName string
|
||||
IBMCloudProxied bool
|
||||
IBMCloudConfigFile string
|
||||
TencentCloudConfigFile string
|
||||
TencentCloudZoneType string
|
||||
PiholeServer string
|
||||
PiholePassword string `secure:"yes"`
|
||||
PiholeTLSInsecureSkipVerify bool
|
||||
@ -293,8 +289,6 @@ var defaultConfig = &Config{
|
||||
GoogleBatchChangeSize: 1000,
|
||||
GoogleProject: "",
|
||||
GoogleZoneVisibility: "",
|
||||
IBMCloudConfigFile: "/etc/kubernetes/ibmcloud.json",
|
||||
IBMCloudProxied: false,
|
||||
IgnoreHostnameAnnotation: false,
|
||||
IgnoreIngressRulesSpec: false,
|
||||
IgnoreIngressTLSSpec: false,
|
||||
@ -360,8 +354,6 @@ var defaultConfig = &Config{
|
||||
SkipperRouteGroupVersion: "zalando.org/v1",
|
||||
Sources: nil,
|
||||
TargetNetFilter: []string{},
|
||||
TencentCloudConfigFile: "/etc/kubernetes/tencent-cloud.json",
|
||||
TencentCloudZoneType: "",
|
||||
TLSCA: "",
|
||||
TLSClientCert: "",
|
||||
TLSClientCertKey: "",
|
||||
@ -495,7 +487,7 @@ func App(cfg *Config) *kingpin.Application {
|
||||
app.Flag("traefik-disable-new", "Disable listeners on Resources under the traefik.io API Group").Default(strconv.FormatBool(defaultConfig.TraefikDisableNew)).BoolVar(&cfg.TraefikDisableNew)
|
||||
|
||||
// Flags related to providers
|
||||
providers := []string{"akamai", "alibabacloud", "aws", "aws-sd", "azure", "azure-dns", "azure-private-dns", "civo", "cloudflare", "coredns", "digitalocean", "dnsimple", "exoscale", "gandi", "godaddy", "google", "ibmcloud", "inmemory", "linode", "ns1", "oci", "ovh", "pdns", "pihole", "plural", "rfc2136", "scaleway", "skydns", "tencentcloud", "transip", "ultradns", "webhook"}
|
||||
providers := []string{"akamai", "alibabacloud", "aws", "aws-sd", "azure", "azure-dns", "azure-private-dns", "civo", "cloudflare", "coredns", "digitalocean", "dnsimple", "exoscale", "gandi", "godaddy", "google", "inmemory", "linode", "ns1", "oci", "ovh", "pdns", "pihole", "plural", "rfc2136", "scaleway", "skydns", "transip", "webhook"}
|
||||
app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: "+strings.Join(providers, ", ")+")").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, providers...)
|
||||
app.Flag("provider-cache-time", "The time to cache the DNS provider record list requests.").Default(defaultConfig.ProviderCacheTime.String()).DurationVar(&cfg.ProviderCacheTime)
|
||||
app.Flag("domain-filter", "Limit possible target zones by a domain suffix; specify multiple times for multiple domains (optional)").Default("").StringsVar(&cfg.DomainFilter)
|
||||
@ -532,8 +524,6 @@ func App(cfg *Config) *kingpin.Application {
|
||||
app.Flag("azure-user-assigned-identity-client-id", "When using the Azure provider, override the client id of user assigned identity in config file (optional)").Default("").StringVar(&cfg.AzureUserAssignedIdentityClientID)
|
||||
app.Flag("azure-zones-cache-duration", "When using the Azure provider, set the zones list cache TTL (0s to disable).").Default(defaultConfig.AzureZonesCacheDuration.String()).DurationVar(&cfg.AzureZonesCacheDuration)
|
||||
app.Flag("azure-maxretries-count", "When using the Azure provider, set the number of retries for API calls (When less than 0, it disables retries). (optional)").Default(strconv.Itoa(defaultConfig.AzureMaxRetriesCount)).IntVar(&cfg.AzureMaxRetriesCount)
|
||||
app.Flag("tencent-cloud-config-file", "When using the Tencent Cloud provider, specify the Tencent Cloud configuration file (required when --provider=tencentcloud)").Default(defaultConfig.TencentCloudConfigFile).StringVar(&cfg.TencentCloudConfigFile)
|
||||
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-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)
|
||||
@ -567,8 +557,6 @@ func App(cfg *Config) *kingpin.Application {
|
||||
app.Flag("ns1-ignoressl", "When using the NS1 provider, specify whether to verify the SSL certificate (default: false)").Default(strconv.FormatBool(defaultConfig.NS1IgnoreSSL)).BoolVar(&cfg.NS1IgnoreSSL)
|
||||
app.Flag("ns1-min-ttl", "Minimal TTL (in seconds) for records. This value will be used if the provided TTL for a service/ingress is lower than this.").IntVar(&cfg.NS1MinTTLSeconds)
|
||||
app.Flag("digitalocean-api-page-size", "Configure the page size used when querying the DigitalOcean API.").Default(strconv.Itoa(defaultConfig.DigitalOceanAPIPageSize)).IntVar(&cfg.DigitalOceanAPIPageSize)
|
||||
app.Flag("ibmcloud-config-file", "When using the IBM Cloud provider, specify the IBM Cloud configuration file (required when --provider=ibmcloud").Default(defaultConfig.IBMCloudConfigFile).StringVar(&cfg.IBMCloudConfigFile)
|
||||
app.Flag("ibmcloud-proxied", "When using the IBM provider, specify if the proxy mode must be enabled (default: disabled)").BoolVar(&cfg.IBMCloudProxied)
|
||||
// GoDaddy flags
|
||||
app.Flag("godaddy-api-key", "When using the GoDaddy provider, specify the API Key (required when --provider=godaddy)").Default(defaultConfig.GoDaddyAPIKey).StringVar(&cfg.GoDaddyAPIKey)
|
||||
app.Flag("godaddy-api-secret", "When using the GoDaddy provider, specify the API secret (required when --provider=godaddy)").Default(defaultConfig.GoDaddySecretKey).StringVar(&cfg.GoDaddySecretKey)
|
||||
|
@ -125,10 +125,6 @@ var (
|
||||
RFC2136Host: []string{""},
|
||||
RFC2136LoadBalancingStrategy: "disabled",
|
||||
OCPRouterName: "default",
|
||||
IBMCloudProxied: false,
|
||||
IBMCloudConfigFile: "/etc/kubernetes/ibmcloud.json",
|
||||
TencentCloudConfigFile: "/etc/kubernetes/tencent-cloud.json",
|
||||
TencentCloudZoneType: "",
|
||||
PiholeApiVersion: "5",
|
||||
WebhookProviderURL: "http://localhost:8888",
|
||||
WebhookProviderReadTimeout: 5 * time.Second,
|
||||
@ -242,10 +238,6 @@ var (
|
||||
RFC2136BatchChangeSize: 100,
|
||||
RFC2136Host: []string{"rfc2136-host1", "rfc2136-host2"},
|
||||
RFC2136LoadBalancingStrategy: "round-robin",
|
||||
IBMCloudProxied: true,
|
||||
IBMCloudConfigFile: "ibmcloud.json",
|
||||
TencentCloudConfigFile: "tencent-cloud.json",
|
||||
TencentCloudZoneType: "private",
|
||||
PiholeApiVersion: "6",
|
||||
WebhookProviderURL: "http://localhost:8888",
|
||||
WebhookProviderReadTimeout: 5 * time.Second,
|
||||
@ -396,10 +388,6 @@ func TestParseFlags(t *testing.T) {
|
||||
"--rfc2136-load-balancing-strategy=round-robin",
|
||||
"--rfc2136-host=rfc2136-host1",
|
||||
"--rfc2136-host=rfc2136-host2",
|
||||
"--ibmcloud-proxied",
|
||||
"--ibmcloud-config-file=ibmcloud.json",
|
||||
"--tencent-cloud-config-file=tencent-cloud.json",
|
||||
"--tencent-cloud-zone-type=private",
|
||||
},
|
||||
envVars: map[string]string{},
|
||||
expected: overriddenConfig,
|
||||
@ -516,10 +504,6 @@ func TestParseFlags(t *testing.T) {
|
||||
"EXTERNAL_DNS_RFC2136_BATCH_CHANGE_SIZE": "100",
|
||||
"EXTERNAL_DNS_RFC2136_LOAD_BALANCING_STRATEGY": "round-robin",
|
||||
"EXTERNAL_DNS_RFC2136_HOST": "rfc2136-host1\nrfc2136-host2",
|
||||
"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,
|
||||
},
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,953 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package ibmcloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/IBM/go-sdk-core/v5/core"
|
||||
"github.com/IBM/networking-go-sdk/dnsrecordsv1"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/IBM/networking-go-sdk/dnssvcsv1"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
||||
"sigs.k8s.io/external-dns/endpoint"
|
||||
"sigs.k8s.io/external-dns/plan"
|
||||
"sigs.k8s.io/external-dns/provider"
|
||||
)
|
||||
|
||||
func NewMockIBMCloudDNSAPI() *mockIbmcloudClientInterface {
|
||||
// Setup public example responses
|
||||
firstPublicRecord := dnsrecordsv1.DnsrecordDetails{
|
||||
ID: core.StringPtr("123"),
|
||||
Name: core.StringPtr("test.example.com"),
|
||||
Type: core.StringPtr("A"),
|
||||
Content: core.StringPtr("1.2.3.4"),
|
||||
Proxied: core.BoolPtr(true),
|
||||
TTL: core.Int64Ptr(int64(120)),
|
||||
}
|
||||
secondPublicRecord := dnsrecordsv1.DnsrecordDetails{
|
||||
ID: core.StringPtr("456"),
|
||||
Name: core.StringPtr("test.example.com"),
|
||||
Type: core.StringPtr("TXT"),
|
||||
Proxied: core.BoolPtr(false),
|
||||
Content: core.StringPtr("\"heritage=external-dns,external-dns/owner=tower-pdns\""),
|
||||
TTL: core.Int64Ptr(int64(120)),
|
||||
}
|
||||
publicRecordsResult := []dnsrecordsv1.DnsrecordDetails{firstPublicRecord, secondPublicRecord}
|
||||
publicRecordsResultInfo := &dnsrecordsv1.ResultInfo{
|
||||
Page: core.Int64Ptr(int64(1)),
|
||||
TotalCount: core.Int64Ptr(int64(1)),
|
||||
}
|
||||
|
||||
publicRecordsResp := &dnsrecordsv1.ListDnsrecordsResp{
|
||||
Result: publicRecordsResult,
|
||||
ResultInfo: publicRecordsResultInfo,
|
||||
}
|
||||
// Setup private example responses
|
||||
firstPrivateZone := dnssvcsv1.Dnszone{
|
||||
ID: core.StringPtr("123"),
|
||||
Name: core.StringPtr("example.com"),
|
||||
State: core.StringPtr(zoneStatePendingNetwork),
|
||||
}
|
||||
|
||||
secondPrivateZone := dnssvcsv1.Dnszone{
|
||||
ID: core.StringPtr("456"),
|
||||
Name: core.StringPtr("example1.com"),
|
||||
State: core.StringPtr(zoneStateActive),
|
||||
}
|
||||
privateZones := []dnssvcsv1.Dnszone{firstPrivateZone, secondPrivateZone}
|
||||
listZonesResp := &dnssvcsv1.ListDnszones{
|
||||
Dnszones: privateZones,
|
||||
}
|
||||
firstPrivateRecord := dnssvcsv1.ResourceRecord{
|
||||
ID: core.StringPtr("123"),
|
||||
Name: core.StringPtr("test.example.com"),
|
||||
Type: core.StringPtr("A"),
|
||||
Rdata: map[string]interface{}{"ip": "1.2.3.4"},
|
||||
TTL: core.Int64Ptr(int64(120)),
|
||||
}
|
||||
secondPrivateRecord := dnssvcsv1.ResourceRecord{
|
||||
ID: core.StringPtr("456"),
|
||||
Name: core.StringPtr("testCNAME.example.com"),
|
||||
Type: core.StringPtr("CNAME"),
|
||||
Rdata: map[string]interface{}{"cname": "test.example.com"},
|
||||
TTL: core.Int64Ptr(int64(120)),
|
||||
}
|
||||
thirdPrivateRecord := dnssvcsv1.ResourceRecord{
|
||||
ID: core.StringPtr("789"),
|
||||
Name: core.StringPtr("test.example.com"),
|
||||
Type: core.StringPtr("TXT"),
|
||||
Rdata: map[string]interface{}{"text": "\"heritage=external-dns,external-dns/owner=tower-pdns\""},
|
||||
TTL: core.Int64Ptr(int64(120)),
|
||||
}
|
||||
privateRecords := []dnssvcsv1.ResourceRecord{firstPrivateRecord, secondPrivateRecord, thirdPrivateRecord}
|
||||
privateRecordsResop := &dnssvcsv1.ListResourceRecords{
|
||||
ResourceRecords: privateRecords,
|
||||
Offset: core.Int64Ptr(int64(0)),
|
||||
TotalCount: core.Int64Ptr(int64(1)),
|
||||
}
|
||||
|
||||
// Setup record rData
|
||||
inputARecord := &dnssvcsv1.ResourceRecordInputRdataRdataARecord{
|
||||
Ip: core.StringPtr("1.2.3.4"),
|
||||
}
|
||||
inputCnameRecord := &dnssvcsv1.ResourceRecordInputRdataRdataCnameRecord{
|
||||
Cname: core.StringPtr("test.example.com"),
|
||||
}
|
||||
inputTxtRecord := &dnssvcsv1.ResourceRecordInputRdataRdataTxtRecord{
|
||||
Text: core.StringPtr("test"),
|
||||
}
|
||||
|
||||
updateARecord := &dnssvcsv1.ResourceRecordUpdateInputRdataRdataARecord{
|
||||
Ip: core.StringPtr("1.2.3.4"),
|
||||
}
|
||||
updateCnameRecord := &dnssvcsv1.ResourceRecordUpdateInputRdataRdataCnameRecord{
|
||||
Cname: core.StringPtr("test.example.com"),
|
||||
}
|
||||
updateTxtRecord := &dnssvcsv1.ResourceRecordUpdateInputRdataRdataTxtRecord{
|
||||
Text: core.StringPtr("test"),
|
||||
}
|
||||
|
||||
// Setup mock services
|
||||
mockDNSClient := &mockIbmcloudClientInterface{}
|
||||
mockDNSClient.On("CreateDNSRecordWithContext", mock.Anything, mock.Anything).Return(nil, nil, nil)
|
||||
mockDNSClient.On("UpdateDNSRecordWithContext", mock.Anything, mock.Anything).Return(nil, nil, nil)
|
||||
mockDNSClient.On("DeleteDNSRecordWithContext", mock.Anything, mock.Anything).Return(nil, nil, nil)
|
||||
mockDNSClient.On("ListAllDDNSRecordsWithContext", mock.Anything, mock.Anything).Return(publicRecordsResp, nil, nil)
|
||||
mockDNSClient.On("ListDnszonesWithContext", mock.Anything, mock.Anything).Return(listZonesResp, nil, nil)
|
||||
mockDNSClient.On("GetDnszoneWithContext", mock.Anything, mock.Anything).Return(&firstPrivateZone, nil, nil)
|
||||
mockDNSClient.On("ListResourceRecordsWithContext", mock.Anything, mock.Anything).Return(privateRecordsResop, nil, nil)
|
||||
mockDNSClient.On("CreatePermittedNetworkWithContext", mock.Anything, mock.Anything).Return(nil, nil, nil)
|
||||
mockDNSClient.On("CreateResourceRecordWithContext", mock.Anything, mock.Anything).Return(nil, nil, nil)
|
||||
mockDNSClient.On("DeleteResourceRecordWithContext", mock.Anything, mock.Anything).Return(nil, nil, nil)
|
||||
mockDNSClient.On("UpdateResourceRecordWithContext", mock.Anything, mock.Anything).Return(nil, nil, nil)
|
||||
mockDNSClient.On("NewResourceRecordInputRdataRdataARecord", mock.Anything).Return(inputARecord, nil)
|
||||
mockDNSClient.On("NewResourceRecordInputRdataRdataCnameRecord", mock.Anything).Return(inputCnameRecord, nil)
|
||||
mockDNSClient.On("NewResourceRecordInputRdataRdataTxtRecord", mock.Anything).Return(inputTxtRecord, nil)
|
||||
mockDNSClient.On("NewResourceRecordUpdateInputRdataRdataARecord", mock.Anything).Return(updateARecord, nil)
|
||||
mockDNSClient.On("NewResourceRecordUpdateInputRdataRdataCnameRecord", mock.Anything).Return(updateCnameRecord, nil)
|
||||
mockDNSClient.On("NewResourceRecordUpdateInputRdataRdataTxtRecord", mock.Anything).Return(updateTxtRecord, nil)
|
||||
|
||||
return mockDNSClient
|
||||
}
|
||||
|
||||
func newTestIBMCloudProvider(private bool) *IBMCloudProvider {
|
||||
mockSource := &mockSource{}
|
||||
endpoints := []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "new.example.com",
|
||||
Targets: endpoint.Targets{"4.3.2.1"},
|
||||
ProviderSpecific: endpoint.ProviderSpecific{
|
||||
{
|
||||
Name: "ibmcloud-vpc",
|
||||
Value: "crn:v1:staging:public:is:us-south:a/0821fa9f9ebcc7b7c9a0d6e9bf9442a4::vpc:be33cdad-9a03-4bfa-82ca-eadb9f1de688",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
mockSource.On("Endpoints", mock.Anything).Return(endpoints, nil, nil)
|
||||
|
||||
domainFilterTest := endpoint.NewDomainFilter([]string{"example.com"})
|
||||
|
||||
return &IBMCloudProvider{
|
||||
Client: NewMockIBMCloudDNSAPI(),
|
||||
source: mockSource,
|
||||
domainFilter: domainFilterTest,
|
||||
DryRun: false,
|
||||
instanceID: "test123",
|
||||
privateZone: private,
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublic_Records(t *testing.T) {
|
||||
p := newTestIBMCloudProvider(false)
|
||||
endpoints, err := p.Records(context.Background())
|
||||
if err != nil {
|
||||
t.Errorf("Failed to get records: %v", err)
|
||||
} else {
|
||||
if len(endpoints) != 2 {
|
||||
t.Errorf("Incorrect number of records: %d", len(endpoints))
|
||||
}
|
||||
for _, endpoint := range endpoints {
|
||||
t.Logf("Endpoint for %++v", *endpoint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrivate_Records(t *testing.T) {
|
||||
p := newTestIBMCloudProvider(true)
|
||||
endpoints, err := p.Records(context.Background())
|
||||
if err != nil {
|
||||
t.Errorf("Failed to get records: %v", err)
|
||||
} else {
|
||||
if len(endpoints) != 3 {
|
||||
t.Errorf("Incorrect number of records: %d", len(endpoints))
|
||||
}
|
||||
for _, endpoint := range endpoints {
|
||||
t.Logf("Endpoint for %++v", *endpoint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublic_ApplyChanges(t *testing.T) {
|
||||
p := newTestIBMCloudProvider(false)
|
||||
|
||||
changes := plan.Changes{
|
||||
Create: []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "newA.example.com",
|
||||
RecordType: "A",
|
||||
RecordTTL: 300,
|
||||
Targets: endpoint.NewTargets("4.3.2.1"),
|
||||
ProviderSpecific: endpoint.ProviderSpecific{
|
||||
{
|
||||
Name: "ibmcloud-proxied",
|
||||
Value: "false",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
UpdateOld: []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "test.example.com",
|
||||
RecordType: "A",
|
||||
RecordTTL: 180,
|
||||
Targets: endpoint.NewTargets("1.2.3.4"),
|
||||
ProviderSpecific: endpoint.ProviderSpecific{
|
||||
{
|
||||
Name: "ibmcloud-proxied",
|
||||
Value: "false",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
UpdateNew: []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "test.example.com",
|
||||
RecordType: "A",
|
||||
RecordTTL: 180,
|
||||
Targets: endpoint.NewTargets("1.2.3.4", "5.6.7.8"),
|
||||
ProviderSpecific: endpoint.ProviderSpecific{
|
||||
{
|
||||
Name: "ibmcloud-proxied",
|
||||
Value: "true",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Delete: []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "test.example.com",
|
||||
RecordType: "TXT",
|
||||
RecordTTL: 300,
|
||||
Targets: endpoint.NewTargets("\"heritage=external-dns,external-dns/owner=tower-pdns\""),
|
||||
},
|
||||
},
|
||||
}
|
||||
ctx := context.Background()
|
||||
err := p.ApplyChanges(ctx, &changes)
|
||||
if err != nil {
|
||||
t.Errorf("should not fail, %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrivate_ApplyChanges(t *testing.T) {
|
||||
p := newTestIBMCloudProvider(true)
|
||||
|
||||
endpointsCreate, err := p.AdjustEndpoints([]*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "newA.example.com",
|
||||
RecordType: "A",
|
||||
RecordTTL: 120,
|
||||
Targets: endpoint.NewTargets("4.3.2.1"),
|
||||
ProviderSpecific: endpoint.ProviderSpecific{
|
||||
{
|
||||
Name: "ibmcloud-vpc",
|
||||
Value: "crn:v1:staging:public:is:us-south:a/0821fa9f9ebcc7b7c9a0d6e9bf9442a4::vpc:be33cdad-9a03-4bfa-82ca-eadb9f1de688",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
DNSName: "newCNAME.example.com",
|
||||
RecordType: "CNAME",
|
||||
RecordTTL: 180,
|
||||
Targets: endpoint.NewTargets("newA.example.com"),
|
||||
},
|
||||
{
|
||||
DNSName: "newTXT.example.com",
|
||||
RecordType: "TXT",
|
||||
RecordTTL: 240,
|
||||
Targets: endpoint.NewTargets("\"heritage=external-dns,external-dns/owner=tower-pdns\""),
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
endpointsUpdate, err := p.AdjustEndpoints([]*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "test.example.com",
|
||||
RecordType: "A",
|
||||
RecordTTL: 180,
|
||||
Targets: endpoint.NewTargets("1.2.3.4", "5.6.7.8"),
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
changes := plan.Changes{
|
||||
Create: endpointsCreate,
|
||||
UpdateOld: []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "test.example.com",
|
||||
RecordType: "A",
|
||||
RecordTTL: 180,
|
||||
Targets: endpoint.NewTargets("1.2.3.4"),
|
||||
},
|
||||
},
|
||||
UpdateNew: endpointsUpdate,
|
||||
Delete: []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "test.example.com",
|
||||
RecordType: "TXT",
|
||||
RecordTTL: 300,
|
||||
Targets: endpoint.NewTargets("\"heritage=external-dns,external-dns/owner=tower-pdns\""),
|
||||
},
|
||||
},
|
||||
}
|
||||
ctx := context.Background()
|
||||
err = p.ApplyChanges(ctx, &changes)
|
||||
if err != nil {
|
||||
t.Errorf("should not fail, %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdjustEndpoints(t *testing.T) {
|
||||
p := newTestIBMCloudProvider(false)
|
||||
endpoints := []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "test.example.com",
|
||||
Targets: endpoint.Targets{"1.2.3.4"},
|
||||
RecordType: endpoint.RecordTypeA,
|
||||
RecordTTL: 300,
|
||||
Labels: endpoint.Labels{},
|
||||
ProviderSpecific: endpoint.ProviderSpecific{
|
||||
{
|
||||
Name: "ibmcloud-proxied",
|
||||
Value: "1",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ep, err := p.AdjustEndpoints(endpoints)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, endpoint.TTL(0), ep[0].RecordTTL)
|
||||
assert.Equal(t, "test.example.com", ep[0].DNSName)
|
||||
proxied, _ := ep[0].GetProviderSpecificProperty("ibmcloud-proxied")
|
||||
assert.Equal(t, "true", proxied)
|
||||
}
|
||||
|
||||
func TestPrivateZone_withFilterID(t *testing.T) {
|
||||
p := newTestIBMCloudProvider(true)
|
||||
p.zoneIDFilter = provider.NewZoneIDFilter([]string{"123", "456"})
|
||||
|
||||
zones, err := p.privateZones(context.Background())
|
||||
if err != nil {
|
||||
t.Errorf("should not fail, %s", err)
|
||||
} else {
|
||||
if len(zones) != 2 {
|
||||
t.Errorf("Incorrect number of zones: %d", len(zones))
|
||||
}
|
||||
for _, zone := range zones {
|
||||
t.Logf("zone %s", *zone.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublicConfig_Validate(t *testing.T) {
|
||||
// mock http server
|
||||
testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
|
||||
defer GinkgoRecover()
|
||||
time.Sleep(0)
|
||||
|
||||
// Set mock response
|
||||
res.Header().Set("Content-type", "application/json")
|
||||
res.WriteHeader(http.StatusOK)
|
||||
fmt.Fprintf(res, "%s", `{"success": true, "errors": [["Errors"]], "messages": [["Messages"]], "result": [{"id": "123", "created_on": "2014-01-01T05:20:00.12345Z", "modified_on": "2014-01-01T05:20:00.12345Z", "name": "example.com", "original_registrar": "GoDaddy", "original_dnshost": "NameCheap", "status": "active", "paused": false, "original_name_servers": ["ns1.originaldnshost.com"], "name_servers": ["ns001.name.cloud.ibm.com"]}], "result_info": {"page": 1, "per_page": 20, "count": 1, "total_count": 2000}}`)
|
||||
}))
|
||||
zoneIDFilterTest := provider.NewZoneIDFilter([]string{"123"})
|
||||
domainFilterTest := endpoint.NewDomainFilter([]string{"example.com"})
|
||||
cfg := &ibmcloudConfig{
|
||||
Endpoint: testServer.URL,
|
||||
CRN: "crn:v1:bluemix:public:internet-svcs:global:a/bcf1865e99742d38d2d5fc3fb80a5496:a6338168-9510-4951-9d67-425612de96f0::",
|
||||
}
|
||||
crn := cfg.CRN
|
||||
authenticator := &core.NoAuthAuthenticator{}
|
||||
service, isPrivate, err := cfg.Validate(authenticator, domainFilterTest, provider.NewZoneIDFilter([]string{""}))
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, isPrivate)
|
||||
assert.Equal(t, crn, *service.publicRecordsService.Crn)
|
||||
assert.Equal(t, "123", *service.publicRecordsService.ZoneIdentifier)
|
||||
|
||||
service, isPrivate, err = cfg.Validate(authenticator, endpoint.NewDomainFilter([]string{""}), zoneIDFilterTest)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, isPrivate)
|
||||
assert.Equal(t, crn, *service.publicRecordsService.Crn)
|
||||
assert.Equal(t, "123", *service.publicRecordsService.ZoneIdentifier)
|
||||
|
||||
testServer.Close()
|
||||
}
|
||||
|
||||
func TestPrivateConfig_Validate(t *testing.T) {
|
||||
zoneIDFilterTest := provider.NewZoneIDFilter([]string{"123"})
|
||||
domainFilterTest := endpoint.NewDomainFilter([]string{"example.com"})
|
||||
authenticator := &core.NoAuthAuthenticator{}
|
||||
cfg := &ibmcloudConfig{
|
||||
Endpoint: "XXX",
|
||||
CRN: "crn:v1:bluemix:public:dns-svcs:global:a/bcf1865e99742d38d2d5fc3fb80a5496:a6338168-9510-4951-9d67-425612de96f0::",
|
||||
}
|
||||
_, isPrivate, err := cfg.Validate(authenticator, domainFilterTest, zoneIDFilterTest)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, isPrivate)
|
||||
}
|
||||
|
||||
// mockIbmcloudClientInterface is an autogenerated mock type for the ibmcloudClient type
|
||||
type mockIbmcloudClientInterface struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// CreateDNSRecordWithContext provides a mock function with given fields: ctx, createDnsRecordOptions
|
||||
func (_m *mockIbmcloudClientInterface) CreateDNSRecordWithContext(ctx context.Context, createDnsRecordOptions *dnsrecordsv1.CreateDnsRecordOptions) (*dnsrecordsv1.DnsrecordResp, *core.DetailedResponse, error) {
|
||||
ret := _m.Called(ctx, createDnsRecordOptions)
|
||||
|
||||
var r0 *dnsrecordsv1.DnsrecordResp
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *dnsrecordsv1.CreateDnsRecordOptions) *dnsrecordsv1.DnsrecordResp); ok {
|
||||
r0 = rf(ctx, createDnsRecordOptions)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*dnsrecordsv1.DnsrecordResp)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 *core.DetailedResponse
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *dnsrecordsv1.CreateDnsRecordOptions) *core.DetailedResponse); ok {
|
||||
r1 = rf(ctx, createDnsRecordOptions)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(*core.DetailedResponse)
|
||||
}
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(context.Context, *dnsrecordsv1.CreateDnsRecordOptions) error); ok {
|
||||
r2 = rf(ctx, createDnsRecordOptions)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// CreatePermittedNetworkWithContext provides a mock function with given fields: ctx, createPermittedNetworkOptions
|
||||
func (_m *mockIbmcloudClientInterface) CreatePermittedNetworkWithContext(ctx context.Context, createPermittedNetworkOptions *dnssvcsv1.CreatePermittedNetworkOptions) (*dnssvcsv1.PermittedNetwork, *core.DetailedResponse, error) {
|
||||
ret := _m.Called(ctx, createPermittedNetworkOptions)
|
||||
|
||||
var r0 *dnssvcsv1.PermittedNetwork
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *dnssvcsv1.CreatePermittedNetworkOptions) *dnssvcsv1.PermittedNetwork); ok {
|
||||
r0 = rf(ctx, createPermittedNetworkOptions)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*dnssvcsv1.PermittedNetwork)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 *core.DetailedResponse
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *dnssvcsv1.CreatePermittedNetworkOptions) *core.DetailedResponse); ok {
|
||||
r1 = rf(ctx, createPermittedNetworkOptions)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(*core.DetailedResponse)
|
||||
}
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(context.Context, *dnssvcsv1.CreatePermittedNetworkOptions) error); ok {
|
||||
r2 = rf(ctx, createPermittedNetworkOptions)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// CreateResourceRecordWithContext provides a mock function with given fields: ctx, createResourceRecordOptions
|
||||
func (_m *mockIbmcloudClientInterface) CreateResourceRecordWithContext(ctx context.Context, createResourceRecordOptions *dnssvcsv1.CreateResourceRecordOptions) (*dnssvcsv1.ResourceRecord, *core.DetailedResponse, error) {
|
||||
ret := _m.Called(ctx, createResourceRecordOptions)
|
||||
|
||||
var r0 *dnssvcsv1.ResourceRecord
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *dnssvcsv1.CreateResourceRecordOptions) *dnssvcsv1.ResourceRecord); ok {
|
||||
r0 = rf(ctx, createResourceRecordOptions)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*dnssvcsv1.ResourceRecord)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 *core.DetailedResponse
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *dnssvcsv1.CreateResourceRecordOptions) *core.DetailedResponse); ok {
|
||||
r1 = rf(ctx, createResourceRecordOptions)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(*core.DetailedResponse)
|
||||
}
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(context.Context, *dnssvcsv1.CreateResourceRecordOptions) error); ok {
|
||||
r2 = rf(ctx, createResourceRecordOptions)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// DeleteDNSRecordWithContext provides a mock function with given fields: ctx, deleteDnsRecordOptions
|
||||
func (_m *mockIbmcloudClientInterface) DeleteDNSRecordWithContext(ctx context.Context, deleteDnsRecordOptions *dnsrecordsv1.DeleteDnsRecordOptions) (*dnsrecordsv1.DeleteDnsrecordResp, *core.DetailedResponse, error) {
|
||||
ret := _m.Called(ctx, deleteDnsRecordOptions)
|
||||
|
||||
var r0 *dnsrecordsv1.DeleteDnsrecordResp
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *dnsrecordsv1.DeleteDnsRecordOptions) *dnsrecordsv1.DeleteDnsrecordResp); ok {
|
||||
r0 = rf(ctx, deleteDnsRecordOptions)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*dnsrecordsv1.DeleteDnsrecordResp)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 *core.DetailedResponse
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *dnsrecordsv1.DeleteDnsRecordOptions) *core.DetailedResponse); ok {
|
||||
r1 = rf(ctx, deleteDnsRecordOptions)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(*core.DetailedResponse)
|
||||
}
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(context.Context, *dnsrecordsv1.DeleteDnsRecordOptions) error); ok {
|
||||
r2 = rf(ctx, deleteDnsRecordOptions)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// DeleteResourceRecordWithContext provides a mock function with given fields: ctx, deleteResourceRecordOptions
|
||||
func (_m *mockIbmcloudClientInterface) DeleteResourceRecordWithContext(ctx context.Context, deleteResourceRecordOptions *dnssvcsv1.DeleteResourceRecordOptions) (*core.DetailedResponse, error) {
|
||||
ret := _m.Called(ctx, deleteResourceRecordOptions)
|
||||
|
||||
var r0 *core.DetailedResponse
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *dnssvcsv1.DeleteResourceRecordOptions) *core.DetailedResponse); ok {
|
||||
r0 = rf(ctx, deleteResourceRecordOptions)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*core.DetailedResponse)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *dnssvcsv1.DeleteResourceRecordOptions) error); ok {
|
||||
r1 = rf(ctx, deleteResourceRecordOptions)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetDnszoneWithContext provides a mock function with given fields: ctx, getDnszoneOptions
|
||||
func (_m *mockIbmcloudClientInterface) GetDnszoneWithContext(ctx context.Context, getDnszoneOptions *dnssvcsv1.GetDnszoneOptions) (*dnssvcsv1.Dnszone, *core.DetailedResponse, error) {
|
||||
ret := _m.Called(ctx, getDnszoneOptions)
|
||||
|
||||
var r0 *dnssvcsv1.Dnszone
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *dnssvcsv1.GetDnszoneOptions) *dnssvcsv1.Dnszone); ok {
|
||||
r0 = rf(ctx, getDnszoneOptions)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*dnssvcsv1.Dnszone)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 *core.DetailedResponse
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *dnssvcsv1.GetDnszoneOptions) *core.DetailedResponse); ok {
|
||||
r1 = rf(ctx, getDnszoneOptions)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(*core.DetailedResponse)
|
||||
}
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(context.Context, *dnssvcsv1.GetDnszoneOptions) error); ok {
|
||||
r2 = rf(ctx, getDnszoneOptions)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// ListAllDDNSRecordsWithContext provides a mock function with given fields: ctx, listAllDnsRecordsOptions
|
||||
func (_m *mockIbmcloudClientInterface) ListAllDDNSRecordsWithContext(ctx context.Context, listAllDnsRecordsOptions *dnsrecordsv1.ListAllDnsRecordsOptions) (*dnsrecordsv1.ListDnsrecordsResp, *core.DetailedResponse, error) {
|
||||
ret := _m.Called(ctx, listAllDnsRecordsOptions)
|
||||
|
||||
var r0 *dnsrecordsv1.ListDnsrecordsResp
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *dnsrecordsv1.ListAllDnsRecordsOptions) *dnsrecordsv1.ListDnsrecordsResp); ok {
|
||||
r0 = rf(ctx, listAllDnsRecordsOptions)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*dnsrecordsv1.ListDnsrecordsResp)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 *core.DetailedResponse
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *dnsrecordsv1.ListAllDnsRecordsOptions) *core.DetailedResponse); ok {
|
||||
r1 = rf(ctx, listAllDnsRecordsOptions)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(*core.DetailedResponse)
|
||||
}
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(context.Context, *dnsrecordsv1.ListAllDnsRecordsOptions) error); ok {
|
||||
r2 = rf(ctx, listAllDnsRecordsOptions)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// ListDnszonesWithContext provides a mock function with given fields: ctx, listDnszonesOptions
|
||||
func (_m *mockIbmcloudClientInterface) ListDnszonesWithContext(ctx context.Context, listDnszonesOptions *dnssvcsv1.ListDnszonesOptions) (*dnssvcsv1.ListDnszones, *core.DetailedResponse, error) {
|
||||
ret := _m.Called(ctx, listDnszonesOptions)
|
||||
|
||||
var r0 *dnssvcsv1.ListDnszones
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *dnssvcsv1.ListDnszonesOptions) *dnssvcsv1.ListDnszones); ok {
|
||||
r0 = rf(ctx, listDnszonesOptions)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*dnssvcsv1.ListDnszones)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 *core.DetailedResponse
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *dnssvcsv1.ListDnszonesOptions) *core.DetailedResponse); ok {
|
||||
r1 = rf(ctx, listDnszonesOptions)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(*core.DetailedResponse)
|
||||
}
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(context.Context, *dnssvcsv1.ListDnszonesOptions) error); ok {
|
||||
r2 = rf(ctx, listDnszonesOptions)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// ListResourceRecordsWithContext provides a mock function with given fields: ctx, listResourceRecordsOptions
|
||||
func (_m *mockIbmcloudClientInterface) ListResourceRecordsWithContext(ctx context.Context, listResourceRecordsOptions *dnssvcsv1.ListResourceRecordsOptions) (*dnssvcsv1.ListResourceRecords, *core.DetailedResponse, error) {
|
||||
ret := _m.Called(ctx, listResourceRecordsOptions)
|
||||
|
||||
var r0 *dnssvcsv1.ListResourceRecords
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *dnssvcsv1.ListResourceRecordsOptions) *dnssvcsv1.ListResourceRecords); ok {
|
||||
r0 = rf(ctx, listResourceRecordsOptions)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*dnssvcsv1.ListResourceRecords)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 *core.DetailedResponse
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *dnssvcsv1.ListResourceRecordsOptions) *core.DetailedResponse); ok {
|
||||
r1 = rf(ctx, listResourceRecordsOptions)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(*core.DetailedResponse)
|
||||
}
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(context.Context, *dnssvcsv1.ListResourceRecordsOptions) error); ok {
|
||||
r2 = rf(ctx, listResourceRecordsOptions)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// NewResourceRecordInputRdataRdataARecord provides a mock function with given fields: ip
|
||||
func (_m *mockIbmcloudClientInterface) NewResourceRecordInputRdataRdataARecord(ip string) (*dnssvcsv1.ResourceRecordInputRdataRdataARecord, error) {
|
||||
ret := _m.Called(ip)
|
||||
|
||||
var r0 *dnssvcsv1.ResourceRecordInputRdataRdataARecord
|
||||
if rf, ok := ret.Get(0).(func(string) *dnssvcsv1.ResourceRecordInputRdataRdataARecord); ok {
|
||||
r0 = rf(ip)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*dnssvcsv1.ResourceRecordInputRdataRdataARecord)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||
r1 = rf(ip)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// NewResourceRecordInputRdataRdataCnameRecord provides a mock function with given fields: cname
|
||||
func (_m *mockIbmcloudClientInterface) NewResourceRecordInputRdataRdataCnameRecord(cname string) (*dnssvcsv1.ResourceRecordInputRdataRdataCnameRecord, error) {
|
||||
ret := _m.Called(cname)
|
||||
|
||||
var r0 *dnssvcsv1.ResourceRecordInputRdataRdataCnameRecord
|
||||
if rf, ok := ret.Get(0).(func(string) *dnssvcsv1.ResourceRecordInputRdataRdataCnameRecord); ok {
|
||||
r0 = rf(cname)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*dnssvcsv1.ResourceRecordInputRdataRdataCnameRecord)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||
r1 = rf(cname)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// NewResourceRecordInputRdataRdataTxtRecord provides a mock function with given fields: text
|
||||
func (_m *mockIbmcloudClientInterface) NewResourceRecordInputRdataRdataTxtRecord(text string) (*dnssvcsv1.ResourceRecordInputRdataRdataTxtRecord, error) {
|
||||
ret := _m.Called(text)
|
||||
|
||||
var r0 *dnssvcsv1.ResourceRecordInputRdataRdataTxtRecord
|
||||
if rf, ok := ret.Get(0).(func(string) *dnssvcsv1.ResourceRecordInputRdataRdataTxtRecord); ok {
|
||||
r0 = rf(text)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*dnssvcsv1.ResourceRecordInputRdataRdataTxtRecord)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||
r1 = rf(text)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// NewResourceRecordUpdateInputRdataRdataARecord provides a mock function with given fields: ip
|
||||
func (_m *mockIbmcloudClientInterface) NewResourceRecordUpdateInputRdataRdataARecord(ip string) (*dnssvcsv1.ResourceRecordUpdateInputRdataRdataARecord, error) {
|
||||
ret := _m.Called(ip)
|
||||
|
||||
var r0 *dnssvcsv1.ResourceRecordUpdateInputRdataRdataARecord
|
||||
if rf, ok := ret.Get(0).(func(string) *dnssvcsv1.ResourceRecordUpdateInputRdataRdataARecord); ok {
|
||||
r0 = rf(ip)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*dnssvcsv1.ResourceRecordUpdateInputRdataRdataARecord)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||
r1 = rf(ip)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// NewResourceRecordUpdateInputRdataRdataCnameRecord provides a mock function with given fields: cname
|
||||
func (_m *mockIbmcloudClientInterface) NewResourceRecordUpdateInputRdataRdataCnameRecord(cname string) (*dnssvcsv1.ResourceRecordUpdateInputRdataRdataCnameRecord, error) {
|
||||
ret := _m.Called(cname)
|
||||
|
||||
var r0 *dnssvcsv1.ResourceRecordUpdateInputRdataRdataCnameRecord
|
||||
if rf, ok := ret.Get(0).(func(string) *dnssvcsv1.ResourceRecordUpdateInputRdataRdataCnameRecord); ok {
|
||||
r0 = rf(cname)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*dnssvcsv1.ResourceRecordUpdateInputRdataRdataCnameRecord)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||
r1 = rf(cname)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// NewResourceRecordUpdateInputRdataRdataTxtRecord provides a mock function with given fields: text
|
||||
func (_m *mockIbmcloudClientInterface) NewResourceRecordUpdateInputRdataRdataTxtRecord(text string) (*dnssvcsv1.ResourceRecordUpdateInputRdataRdataTxtRecord, error) {
|
||||
ret := _m.Called(text)
|
||||
|
||||
var r0 *dnssvcsv1.ResourceRecordUpdateInputRdataRdataTxtRecord
|
||||
if rf, ok := ret.Get(0).(func(string) *dnssvcsv1.ResourceRecordUpdateInputRdataRdataTxtRecord); ok {
|
||||
r0 = rf(text)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*dnssvcsv1.ResourceRecordUpdateInputRdataRdataTxtRecord)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||
r1 = rf(text)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// UpdateDNSRecordWithContext provides a mock function with given fields: ctx, updateDnsRecordOptions
|
||||
func (_m *mockIbmcloudClientInterface) UpdateDNSRecordWithContext(ctx context.Context, updateDnsRecordOptions *dnsrecordsv1.UpdateDnsRecordOptions) (*dnsrecordsv1.DnsrecordResp, *core.DetailedResponse, error) {
|
||||
ret := _m.Called(ctx, updateDnsRecordOptions)
|
||||
|
||||
var r0 *dnsrecordsv1.DnsrecordResp
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *dnsrecordsv1.UpdateDnsRecordOptions) *dnsrecordsv1.DnsrecordResp); ok {
|
||||
r0 = rf(ctx, updateDnsRecordOptions)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*dnsrecordsv1.DnsrecordResp)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 *core.DetailedResponse
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *dnsrecordsv1.UpdateDnsRecordOptions) *core.DetailedResponse); ok {
|
||||
r1 = rf(ctx, updateDnsRecordOptions)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(*core.DetailedResponse)
|
||||
}
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(context.Context, *dnsrecordsv1.UpdateDnsRecordOptions) error); ok {
|
||||
r2 = rf(ctx, updateDnsRecordOptions)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// UpdateResourceRecordWithContext provides a mock function with given fields: ctx, updateResourceRecordOptions
|
||||
func (_m *mockIbmcloudClientInterface) UpdateResourceRecordWithContext(ctx context.Context, updateResourceRecordOptions *dnssvcsv1.UpdateResourceRecordOptions) (*dnssvcsv1.ResourceRecord, *core.DetailedResponse, error) {
|
||||
ret := _m.Called(ctx, updateResourceRecordOptions)
|
||||
|
||||
var r0 *dnssvcsv1.ResourceRecord
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *dnssvcsv1.UpdateResourceRecordOptions) *dnssvcsv1.ResourceRecord); ok {
|
||||
r0 = rf(ctx, updateResourceRecordOptions)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*dnssvcsv1.ResourceRecord)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 *core.DetailedResponse
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *dnssvcsv1.UpdateResourceRecordOptions) *core.DetailedResponse); ok {
|
||||
r1 = rf(ctx, updateResourceRecordOptions)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(*core.DetailedResponse)
|
||||
}
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(context.Context, *dnssvcsv1.UpdateResourceRecordOptions) error); ok {
|
||||
r2 = rf(ctx, updateResourceRecordOptions)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
type mockSource struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// Endpoints provides a mock function with given fields: ctx
|
||||
func (_m *mockSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error) {
|
||||
ret := _m.Called(ctx)
|
||||
|
||||
var r0 []*endpoint.Endpoint
|
||||
if rf, ok := ret.Get(0).(func(context.Context) []*endpoint.Endpoint); ok {
|
||||
r0 = rf(ctx)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*endpoint.Endpoint)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
|
||||
r1 = rf(ctx)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// AddEventHandler provides a mock function with given fields: _a0, _a1
|
||||
func (_m *mockSource) AddEventHandler(_a0 context.Context, _a1 func()) {
|
||||
_m.Called(_a0, _a1)
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cloudapi
|
||||
|
||||
import (
|
||||
dnspod "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod/v20210323"
|
||||
privatedns "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns/v20201028"
|
||||
)
|
||||
|
||||
type Action struct {
|
||||
Service string `json:"service"`
|
||||
Name string `json:"name"`
|
||||
ReadOnly bool `json:"readOnly"`
|
||||
}
|
||||
|
||||
var (
|
||||
/* PrivateDNS */
|
||||
CreatePrivateZoneRecord = Action{Service: "PrivateDns", Name: "CreatePrivateZoneRecord", ReadOnly: false}
|
||||
DeletePrivateZoneRecord = Action{Service: "PrivateDns", Name: "DeletePrivateZoneRecord", ReadOnly: false}
|
||||
ModifyPrivateZoneRecord = Action{Service: "PrivateDns", Name: "ModifyPrivateZoneRecord", ReadOnly: false}
|
||||
DescribePrivateZoneList = Action{Service: "PrivateDns", Name: "DescribePrivateZoneList", ReadOnly: true}
|
||||
DescribePrivateZoneRecordList = Action{Service: "PrivateDns", Name: "DescribePrivateZoneRecordList", ReadOnly: true}
|
||||
|
||||
/* DNSPod */
|
||||
DescribeDomainList = Action{Service: "DnsPod", Name: "DescribeDomainList", ReadOnly: true}
|
||||
DescribeRecordList = Action{Service: "DnsPod", Name: "DescribeRecordList", ReadOnly: true}
|
||||
CreateRecord = Action{Service: "DnsPod", Name: "CreateRecord", ReadOnly: false}
|
||||
DeleteRecord = Action{Service: "DnsPod", Name: "DeleteRecord", ReadOnly: false}
|
||||
ModifyRecord = Action{Service: "DnsPod", Name: "ModifyRecord", ReadOnly: false}
|
||||
)
|
||||
|
||||
type TencentAPIService interface {
|
||||
// PrivateDNS
|
||||
CreatePrivateZoneRecord(request *privatedns.CreatePrivateZoneRecordRequest) (response *privatedns.CreatePrivateZoneRecordResponse, err error)
|
||||
DeletePrivateZoneRecord(request *privatedns.DeletePrivateZoneRecordRequest) (response *privatedns.DeletePrivateZoneRecordResponse, err error)
|
||||
ModifyPrivateZoneRecord(request *privatedns.ModifyPrivateZoneRecordRequest) (response *privatedns.ModifyPrivateZoneRecordResponse, err error)
|
||||
DescribePrivateZoneList(request *privatedns.DescribePrivateZoneListRequest) (response *privatedns.DescribePrivateZoneListResponse, err error)
|
||||
DescribePrivateZoneRecordList(request *privatedns.DescribePrivateZoneRecordListRequest) (response *privatedns.DescribePrivateZoneRecordListResponse, err error)
|
||||
|
||||
// DNSPod
|
||||
DescribeDomainList(request *dnspod.DescribeDomainListRequest) (response *dnspod.DescribeDomainListResponse, err error)
|
||||
DescribeRecordList(request *dnspod.DescribeRecordListRequest) (response *dnspod.DescribeRecordListResponse, err error)
|
||||
CreateRecord(request *dnspod.CreateRecordRequest) (response *dnspod.CreateRecordResponse, err error)
|
||||
DeleteRecord(request *dnspod.DeleteRecordRequest) (response *dnspod.DeleteRecordResponse, err error)
|
||||
ModifyRecord(request *dnspod.ModifyRecordRequest) (response *dnspod.ModifyRecordResponse, err error)
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cloudapi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
|
||||
dnspod "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod/v20210323"
|
||||
privatedns "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns/v20201028"
|
||||
"go.uber.org/ratelimit"
|
||||
)
|
||||
|
||||
type TencentClientSetService interface {
|
||||
PrivateDnsCli(action string) *privatedns.Client
|
||||
DnsPodCli(action string) *dnspod.Client
|
||||
}
|
||||
|
||||
func NewTencentClientSetService(region string, rate int, secretId string, secretKey string, internetEndpoint bool) *defaultTencentClientSetService {
|
||||
p := &defaultTencentClientSetService{
|
||||
Region: region,
|
||||
RateLimit: rate,
|
||||
}
|
||||
cred := common.NewCredential(secretId, secretKey)
|
||||
|
||||
privatednsProf := profile.NewClientProfile()
|
||||
if !internetEndpoint {
|
||||
privatednsProf.HttpProfile.Endpoint = "privatedns.internal.tencentcloudapi.com"
|
||||
}
|
||||
p.privateDnsClient, _ = privatedns.NewClient(cred, region, privatednsProf)
|
||||
|
||||
dnsPodProf := profile.NewClientProfile()
|
||||
if !internetEndpoint {
|
||||
dnsPodProf.HttpProfile.Endpoint = "dnspod.internal.tencentcloudapi.com"
|
||||
}
|
||||
p.dnsPodClient, _ = dnspod.NewClient(cred, region, dnsPodProf)
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
type defaultTencentClientSetService struct {
|
||||
Region string
|
||||
RateLimit int
|
||||
RateLimitSyncMap sync.Map
|
||||
|
||||
privateDnsClient *privatedns.Client
|
||||
dnsPodClient *dnspod.Client
|
||||
}
|
||||
|
||||
func (p *defaultTencentClientSetService) checkRateLimit(request, method string) {
|
||||
action := fmt.Sprintf("%s_%s", request, method)
|
||||
if rl, ok := p.RateLimitSyncMap.LoadOrStore(action, ratelimit.New(p.RateLimit, ratelimit.WithoutSlack)); ok {
|
||||
rl.(ratelimit.Limiter).Take()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *defaultTencentClientSetService) PrivateDnsCli(action string) *privatedns.Client {
|
||||
p.checkRateLimit("privateDns", action)
|
||||
return p.privateDnsClient
|
||||
}
|
||||
|
||||
func (p *defaultTencentClientSetService) DnsPodCli(action string) *dnspod.Client {
|
||||
p.checkRateLimit("dnsPod", action)
|
||||
return p.dnsPodClient
|
||||
}
|
@ -1,234 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cloudapi
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
|
||||
dnspod "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod/v20210323"
|
||||
privatedns "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns/v20201028"
|
||||
)
|
||||
|
||||
type mockAPIService struct {
|
||||
privateZones []*privatedns.PrivateZone
|
||||
privateZoneRecords map[string][]*privatedns.PrivateZoneRecord
|
||||
|
||||
dnspodDomains []*dnspod.DomainListItem
|
||||
dnspodRecords map[string][]*dnspod.RecordListItem
|
||||
}
|
||||
|
||||
func NewMockService(privateZones []*privatedns.PrivateZone, privateZoneRecords map[string][]*privatedns.PrivateZoneRecord, dnspodDomains []*dnspod.DomainListItem, dnspodRecords map[string][]*dnspod.RecordListItem) *mockAPIService {
|
||||
return &mockAPIService{
|
||||
privateZones: privateZones,
|
||||
privateZoneRecords: privateZoneRecords,
|
||||
dnspodDomains: dnspodDomains,
|
||||
dnspodRecords: dnspodRecords,
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// PrivateDns API
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
func (api *mockAPIService) CreatePrivateZoneRecord(request *privatedns.CreatePrivateZoneRecordRequest) (response *privatedns.CreatePrivateZoneRecordResponse, err error) {
|
||||
randomRecordId := RandStringRunes(8)
|
||||
if _, exist := api.privateZoneRecords[*request.ZoneId]; !exist {
|
||||
api.privateZoneRecords[*request.ZoneId] = make([]*privatedns.PrivateZoneRecord, 0)
|
||||
}
|
||||
if request.TTL == nil {
|
||||
request.TTL = common.Int64Ptr(300)
|
||||
}
|
||||
api.privateZoneRecords[*request.ZoneId] = append(api.privateZoneRecords[*request.ZoneId], &privatedns.PrivateZoneRecord{
|
||||
RecordId: common.StringPtr(randomRecordId),
|
||||
ZoneId: request.ZoneId,
|
||||
SubDomain: request.SubDomain,
|
||||
RecordType: request.RecordType,
|
||||
RecordValue: request.RecordValue,
|
||||
TTL: request.TTL,
|
||||
})
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (api *mockAPIService) DeletePrivateZoneRecord(request *privatedns.DeletePrivateZoneRecordRequest) (response *privatedns.DeletePrivateZoneRecordResponse, err error) {
|
||||
result := make([]*privatedns.PrivateZoneRecord, 0)
|
||||
if _, exist := api.privateZoneRecords[*request.ZoneId]; !exist {
|
||||
return response, nil
|
||||
}
|
||||
for _, privateZoneRecord := range api.privateZoneRecords[*request.ZoneId] {
|
||||
deleteflag := false
|
||||
if len(request.RecordIdSet) != 0 {
|
||||
for _, recordId := range request.RecordIdSet {
|
||||
if *privateZoneRecord.RecordId == *recordId {
|
||||
deleteflag = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if request.RecordId != nil && *request.RecordId == *privateZoneRecord.RecordId {
|
||||
deleteflag = true
|
||||
}
|
||||
if !deleteflag {
|
||||
result = append(result, privateZoneRecord)
|
||||
}
|
||||
}
|
||||
api.privateZoneRecords[*request.ZoneId] = result
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (api *mockAPIService) ModifyPrivateZoneRecord(request *privatedns.ModifyPrivateZoneRecordRequest) (response *privatedns.ModifyPrivateZoneRecordResponse, err error) {
|
||||
if _, exist := api.privateZoneRecords[*request.ZoneId]; !exist {
|
||||
return response, nil
|
||||
}
|
||||
for _, privateZoneRecord := range api.privateZoneRecords[*request.ZoneId] {
|
||||
if *privateZoneRecord.RecordId != *request.RecordId {
|
||||
continue
|
||||
}
|
||||
privateZoneRecord.ZoneId = request.ZoneId
|
||||
privateZoneRecord.SubDomain = request.SubDomain
|
||||
privateZoneRecord.RecordType = request.RecordType
|
||||
privateZoneRecord.RecordValue = request.RecordValue
|
||||
privateZoneRecord.TTL = request.TTL
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (api *mockAPIService) DescribePrivateZoneList(request *privatedns.DescribePrivateZoneListRequest) (response *privatedns.DescribePrivateZoneListResponse, err error) {
|
||||
response = privatedns.NewDescribePrivateZoneListResponse()
|
||||
response.Response = &privatedns.DescribePrivateZoneListResponseParams{
|
||||
TotalCount: common.Int64Ptr(int64(len(api.privateZones))),
|
||||
PrivateZoneSet: api.privateZones,
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (api *mockAPIService) DescribePrivateZoneRecordList(request *privatedns.DescribePrivateZoneRecordListRequest) (response *privatedns.DescribePrivateZoneRecordListResponse, err error) {
|
||||
response = privatedns.NewDescribePrivateZoneRecordListResponse()
|
||||
response.Response = &privatedns.DescribePrivateZoneRecordListResponseParams{}
|
||||
if _, exist := api.privateZoneRecords[*request.ZoneId]; !exist {
|
||||
response.Response.TotalCount = common.Int64Ptr(0)
|
||||
response.Response.RecordSet = make([]*privatedns.PrivateZoneRecord, 0)
|
||||
return response, nil
|
||||
}
|
||||
response.Response.TotalCount = common.Int64Ptr(int64(len(api.privateZoneRecords[*request.ZoneId])))
|
||||
response.Response.RecordSet = api.privateZoneRecords[*request.ZoneId]
|
||||
return response, nil
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// DnsPod API
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
func (api *mockAPIService) DescribeDomainList(request *dnspod.DescribeDomainListRequest) (response *dnspod.DescribeDomainListResponse, err error) {
|
||||
response = dnspod.NewDescribeDomainListResponse()
|
||||
response.Response = &dnspod.DescribeDomainListResponseParams{
|
||||
DomainCountInfo: &dnspod.DomainCountInfo{
|
||||
AllTotal: common.Uint64Ptr(uint64(len(api.dnspodDomains))),
|
||||
},
|
||||
DomainList: api.dnspodDomains,
|
||||
}
|
||||
response.Response.DomainList = api.dnspodDomains
|
||||
response.Response.DomainCountInfo = &dnspod.DomainCountInfo{
|
||||
AllTotal: common.Uint64Ptr(uint64(len(api.dnspodDomains))),
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (api *mockAPIService) DescribeRecordList(request *dnspod.DescribeRecordListRequest) (response *dnspod.DescribeRecordListResponse, err error) {
|
||||
response = dnspod.NewDescribeRecordListResponse()
|
||||
response.Response = &dnspod.DescribeRecordListResponseParams{}
|
||||
if _, exist := api.dnspodRecords[*request.Domain]; !exist {
|
||||
response.Response.RecordList = make([]*dnspod.RecordListItem, 0)
|
||||
response.Response.RecordCountInfo = &dnspod.RecordCountInfo{
|
||||
TotalCount: common.Uint64Ptr(uint64(0)),
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
response.Response.RecordList = api.dnspodRecords[*request.Domain]
|
||||
response.Response.RecordCountInfo = &dnspod.RecordCountInfo{
|
||||
TotalCount: common.Uint64Ptr(uint64(len(api.dnspodRecords[*request.Domain]))),
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (api *mockAPIService) CreateRecord(request *dnspod.CreateRecordRequest) (response *dnspod.CreateRecordResponse, err error) {
|
||||
randomRecordId := RandUint64()
|
||||
if _, exist := api.dnspodRecords[*request.Domain]; !exist {
|
||||
api.dnspodRecords[*request.Domain] = make([]*dnspod.RecordListItem, 0)
|
||||
}
|
||||
if request.TTL == nil {
|
||||
request.TTL = common.Uint64Ptr(300)
|
||||
}
|
||||
api.dnspodRecords[*request.Domain] = append(api.dnspodRecords[*request.Domain], &dnspod.RecordListItem{
|
||||
RecordId: common.Uint64Ptr(randomRecordId),
|
||||
Value: request.Value,
|
||||
TTL: request.TTL,
|
||||
Name: request.SubDomain,
|
||||
Line: request.RecordLine,
|
||||
LineId: request.RecordLineId,
|
||||
Type: request.RecordType,
|
||||
})
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (api *mockAPIService) DeleteRecord(request *dnspod.DeleteRecordRequest) (response *dnspod.DeleteRecordResponse, err error) {
|
||||
result := make([]*dnspod.RecordListItem, 0)
|
||||
if _, exist := api.dnspodRecords[*request.Domain]; !exist {
|
||||
return response, nil
|
||||
}
|
||||
for _, zoneRecord := range api.dnspodRecords[*request.Domain] {
|
||||
deleteflag := false
|
||||
if request.RecordId != nil && *request.RecordId == *zoneRecord.RecordId {
|
||||
deleteflag = true
|
||||
}
|
||||
if !deleteflag {
|
||||
result = append(result, zoneRecord)
|
||||
}
|
||||
}
|
||||
api.dnspodRecords[*request.Domain] = result
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (api *mockAPIService) ModifyRecord(request *dnspod.ModifyRecordRequest) (response *dnspod.ModifyRecordResponse, err error) {
|
||||
if _, exist := api.dnspodRecords[*request.Domain]; !exist {
|
||||
return response, nil
|
||||
}
|
||||
for _, zoneRecord := range api.dnspodRecords[*request.Domain] {
|
||||
if *zoneRecord.RecordId != *request.RecordId {
|
||||
continue
|
||||
}
|
||||
zoneRecord.Type = request.RecordType
|
||||
zoneRecord.Name = request.SubDomain
|
||||
zoneRecord.Value = request.Value
|
||||
zoneRecord.TTL = request.TTL
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
var letterRunes = []byte("abcdefghijklmnopqrstuvwxyz")
|
||||
|
||||
func RandStringRunes(n int) string {
|
||||
b := make([]byte, n)
|
||||
for i := range b {
|
||||
b[i] = letterRunes[rand.Intn(len(letterRunes))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func RandUint64() uint64 {
|
||||
return rand.Uint64()
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cloudapi
|
||||
|
||||
import (
|
||||
dnspod "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod/v20210323"
|
||||
privatedns "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns/v20201028"
|
||||
)
|
||||
|
||||
type readonlyAPIService struct {
|
||||
defaultTencentAPIService
|
||||
}
|
||||
|
||||
func NewReadOnlyAPIService(region string, rate int, secretId string, secretKey string, internetEndpoint bool) *readonlyAPIService {
|
||||
apiService := NewTencentAPIService(region, rate, secretId, secretKey, internetEndpoint)
|
||||
tencentAPIService := &readonlyAPIService{
|
||||
*apiService,
|
||||
}
|
||||
return tencentAPIService
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// PrivateDns API
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
func (api *readonlyAPIService) CreatePrivateZoneRecord(request *privatedns.CreatePrivateZoneRecordRequest) (response *privatedns.CreatePrivateZoneRecordResponse, err error) {
|
||||
apiAction := CreatePrivateZoneRecord
|
||||
APIRecord(apiAction, JsonWrapper(request), "dryRun")
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (api *readonlyAPIService) DeletePrivateZoneRecord(request *privatedns.DeletePrivateZoneRecordRequest) (response *privatedns.DeletePrivateZoneRecordResponse, err error) {
|
||||
apiAction := DeletePrivateZoneRecord
|
||||
APIRecord(apiAction, JsonWrapper(request), "dryRun")
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (api *readonlyAPIService) ModifyPrivateZoneRecord(request *privatedns.ModifyPrivateZoneRecordRequest) (response *privatedns.ModifyPrivateZoneRecordResponse, err error) {
|
||||
apiAction := ModifyPrivateZoneRecord
|
||||
APIRecord(apiAction, JsonWrapper(request), "dryRun")
|
||||
return response, nil
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// DnsPod API
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
func (api *readonlyAPIService) CreateRecord(request *dnspod.CreateRecordRequest) (response *dnspod.CreateRecordResponse, err error) {
|
||||
apiAction := CreateRecord
|
||||
APIRecord(apiAction, JsonWrapper(request), "dryRun")
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (api *readonlyAPIService) DeleteRecord(request *dnspod.DeleteRecordRequest) (response *dnspod.DeleteRecordResponse, err error) {
|
||||
apiAction := DeleteRecord
|
||||
APIRecord(apiAction, JsonWrapper(request), "dryRun")
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (api *readonlyAPIService) ModifyRecord(request *dnspod.ModifyRecordRequest) (response *dnspod.ModifyRecordResponse, err error) {
|
||||
apiAction := ModifyRecord
|
||||
APIRecord(apiAction, JsonWrapper(request), "dryRun")
|
||||
return response, nil
|
||||
}
|
@ -1,278 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cloudapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
tclouderrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
|
||||
dnspod "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod/v20210323"
|
||||
privatedns "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns/v20201028"
|
||||
)
|
||||
|
||||
type defaultTencentAPIService struct {
|
||||
RetryDefault int
|
||||
TaskCheckInterval time.Duration
|
||||
ClientSetService TencentClientSetService
|
||||
}
|
||||
|
||||
func NewTencentAPIService(region string, rate int, secretId string, secretKey string, internetEndpoint bool) *defaultTencentAPIService {
|
||||
tencentAPIService := &defaultTencentAPIService{
|
||||
RetryDefault: 3,
|
||||
TaskCheckInterval: 3 * time.Second,
|
||||
ClientSetService: NewTencentClientSetService(region, rate, secretId, secretKey, internetEndpoint),
|
||||
}
|
||||
return tencentAPIService
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////
|
||||
// PrivateDns API
|
||||
// //////////////////////////////////////////////////////////////
|
||||
|
||||
func (api *defaultTencentAPIService) CreatePrivateZoneRecord(request *privatedns.CreatePrivateZoneRecordRequest) (response *privatedns.CreatePrivateZoneRecordResponse, err error) {
|
||||
apiAction := CreatePrivateZoneRecord
|
||||
for times := 1; times <= api.RetryDefault; times++ {
|
||||
client := api.ClientSetService.PrivateDnsCli(apiAction.Name)
|
||||
if response, err = client.CreatePrivateZoneRecord(request); err != nil {
|
||||
requestJson := JsonWrapper(request)
|
||||
if retry := dealWithError(apiAction, requestJson, err); retry || times == api.RetryDefault {
|
||||
APIErrorRecord(apiAction, requestJson, JsonWrapper(response), err)
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
APIRecord(apiAction, JsonWrapper(request), JsonWrapper(response))
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (api *defaultTencentAPIService) DeletePrivateZoneRecord(request *privatedns.DeletePrivateZoneRecordRequest) (response *privatedns.DeletePrivateZoneRecordResponse, err error) {
|
||||
apiAction := DeletePrivateZoneRecord
|
||||
for times := 1; times <= api.RetryDefault; times++ {
|
||||
client := api.ClientSetService.PrivateDnsCli(apiAction.Name)
|
||||
if response, err = client.DeletePrivateZoneRecord(request); err != nil {
|
||||
requestJson := JsonWrapper(request)
|
||||
if retry := dealWithError(apiAction, requestJson, err); retry || times == api.RetryDefault {
|
||||
APIErrorRecord(apiAction, requestJson, JsonWrapper(response), err)
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
APIRecord(apiAction, JsonWrapper(request), JsonWrapper(response))
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (api *defaultTencentAPIService) ModifyPrivateZoneRecord(request *privatedns.ModifyPrivateZoneRecordRequest) (response *privatedns.ModifyPrivateZoneRecordResponse, err error) {
|
||||
apiAction := ModifyPrivateZoneRecord
|
||||
for times := 1; times <= api.RetryDefault; times++ {
|
||||
client := api.ClientSetService.PrivateDnsCli(apiAction.Name)
|
||||
if response, err = client.ModifyPrivateZoneRecord(request); err != nil {
|
||||
requestJson := JsonWrapper(request)
|
||||
if retry := dealWithError(apiAction, requestJson, err); retry || times == api.RetryDefault {
|
||||
APIErrorRecord(apiAction, requestJson, JsonWrapper(response), err)
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
APIRecord(apiAction, JsonWrapper(request), JsonWrapper(response))
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (api *defaultTencentAPIService) DescribePrivateZoneList(request *privatedns.DescribePrivateZoneListRequest) (response *privatedns.DescribePrivateZoneListResponse, err error) {
|
||||
apiAction := DescribePrivateZoneList
|
||||
for times := 1; times <= api.RetryDefault; times++ {
|
||||
client := api.ClientSetService.PrivateDnsCli(apiAction.Name)
|
||||
if response, err = client.DescribePrivateZoneList(request); err != nil {
|
||||
requestJson := JsonWrapper(request)
|
||||
if retry := dealWithError(apiAction, requestJson, err); retry || times == api.RetryDefault {
|
||||
APIErrorRecord(apiAction, requestJson, JsonWrapper(response), err)
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
APIRecord(apiAction, JsonWrapper(request), JsonWrapper(response))
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (api *defaultTencentAPIService) DescribePrivateZoneRecordList(request *privatedns.DescribePrivateZoneRecordListRequest) (response *privatedns.DescribePrivateZoneRecordListResponse, err error) {
|
||||
apiAction := DescribePrivateZoneRecordList
|
||||
for times := 1; times <= api.RetryDefault; times++ {
|
||||
client := api.ClientSetService.PrivateDnsCli(apiAction.Name)
|
||||
if response, err = client.DescribePrivateZoneRecordList(request); err != nil {
|
||||
requestJson := JsonWrapper(request)
|
||||
if retry := dealWithError(apiAction, requestJson, err); retry || times == api.RetryDefault {
|
||||
APIErrorRecord(apiAction, requestJson, JsonWrapper(response), err)
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
APIRecord(apiAction, JsonWrapper(request), JsonWrapper(response))
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////
|
||||
// DnsPod API
|
||||
// //////////////////////////////////////////////////////////////
|
||||
|
||||
func (api *defaultTencentAPIService) DescribeDomainList(request *dnspod.DescribeDomainListRequest) (response *dnspod.DescribeDomainListResponse, err error) {
|
||||
apiAction := DescribeDomainList
|
||||
for times := 1; times <= api.RetryDefault; times++ {
|
||||
client := api.ClientSetService.DnsPodCli(apiAction.Name)
|
||||
if response, err = client.DescribeDomainList(request); err != nil {
|
||||
requestJson := JsonWrapper(request)
|
||||
if retry := dealWithError(apiAction, requestJson, err); retry || times == api.RetryDefault {
|
||||
APIErrorRecord(apiAction, requestJson, JsonWrapper(response), err)
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
APIRecord(apiAction, JsonWrapper(request), JsonWrapper(response))
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (api *defaultTencentAPIService) DescribeRecordList(request *dnspod.DescribeRecordListRequest) (response *dnspod.DescribeRecordListResponse, err error) {
|
||||
apiAction := DescribeRecordList
|
||||
for times := 1; times <= api.RetryDefault; times++ {
|
||||
client := api.ClientSetService.DnsPodCli(apiAction.Name)
|
||||
if response, err = client.DescribeRecordList(request); err != nil {
|
||||
requestJson := JsonWrapper(request)
|
||||
if retry := dealWithError(apiAction, requestJson, err); retry || times == api.RetryDefault {
|
||||
APIErrorRecord(apiAction, requestJson, JsonWrapper(response), err)
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
APIRecord(apiAction, JsonWrapper(request), JsonWrapper(response))
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (api *defaultTencentAPIService) CreateRecord(request *dnspod.CreateRecordRequest) (response *dnspod.CreateRecordResponse, err error) {
|
||||
apiAction := CreateRecord
|
||||
for times := 1; times <= api.RetryDefault; times++ {
|
||||
client := api.ClientSetService.DnsPodCli(apiAction.Name)
|
||||
if response, err = client.CreateRecord(request); err != nil {
|
||||
requestJson := JsonWrapper(request)
|
||||
if retry := dealWithError(apiAction, requestJson, err); retry || times == api.RetryDefault {
|
||||
APIErrorRecord(apiAction, requestJson, JsonWrapper(response), err)
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
APIRecord(apiAction, JsonWrapper(request), JsonWrapper(response))
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (api *defaultTencentAPIService) DeleteRecord(request *dnspod.DeleteRecordRequest) (response *dnspod.DeleteRecordResponse, err error) {
|
||||
apiAction := DeleteRecord
|
||||
for times := 1; times <= api.RetryDefault; times++ {
|
||||
client := api.ClientSetService.DnsPodCli(apiAction.Name)
|
||||
if response, err = client.DeleteRecord(request); err != nil {
|
||||
requestJson := JsonWrapper(request)
|
||||
if retry := dealWithError(apiAction, requestJson, err); retry || times == api.RetryDefault {
|
||||
APIErrorRecord(apiAction, requestJson, JsonWrapper(response), err)
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
APIRecord(apiAction, JsonWrapper(request), JsonWrapper(response))
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (api *defaultTencentAPIService) ModifyRecord(request *dnspod.ModifyRecordRequest) (response *dnspod.ModifyRecordResponse, err error) {
|
||||
apiAction := ModifyRecord
|
||||
for times := 1; times <= api.RetryDefault; times++ {
|
||||
client := api.ClientSetService.DnsPodCli(apiAction.Name)
|
||||
if response, err = client.ModifyRecord(request); err != nil {
|
||||
requestJson := JsonWrapper(request)
|
||||
if retry := dealWithError(apiAction, requestJson, err); retry || times == api.RetryDefault {
|
||||
APIErrorRecord(apiAction, requestJson, JsonWrapper(response), err)
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
APIRecord(apiAction, JsonWrapper(request), JsonWrapper(response))
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////
|
||||
// API Error Report
|
||||
// //////////////////////////////////////////////////////////////
|
||||
|
||||
func dealWithError(action Action, request string, err error) bool {
|
||||
log.Errorf("dealWithError %s/%s request: %s, error: %s.", action.Service, action.Name, request, err.Error())
|
||||
sdkError := &tclouderrors.TencentCloudSDKError{}
|
||||
if errors.As(err, &sdkError) {
|
||||
switch sdkError.Code {
|
||||
case "RequestLimitExceeded":
|
||||
return true
|
||||
case "InternalError", "ClientError.HttpStatusCodeError":
|
||||
return false
|
||||
case "ClientError.NetworkError":
|
||||
return false
|
||||
case "AuthFailure.UnauthorizedOperation", "UnauthorizedOperation.CamNoAuth":
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return errors.As(err, new(net.Error))
|
||||
}
|
||||
|
||||
func APIErrorRecord(apiAction Action, request string, response string, err error) {
|
||||
log.Infof("APIError API: %s/%s Request: %s, Response: %s, Error: %s", apiAction.Service, apiAction.Name, request, response, err.Error())
|
||||
}
|
||||
|
||||
func APIRecord(apiAction Action, request string, response string) {
|
||||
message := fmt.Sprintf("APIRecord API: %s/%s Request: %s, Response: %s", apiAction.Service, apiAction.Name, request, response)
|
||||
|
||||
if apiAction.ReadOnly {
|
||||
// log.Info(message)
|
||||
} else {
|
||||
log.Info(message)
|
||||
}
|
||||
}
|
||||
|
||||
func JsonWrapper(obj interface{}) string {
|
||||
if jsonStr, jsonErr := json.Marshal(obj); jsonErr == nil {
|
||||
return string(jsonStr)
|
||||
}
|
||||
return "json_format_error"
|
||||
}
|
@ -1,281 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tencentcloud
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
|
||||
dnspod "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod/v20210323"
|
||||
|
||||
"sigs.k8s.io/external-dns/endpoint"
|
||||
"sigs.k8s.io/external-dns/plan"
|
||||
"sigs.k8s.io/external-dns/provider"
|
||||
)
|
||||
|
||||
// DnsPod For Public Dns
|
||||
|
||||
func (p *TencentCloudProvider) dnsRecords() ([]*endpoint.Endpoint, error) {
|
||||
recordsList, err := p.recordsForDNS()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
endpoints := make([]*endpoint.Endpoint, 0)
|
||||
recordMap := groupDomainRecordList(recordsList)
|
||||
for _, recordList := range recordMap {
|
||||
name := getDnsDomain(*recordList.RecordList[0].Name, *recordList.Domain.Name)
|
||||
recordType := *recordList.RecordList[0].Type
|
||||
ttl := *recordList.RecordList[0].TTL
|
||||
var targets []string
|
||||
for _, record := range recordList.RecordList {
|
||||
targets = append(targets, *record.Value)
|
||||
}
|
||||
endpoints = append(endpoints, endpoint.NewEndpointWithTTL(name, recordType, endpoint.TTL(ttl), targets...))
|
||||
}
|
||||
return endpoints, nil
|
||||
}
|
||||
|
||||
func (p *TencentCloudProvider) recordsForDNS() (map[uint64]*RecordListGroup, error) {
|
||||
domainList, err := p.getDomainList()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
recordListGroup := make(map[uint64]*RecordListGroup, 0)
|
||||
for _, domain := range domainList {
|
||||
records, err := p.getDomainRecordList(*domain.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, record := range records {
|
||||
if *record.Type == "TXT" && strings.HasPrefix(*record.Value, "heritage=") {
|
||||
record.Value = common.StringPtr(fmt.Sprintf(`"%s"`, *record.Value))
|
||||
}
|
||||
}
|
||||
recordListGroup[*domain.DomainId] = &RecordListGroup{
|
||||
Domain: domain,
|
||||
RecordList: records,
|
||||
}
|
||||
}
|
||||
return recordListGroup, nil
|
||||
}
|
||||
|
||||
func (p *TencentCloudProvider) getDomainList() ([]*dnspod.DomainListItem, error) {
|
||||
request := dnspod.NewDescribeDomainListRequest()
|
||||
request.Offset = common.Int64Ptr(0)
|
||||
request.Limit = common.Int64Ptr(3000)
|
||||
|
||||
domainList := make([]*dnspod.DomainListItem, 0)
|
||||
totalCount := int64(100)
|
||||
for *request.Offset < totalCount {
|
||||
response, err := p.apiService.DescribeDomainList(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(response.Response.DomainList) > 0 {
|
||||
if !p.domainFilter.IsConfigured() {
|
||||
domainList = append(domainList, response.Response.DomainList...)
|
||||
} else {
|
||||
for _, domain := range response.Response.DomainList {
|
||||
if p.domainFilter.Match(*domain.Name) {
|
||||
domainList = append(domainList, domain)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
totalCount = int64(*response.Response.DomainCountInfo.AllTotal)
|
||||
request.Offset = common.Int64Ptr(*request.Offset + int64(len(response.Response.DomainList)))
|
||||
}
|
||||
return domainList, nil
|
||||
}
|
||||
|
||||
func (p *TencentCloudProvider) getDomainRecordList(domain string) ([]*dnspod.RecordListItem, error) {
|
||||
request := dnspod.NewDescribeRecordListRequest()
|
||||
request.Domain = common.StringPtr(domain)
|
||||
request.Offset = common.Uint64Ptr(0)
|
||||
request.Limit = common.Uint64Ptr(3000)
|
||||
|
||||
domainList := make([]*dnspod.RecordListItem, 0)
|
||||
totalCount := uint64(100)
|
||||
for *request.Offset < totalCount {
|
||||
response, err := p.apiService.DescribeRecordList(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(response.Response.RecordList) > 0 {
|
||||
for _, record := range response.Response.RecordList {
|
||||
if *record.Name == "@" && *record.Type == "NS" { // Special Record, Skip it.
|
||||
continue
|
||||
}
|
||||
domainList = append(domainList, record)
|
||||
}
|
||||
}
|
||||
totalCount = *response.Response.RecordCountInfo.TotalCount
|
||||
request.Offset = common.Uint64Ptr(*request.Offset + uint64(len(response.Response.RecordList)))
|
||||
}
|
||||
return domainList, nil
|
||||
}
|
||||
|
||||
type RecordListGroup struct {
|
||||
Domain *dnspod.DomainListItem
|
||||
RecordList []*dnspod.RecordListItem
|
||||
}
|
||||
|
||||
func (p *TencentCloudProvider) applyChangesForDNS(changes *plan.Changes) error {
|
||||
recordsGroupMap, err := p.recordsForDNS()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
zoneNameIDMapper := provider.ZoneIDName{}
|
||||
for _, recordsGroup := range recordsGroupMap {
|
||||
if recordsGroup.Domain.DomainId != nil {
|
||||
zoneNameIDMapper.Add(strconv.FormatUint(*recordsGroup.Domain.DomainId, 10), *recordsGroup.Domain.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// Apply Change Delete
|
||||
deleteEndpoints := make(map[string][]uint64)
|
||||
for _, change := range [][]*endpoint.Endpoint{changes.Delete, changes.UpdateOld} {
|
||||
for _, deleteChange := range change {
|
||||
if zoneId, _ := zoneNameIDMapper.FindZone(deleteChange.DNSName); zoneId != "" {
|
||||
zoneIdString, _ := strconv.ParseUint(zoneId, 10, 64)
|
||||
recordListGroup := recordsGroupMap[zoneIdString]
|
||||
for _, domainRecord := range recordListGroup.RecordList {
|
||||
subDomain := getSubDomain(*recordListGroup.Domain.Name, deleteChange)
|
||||
if *domainRecord.Name == subDomain && *domainRecord.Type == deleteChange.RecordType {
|
||||
for _, target := range deleteChange.Targets {
|
||||
if *domainRecord.Value == target {
|
||||
if _, exist := deleteEndpoints[*recordListGroup.Domain.Name]; !exist {
|
||||
deleteEndpoints[*recordListGroup.Domain.Name] = make([]uint64, 0)
|
||||
}
|
||||
deleteEndpoints[*recordListGroup.Domain.Name] = append(deleteEndpoints[*recordListGroup.Domain.Name], *domainRecord.RecordId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := p.deleteRecords(deleteEndpoints); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Apply Change Create
|
||||
createEndpoints := make(map[string][]*endpoint.Endpoint)
|
||||
for zoneId := range zoneNameIDMapper {
|
||||
createEndpoints[zoneId] = make([]*endpoint.Endpoint, 0)
|
||||
}
|
||||
for _, change := range [][]*endpoint.Endpoint{changes.Create, changes.UpdateNew} {
|
||||
for _, createChange := range change {
|
||||
if zoneId, _ := zoneNameIDMapper.FindZone(createChange.DNSName); zoneId != "" {
|
||||
createEndpoints[zoneId] = append(createEndpoints[zoneId], createChange)
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := p.createRecord(recordsGroupMap, createEndpoints); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TencentCloudProvider) createRecord(zoneMap map[uint64]*RecordListGroup, endpointsMap map[string][]*endpoint.Endpoint) error {
|
||||
for zoneId, endpoints := range endpointsMap {
|
||||
zoneIdString, _ := strconv.ParseUint(zoneId, 10, 64)
|
||||
domain := zoneMap[zoneIdString]
|
||||
for _, endpoint := range endpoints {
|
||||
for _, target := range endpoint.Targets {
|
||||
if endpoint.RecordType == "TXT" && strings.HasPrefix(target, `"heritage=`) {
|
||||
target = strings.Trim(target, `"`)
|
||||
}
|
||||
if err := p.createRecords(domain.Domain, endpoint, target); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TencentCloudProvider) createRecords(domain *dnspod.DomainListItem, endpoint *endpoint.Endpoint, target string) error {
|
||||
request := dnspod.NewCreateRecordRequest()
|
||||
|
||||
request.Domain = common.StringPtr(*domain.Name)
|
||||
request.RecordType = common.StringPtr(endpoint.RecordType)
|
||||
request.Value = common.StringPtr(target)
|
||||
request.SubDomain = common.StringPtr(getSubDomain(*domain.Name, endpoint))
|
||||
if endpoint.RecordTTL.IsConfigured() {
|
||||
request.TTL = common.Uint64Ptr(uint64(endpoint.RecordTTL))
|
||||
}
|
||||
request.RecordLine = common.StringPtr("默认")
|
||||
|
||||
if _, err := p.apiService.CreateRecord(request); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TencentCloudProvider) deleteRecords(RecordIdsMap map[string][]uint64) error {
|
||||
for domain, recordIds := range RecordIdsMap {
|
||||
if len(recordIds) == 0 {
|
||||
continue
|
||||
}
|
||||
if err := p.deleteRecord(domain, recordIds); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TencentCloudProvider) deleteRecord(domain string, recordIds []uint64) error {
|
||||
request := dnspod.NewDeleteRecordRequest()
|
||||
request.Domain = common.StringPtr(domain)
|
||||
|
||||
for _, recordId := range recordIds {
|
||||
request.RecordId = common.Uint64Ptr(recordId)
|
||||
if _, err := p.apiService.DeleteRecord(request); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func groupDomainRecordList(recordListGroup map[uint64]*RecordListGroup) (endpointMap map[string]*RecordListGroup) {
|
||||
endpointMap = make(map[string]*RecordListGroup)
|
||||
|
||||
for _, recordGroup := range recordListGroup {
|
||||
for _, record := range recordGroup.RecordList {
|
||||
key := fmt.Sprintf("%s:%s.%s", *record.Type, *record.Name, *recordGroup.Domain.Name)
|
||||
if *record.Name == TencentCloudEmptyPrefix {
|
||||
key = fmt.Sprintf("%s:%s", *record.Type, *recordGroup.Domain.Name)
|
||||
}
|
||||
if _, exist := endpointMap[key]; !exist {
|
||||
endpointMap[key] = &RecordListGroup{
|
||||
Domain: recordGroup.Domain,
|
||||
RecordList: make([]*dnspod.RecordListItem, 0),
|
||||
}
|
||||
}
|
||||
endpointMap[key].RecordList = append(endpointMap[key].RecordList, record)
|
||||
}
|
||||
}
|
||||
|
||||
return endpointMap
|
||||
}
|
@ -1,319 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tencentcloud
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
|
||||
privatedns "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns/v20201028"
|
||||
|
||||
"sigs.k8s.io/external-dns/endpoint"
|
||||
"sigs.k8s.io/external-dns/plan"
|
||||
"sigs.k8s.io/external-dns/provider"
|
||||
)
|
||||
|
||||
// PrivateZone For Internal Dns
|
||||
|
||||
func (p *TencentCloudProvider) privateZoneRecords() ([]*endpoint.Endpoint, error) {
|
||||
privateZones, err := p.recordForPrivateZone()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
endpoints := make([]*endpoint.Endpoint, 0)
|
||||
recordMap := groupPrivateZoneRecords(privateZones)
|
||||
for _, recordList := range recordMap {
|
||||
name := getDnsDomain(*recordList.RecordList[0].SubDomain, *recordList.Zone.Domain)
|
||||
recordType := *recordList.RecordList[0].RecordType
|
||||
ttl := *recordList.RecordList[0].TTL
|
||||
var targets []string
|
||||
for _, record := range recordList.RecordList {
|
||||
targets = append(targets, *record.RecordValue)
|
||||
}
|
||||
endpoints = append(endpoints, endpoint.NewEndpointWithTTL(name, recordType, endpoint.TTL(ttl), targets...))
|
||||
}
|
||||
return endpoints, nil
|
||||
}
|
||||
|
||||
func (p *TencentCloudProvider) recordForPrivateZone() (map[string]*PrivateZoneRecordListGroup, error) {
|
||||
privateZones, err := p.getPrivateZones()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
recordListGroup := make(map[string]*PrivateZoneRecordListGroup, 0)
|
||||
for _, zone := range privateZones {
|
||||
records, err := p.getPrivateZoneRecords(*zone.ZoneId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, record := range records {
|
||||
if *record.RecordType == "TXT" && strings.HasPrefix(*record.RecordValue, "heritage=") {
|
||||
record.RecordValue = common.StringPtr(fmt.Sprintf("\"%s\"", *record.RecordValue))
|
||||
}
|
||||
}
|
||||
recordListGroup[*zone.ZoneId] = &PrivateZoneRecordListGroup{
|
||||
Zone: zone,
|
||||
RecordList: records,
|
||||
}
|
||||
}
|
||||
|
||||
return recordListGroup, nil
|
||||
}
|
||||
|
||||
func (p *TencentCloudProvider) getPrivateZones() ([]*privatedns.PrivateZone, error) {
|
||||
filters := make([]*privatedns.Filter, 1)
|
||||
filters[0] = &privatedns.Filter{
|
||||
Name: common.StringPtr("Vpc"),
|
||||
Values: []*string{
|
||||
common.StringPtr(p.vpcID),
|
||||
},
|
||||
}
|
||||
|
||||
if p.zoneIDFilter.IsConfigured() {
|
||||
zoneIDs := make([]*string, len(p.zoneIDFilter.ZoneIDs))
|
||||
for index, zoneId := range p.zoneIDFilter.ZoneIDs {
|
||||
zoneIDs[index] = common.StringPtr(zoneId)
|
||||
}
|
||||
filters = append(filters, &privatedns.Filter{
|
||||
Name: common.StringPtr("ZoneId"),
|
||||
Values: zoneIDs,
|
||||
})
|
||||
}
|
||||
|
||||
request := privatedns.NewDescribePrivateZoneListRequest()
|
||||
request.Filters = filters
|
||||
request.Offset = common.Int64Ptr(0)
|
||||
request.Limit = common.Int64Ptr(100)
|
||||
|
||||
privateZones := make([]*privatedns.PrivateZone, 0)
|
||||
totalCount := int64(100)
|
||||
for *request.Offset < totalCount {
|
||||
response, err := p.apiService.DescribePrivateZoneList(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(response.Response.PrivateZoneSet) > 0 {
|
||||
privateZones = append(privateZones, response.Response.PrivateZoneSet...)
|
||||
}
|
||||
totalCount = *response.Response.TotalCount
|
||||
request.Offset = common.Int64Ptr(*request.Offset + int64(len(response.Response.PrivateZoneSet)))
|
||||
}
|
||||
|
||||
privateZonesFilter := make([]*privatedns.PrivateZone, 0)
|
||||
for _, privateZone := range privateZones {
|
||||
if !p.domainFilter.Match(*privateZone.Domain) {
|
||||
continue
|
||||
}
|
||||
privateZonesFilter = append(privateZonesFilter, privateZone)
|
||||
}
|
||||
return privateZonesFilter, nil
|
||||
}
|
||||
|
||||
func (p *TencentCloudProvider) getPrivateZoneRecords(zoneId string) ([]*privatedns.PrivateZoneRecord, error) {
|
||||
request := privatedns.NewDescribePrivateZoneRecordListRequest()
|
||||
request.ZoneId = common.StringPtr(zoneId)
|
||||
request.Offset = common.Int64Ptr(0)
|
||||
request.Limit = common.Int64Ptr(100)
|
||||
|
||||
privateZoneRecords := make([]*privatedns.PrivateZoneRecord, 0)
|
||||
totalCount := int64(100)
|
||||
for *request.Offset < totalCount {
|
||||
response, err := p.apiService.DescribePrivateZoneRecordList(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(response.Response.RecordSet) > 0 {
|
||||
privateZoneRecords = append(privateZoneRecords, response.Response.RecordSet...)
|
||||
}
|
||||
totalCount = *response.Response.TotalCount
|
||||
request.Offset = common.Int64Ptr(*request.Offset + int64(len(response.Response.RecordSet)))
|
||||
}
|
||||
return privateZoneRecords, nil
|
||||
}
|
||||
|
||||
type PrivateZoneRecordListGroup struct {
|
||||
Zone *privatedns.PrivateZone
|
||||
RecordList []*privatedns.PrivateZoneRecord
|
||||
}
|
||||
|
||||
// Returns nil if the operation was successful or an error if the operation failed.
|
||||
func (p *TencentCloudProvider) applyChangesForPrivateZone(changes *plan.Changes) error {
|
||||
zoneGroups, err := p.recordForPrivateZone()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// In PrivateDns Service. A Zone has at least one record. The last rule cannot be deleted.
|
||||
for _, zoneGroup := range zoneGroups {
|
||||
if !containsBaseRecord(zoneGroup.RecordList) {
|
||||
err := p.createPrivateZoneRecord(zoneGroup.Zone, &endpoint.Endpoint{
|
||||
DNSName: *zoneGroup.Zone.Domain,
|
||||
RecordType: "TXT",
|
||||
}, "tencent_provider_record")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
zoneNameIDMapper := provider.ZoneIDName{}
|
||||
for _, zoneGroup := range zoneGroups {
|
||||
if zoneGroup.Zone.ZoneId != nil {
|
||||
zoneNameIDMapper.Add(*zoneGroup.Zone.ZoneId, *zoneGroup.Zone.Domain)
|
||||
}
|
||||
}
|
||||
|
||||
// Apply Change Delete
|
||||
deleteEndpoints := make(map[string][]string)
|
||||
for _, change := range [][]*endpoint.Endpoint{changes.Delete, changes.UpdateOld} {
|
||||
for _, deleteChange := range change {
|
||||
if zoneId, _ := zoneNameIDMapper.FindZone(deleteChange.DNSName); zoneId != "" {
|
||||
zoneGroup := zoneGroups[zoneId]
|
||||
for _, zoneRecord := range zoneGroup.RecordList {
|
||||
subDomain := getSubDomain(*zoneGroup.Zone.Domain, deleteChange)
|
||||
if *zoneRecord.SubDomain == subDomain && *zoneRecord.RecordType == deleteChange.RecordType {
|
||||
for _, target := range deleteChange.Targets {
|
||||
if *zoneRecord.RecordValue == target {
|
||||
if _, exist := deleteEndpoints[zoneId]; !exist {
|
||||
deleteEndpoints[zoneId] = make([]string, 0)
|
||||
}
|
||||
deleteEndpoints[zoneId] = append(deleteEndpoints[zoneId], *zoneRecord.RecordId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := p.deletePrivateZoneRecords(deleteEndpoints); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Apply Change Create
|
||||
createEndpoints := make(map[string][]*endpoint.Endpoint)
|
||||
for _, change := range [][]*endpoint.Endpoint{changes.Create, changes.UpdateNew} {
|
||||
for _, createChange := range change {
|
||||
if zoneId, _ := zoneNameIDMapper.FindZone(createChange.DNSName); zoneId != "" {
|
||||
if _, exist := createEndpoints[zoneId]; !exist {
|
||||
createEndpoints[zoneId] = make([]*endpoint.Endpoint, 0)
|
||||
}
|
||||
createEndpoints[zoneId] = append(createEndpoints[zoneId], createChange)
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := p.createPrivateZoneRecords(zoneGroups, createEndpoints); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func containsBaseRecord(records []*privatedns.PrivateZoneRecord) bool {
|
||||
for _, record := range records {
|
||||
if *record.SubDomain == TencentCloudEmptyPrefix && *record.RecordType == "TXT" && *record.RecordValue == "tencent_provider_record" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *TencentCloudProvider) createPrivateZoneRecords(zoneGroups map[string]*PrivateZoneRecordListGroup, endpointsMap map[string][]*endpoint.Endpoint) error {
|
||||
for zoneId, endpoints := range endpointsMap {
|
||||
zoneGroup := zoneGroups[zoneId]
|
||||
for _, endpoint := range endpoints {
|
||||
for _, target := range endpoint.Targets {
|
||||
if endpoint.RecordType == "TXT" && strings.HasPrefix(target, "\"heritage=") {
|
||||
target = strings.Trim(target, "\"")
|
||||
}
|
||||
if err := p.createPrivateZoneRecord(zoneGroup.Zone, endpoint, target); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TencentCloudProvider) deletePrivateZoneRecords(zoneRecordIdsMap map[string][]string) error {
|
||||
for zoneId, zoneRecordIds := range zoneRecordIdsMap {
|
||||
if len(zoneRecordIds) == 0 {
|
||||
continue
|
||||
}
|
||||
if err := p.deletePrivateZoneRecord(zoneId, zoneRecordIds); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TencentCloudProvider) createPrivateZoneRecord(zone *privatedns.PrivateZone, endpoint *endpoint.Endpoint, target string) error {
|
||||
request := privatedns.NewCreatePrivateZoneRecordRequest()
|
||||
request.ZoneId = common.StringPtr(*zone.ZoneId)
|
||||
request.RecordType = common.StringPtr(endpoint.RecordType)
|
||||
request.RecordValue = common.StringPtr(target)
|
||||
request.SubDomain = common.StringPtr(getSubDomain(*zone.Domain, endpoint))
|
||||
if endpoint.RecordTTL.IsConfigured() {
|
||||
request.TTL = common.Int64Ptr(int64(endpoint.RecordTTL))
|
||||
}
|
||||
|
||||
if _, err := p.apiService.CreatePrivateZoneRecord(request); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TencentCloudProvider) deletePrivateZoneRecord(zoneId string, zoneRecordIds []string) error {
|
||||
recordIds := make([]*string, len(zoneRecordIds))
|
||||
for index, recordId := range zoneRecordIds {
|
||||
recordIds[index] = common.StringPtr(recordId)
|
||||
}
|
||||
|
||||
request := privatedns.NewDeletePrivateZoneRecordRequest()
|
||||
request.ZoneId = common.StringPtr(zoneId)
|
||||
request.RecordIdSet = recordIds
|
||||
|
||||
if _, err := p.apiService.DeletePrivateZoneRecord(request); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func groupPrivateZoneRecords(zoneRecords map[string]*PrivateZoneRecordListGroup) (endpointMap map[string]*PrivateZoneRecordListGroup) {
|
||||
endpointMap = make(map[string]*PrivateZoneRecordListGroup)
|
||||
|
||||
for _, recordGroup := range zoneRecords {
|
||||
for _, record := range recordGroup.RecordList {
|
||||
key := fmt.Sprintf("%s:%s.%s", *record.RecordType, *record.SubDomain, *recordGroup.Zone.Domain)
|
||||
if *record.SubDomain == TencentCloudEmptyPrefix {
|
||||
key = fmt.Sprintf("%s:%s", *record.RecordType, *recordGroup.Zone.Domain)
|
||||
}
|
||||
if _, exist := endpointMap[key]; !exist {
|
||||
endpointMap[key] = &PrivateZoneRecordListGroup{
|
||||
Zone: recordGroup.Zone,
|
||||
RecordList: make([]*privatedns.PrivateZoneRecord, 0),
|
||||
}
|
||||
}
|
||||
endpointMap[key].RecordList = append(endpointMap[key].RecordList, record)
|
||||
}
|
||||
}
|
||||
|
||||
return endpointMap
|
||||
}
|
@ -1,121 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tencentcloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"sigs.k8s.io/external-dns/endpoint"
|
||||
"sigs.k8s.io/external-dns/plan"
|
||||
"sigs.k8s.io/external-dns/provider"
|
||||
"sigs.k8s.io/external-dns/provider/tencentcloud/cloudapi"
|
||||
)
|
||||
|
||||
const (
|
||||
TencentCloudEmptyPrefix = "@"
|
||||
DefaultAPIRate = 9
|
||||
)
|
||||
|
||||
func NewTencentCloudProvider(domainFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, configFile string, zoneType string, dryRun bool) (*TencentCloudProvider, error) {
|
||||
cfg := tencentCloudConfig{}
|
||||
if configFile != "" {
|
||||
contents, err := os.ReadFile(configFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read Tencent Cloud config file '%s': %w", configFile, err)
|
||||
}
|
||||
err = json.Unmarshal(contents, &cfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse Tencent Cloud config file '%s': %w", configFile, err)
|
||||
}
|
||||
}
|
||||
|
||||
var apiService cloudapi.TencentAPIService = cloudapi.NewTencentAPIService(cfg.RegionId, DefaultAPIRate, cfg.SecretId, cfg.SecretKey, cfg.InternetEndpoint)
|
||||
if dryRun {
|
||||
apiService = cloudapi.NewReadOnlyAPIService(cfg.RegionId, DefaultAPIRate, cfg.SecretId, cfg.SecretKey, cfg.InternetEndpoint)
|
||||
}
|
||||
|
||||
tencentCloudProvider := &TencentCloudProvider{
|
||||
domainFilter: domainFilter,
|
||||
zoneIDFilter: zoneIDFilter,
|
||||
apiService: apiService,
|
||||
vpcID: cfg.VPCId,
|
||||
privateZone: zoneType == "private",
|
||||
}
|
||||
|
||||
return tencentCloudProvider, nil
|
||||
}
|
||||
|
||||
type TencentCloudProvider struct {
|
||||
provider.BaseProvider
|
||||
apiService cloudapi.TencentAPIService
|
||||
domainFilter endpoint.DomainFilter
|
||||
zoneIDFilter provider.ZoneIDFilter // Private Zone only
|
||||
vpcID string // Private Zone only
|
||||
privateZone bool
|
||||
}
|
||||
|
||||
type tencentCloudConfig struct {
|
||||
RegionId string `json:"regionId" yaml:"regionId"`
|
||||
SecretId string `json:"secretId" yaml:"secretId"`
|
||||
SecretKey string `json:"secretKey" yaml:"secretKey"`
|
||||
VPCId string `json:"vpcId" yaml:"vpcId"`
|
||||
InternetEndpoint bool `json:"internetEndpoint" yaml:"internetEndpoint"`
|
||||
}
|
||||
|
||||
func (p *TencentCloudProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error) {
|
||||
if p.privateZone {
|
||||
return p.privateZoneRecords()
|
||||
}
|
||||
return p.dnsRecords()
|
||||
}
|
||||
|
||||
func (p *TencentCloudProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error {
|
||||
if !changes.HasChanges() {
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Infof("apply changes. %s", cloudapi.JsonWrapper(changes))
|
||||
|
||||
if p.privateZone {
|
||||
return p.applyChangesForPrivateZone(changes)
|
||||
}
|
||||
return p.applyChangesForDNS(changes)
|
||||
}
|
||||
|
||||
func getSubDomain(domain string, endpoint *endpoint.Endpoint) string {
|
||||
name := endpoint.DNSName
|
||||
name = name[:len(name)-len(domain)]
|
||||
name = strings.TrimSuffix(name, ".")
|
||||
|
||||
if name == "" {
|
||||
return TencentCloudEmptyPrefix
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func getDnsDomain(subDomain string, domain string) string {
|
||||
if subDomain == TencentCloudEmptyPrefix {
|
||||
return domain
|
||||
}
|
||||
return subDomain + "." + domain
|
||||
}
|
@ -1,403 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tencentcloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
|
||||
dnspod "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod/v20210323"
|
||||
"sigs.k8s.io/external-dns/endpoint"
|
||||
"sigs.k8s.io/external-dns/plan"
|
||||
"sigs.k8s.io/external-dns/provider"
|
||||
"sigs.k8s.io/external-dns/provider/tencentcloud/cloudapi"
|
||||
|
||||
privatedns "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/privatedns/v20201028"
|
||||
)
|
||||
|
||||
func NewMockTencentCloudProvider(domainFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, zoneType string) *TencentCloudProvider {
|
||||
cfg := tencentCloudConfig{
|
||||
RegionId: "ap-shanghai",
|
||||
VPCId: "vpc-abcdefg",
|
||||
}
|
||||
|
||||
zoneId1 := common.StringPtr(cloudapi.RandStringRunes(8))
|
||||
|
||||
privateZones := []*privatedns.PrivateZone{
|
||||
{
|
||||
ZoneId: zoneId1,
|
||||
Domain: common.StringPtr("external-dns-test.com"),
|
||||
VpcSet: []*privatedns.VpcInfo{
|
||||
{
|
||||
UniqVpcId: common.StringPtr("vpc-abcdefg"),
|
||||
Region: common.StringPtr("ap-shanghai"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
zoneRecordId1 := common.StringPtr(cloudapi.RandStringRunes(8))
|
||||
zoneRecordId2 := common.StringPtr(cloudapi.RandStringRunes(8))
|
||||
privateZoneRecords := map[string][]*privatedns.PrivateZoneRecord{
|
||||
*zoneId1: {
|
||||
{
|
||||
ZoneId: zoneId1,
|
||||
RecordId: zoneRecordId1,
|
||||
SubDomain: common.StringPtr("nginx"),
|
||||
RecordType: common.StringPtr("TXT"),
|
||||
RecordValue: common.StringPtr("heritage=external-dns,external-dns/owner=default"),
|
||||
TTL: common.Int64Ptr(300),
|
||||
},
|
||||
{
|
||||
ZoneId: zoneId1,
|
||||
RecordId: zoneRecordId2,
|
||||
SubDomain: common.StringPtr("nginx"),
|
||||
RecordType: common.StringPtr("A"),
|
||||
RecordValue: common.StringPtr("10.10.10.10"),
|
||||
TTL: common.Int64Ptr(300),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
dnsDomainId1 := common.Uint64Ptr(cloudapi.RandUint64())
|
||||
dnsPodDomains := []*dnspod.DomainListItem{
|
||||
{
|
||||
DomainId: dnsDomainId1,
|
||||
Name: common.StringPtr("external-dns-test.com"),
|
||||
},
|
||||
}
|
||||
dnsDomainRecordId1 := common.Uint64Ptr(cloudapi.RandUint64())
|
||||
dnsDomainRecordId2 := common.Uint64Ptr(cloudapi.RandUint64())
|
||||
dnspodRecords := map[string][]*dnspod.RecordListItem{
|
||||
"external-dns-test.com": {
|
||||
{
|
||||
RecordId: dnsDomainRecordId1,
|
||||
Value: common.StringPtr("heritage=external-dns,external-dns/owner=default"),
|
||||
Name: common.StringPtr("nginx"),
|
||||
Type: common.StringPtr("TXT"),
|
||||
TTL: common.Uint64Ptr(300),
|
||||
},
|
||||
{
|
||||
RecordId: dnsDomainRecordId2,
|
||||
Name: common.StringPtr("nginx"),
|
||||
Type: common.StringPtr("A"),
|
||||
Value: common.StringPtr("10.10.10.10"),
|
||||
TTL: common.Uint64Ptr(300),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var apiService cloudapi.TencentAPIService = cloudapi.NewMockService(privateZones, privateZoneRecords, dnsPodDomains, dnspodRecords)
|
||||
|
||||
tencentCloudProvider := &TencentCloudProvider{
|
||||
domainFilter: domainFilter,
|
||||
zoneIDFilter: zoneIDFilter,
|
||||
apiService: apiService,
|
||||
vpcID: cfg.VPCId,
|
||||
privateZone: zoneType == "private",
|
||||
}
|
||||
|
||||
return tencentCloudProvider
|
||||
}
|
||||
|
||||
func TestTencentPrivateProvider_Records(t *testing.T) {
|
||||
p := NewMockTencentCloudProvider(endpoint.NewDomainFilter([]string{"external-dns-test.com"}), provider.NewZoneIDFilter([]string{}), "private")
|
||||
endpoints, err := p.Records(context.Background())
|
||||
if err != nil {
|
||||
t.Errorf("Failed to get records: %v", err)
|
||||
} else {
|
||||
if len(endpoints) != 2 {
|
||||
t.Errorf("Incorrect number of records: %d", len(endpoints))
|
||||
}
|
||||
for _, endpoint := range endpoints {
|
||||
t.Logf("Endpoint for %+v", *endpoint)
|
||||
}
|
||||
}
|
||||
|
||||
// Test for Create、UpdateOld、UpdateNew、Delete
|
||||
// The base record will be created.
|
||||
changes := &plan.Changes{
|
||||
Create: []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "redis.external-dns-test.com",
|
||||
RecordType: "A",
|
||||
RecordTTL: 300,
|
||||
Targets: endpoint.NewTargets("4.3.2.1"),
|
||||
},
|
||||
},
|
||||
UpdateOld: []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "nginx.external-dns-test.com",
|
||||
RecordType: "A",
|
||||
RecordTTL: 300,
|
||||
Targets: endpoint.NewTargets("10.10.10.10"),
|
||||
},
|
||||
},
|
||||
UpdateNew: []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "tencent.external-dns-test.com",
|
||||
RecordType: "A",
|
||||
RecordTTL: 600,
|
||||
Targets: endpoint.NewTargets("1.2.3.4", "5.6.7.8"),
|
||||
},
|
||||
},
|
||||
Delete: []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "nginx.external-dns-test.com",
|
||||
RecordType: "TXT",
|
||||
RecordTTL: 300,
|
||||
Targets: endpoint.NewTargets("\"heritage=external-dns,external-dns/owner=default\""),
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := p.ApplyChanges(context.Background(), changes); err != nil {
|
||||
t.Errorf("Failed to get records: %v", err)
|
||||
}
|
||||
endpoints, err = p.Records(context.Background())
|
||||
if err != nil {
|
||||
t.Errorf("Failed to get records: %v", err)
|
||||
} else {
|
||||
if len(endpoints) != 3 {
|
||||
t.Errorf("Incorrect number of records: %d", len(endpoints))
|
||||
}
|
||||
for _, endpoint := range endpoints {
|
||||
t.Logf("Endpoint for %+v", *endpoint)
|
||||
}
|
||||
}
|
||||
|
||||
// Test for Delete one target
|
||||
changes = &plan.Changes{
|
||||
Delete: []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "tencent.external-dns-test.com",
|
||||
RecordType: "A",
|
||||
RecordTTL: 600,
|
||||
Targets: endpoint.NewTargets("5.6.7.8"),
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := p.ApplyChanges(context.Background(), changes); err != nil {
|
||||
t.Errorf("Failed to get records: %v", err)
|
||||
}
|
||||
endpoints, err = p.Records(context.Background())
|
||||
if err != nil {
|
||||
t.Errorf("Failed to get records: %v", err)
|
||||
} else {
|
||||
if len(endpoints) != 3 {
|
||||
t.Errorf("Incorrect number of records: %d", len(endpoints))
|
||||
}
|
||||
for _, endpoint := range endpoints {
|
||||
t.Logf("Endpoint for %+v", *endpoint)
|
||||
}
|
||||
}
|
||||
|
||||
// Test for Delete another target
|
||||
changes = &plan.Changes{
|
||||
Create: []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "redis.external-dns-test.com",
|
||||
RecordType: "A",
|
||||
RecordTTL: 300,
|
||||
Targets: endpoint.NewTargets("5.6.7.8"),
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := p.ApplyChanges(context.Background(), changes); err != nil {
|
||||
t.Errorf("Failed to get records: %v", err)
|
||||
}
|
||||
endpoints, err = p.Records(context.Background())
|
||||
if err != nil {
|
||||
t.Errorf("Failed to get records: %v", err)
|
||||
} else {
|
||||
if len(endpoints) != 3 {
|
||||
t.Errorf("Incorrect number of records: %d", len(endpoints))
|
||||
}
|
||||
for _, endpoint := range endpoints {
|
||||
t.Logf("Endpoint for %+v", *endpoint)
|
||||
}
|
||||
}
|
||||
|
||||
// Test for Delete another target
|
||||
changes = &plan.Changes{
|
||||
Delete: []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "tencent.external-dns-test.com",
|
||||
RecordType: "A",
|
||||
RecordTTL: 600,
|
||||
Targets: endpoint.NewTargets("1.2.3.4"),
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := p.ApplyChanges(context.Background(), changes); err != nil {
|
||||
t.Errorf("Failed to get records: %v", err)
|
||||
}
|
||||
endpoints, err = p.Records(context.Background())
|
||||
if err != nil {
|
||||
t.Errorf("Failed to get records: %v", err)
|
||||
} else {
|
||||
if len(endpoints) != 2 {
|
||||
t.Errorf("Incorrect number of records: %d", len(endpoints))
|
||||
}
|
||||
for _, endpoint := range endpoints {
|
||||
t.Logf("Endpoint for %+v", *endpoint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTencentPublicProvider_Records(t *testing.T) {
|
||||
p := NewMockTencentCloudProvider(endpoint.NewDomainFilter([]string{"external-dns-test.com"}), provider.NewZoneIDFilter([]string{}), "public")
|
||||
endpoints, err := p.Records(context.Background())
|
||||
if err != nil {
|
||||
t.Errorf("Failed to get records: %v", err)
|
||||
} else {
|
||||
if len(endpoints) != 2 {
|
||||
t.Errorf("Incorrect number of records: %d", len(endpoints))
|
||||
}
|
||||
for _, endpoint := range endpoints {
|
||||
t.Logf("Endpoint for %+v", *endpoint)
|
||||
}
|
||||
}
|
||||
|
||||
// Test for Create、UpdateOld、UpdateNew、Delete
|
||||
changes := &plan.Changes{
|
||||
Create: []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "redis.external-dns-test.com",
|
||||
RecordType: "A",
|
||||
RecordTTL: 300,
|
||||
Targets: endpoint.NewTargets("4.3.2.1"),
|
||||
},
|
||||
},
|
||||
UpdateOld: []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "nginx.external-dns-test.com",
|
||||
RecordType: "A",
|
||||
RecordTTL: 300,
|
||||
Targets: endpoint.NewTargets("10.10.10.10"),
|
||||
},
|
||||
},
|
||||
UpdateNew: []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "tencent.external-dns-test.com",
|
||||
RecordType: "A",
|
||||
RecordTTL: 600,
|
||||
Targets: endpoint.NewTargets("1.2.3.4", "5.6.7.8"),
|
||||
},
|
||||
},
|
||||
Delete: []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "nginx.external-dns-test.com",
|
||||
RecordType: "TXT",
|
||||
RecordTTL: 300,
|
||||
Targets: endpoint.NewTargets("\"heritage=external-dns,external-dns/owner=default\""),
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := p.ApplyChanges(context.Background(), changes); err != nil {
|
||||
t.Errorf("Failed to get records: %v", err)
|
||||
}
|
||||
endpoints, err = p.Records(context.Background())
|
||||
if err != nil {
|
||||
t.Errorf("Failed to get records: %v", err)
|
||||
} else {
|
||||
if len(endpoints) != 2 {
|
||||
t.Errorf("Incorrect number of records: %d", len(endpoints))
|
||||
}
|
||||
for _, endpoint := range endpoints {
|
||||
t.Logf("Endpoint for %+v", *endpoint)
|
||||
}
|
||||
}
|
||||
|
||||
// Test for Delete one target
|
||||
changes = &plan.Changes{
|
||||
Delete: []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "tencent.external-dns-test.com",
|
||||
RecordType: "A",
|
||||
RecordTTL: 600,
|
||||
Targets: endpoint.NewTargets("5.6.7.8"),
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := p.ApplyChanges(context.Background(), changes); err != nil {
|
||||
t.Errorf("Failed to get records: %v", err)
|
||||
}
|
||||
endpoints, err = p.Records(context.Background())
|
||||
if err != nil {
|
||||
t.Errorf("Failed to get records: %v", err)
|
||||
} else {
|
||||
if len(endpoints) != 2 {
|
||||
t.Errorf("Incorrect number of records: %d", len(endpoints))
|
||||
}
|
||||
for _, endpoint := range endpoints {
|
||||
t.Logf("Endpoint for %+v", *endpoint)
|
||||
}
|
||||
}
|
||||
|
||||
// Test for Delete another target
|
||||
changes = &plan.Changes{
|
||||
Create: []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "redis.external-dns-test.com",
|
||||
RecordType: "A",
|
||||
RecordTTL: 300,
|
||||
Targets: endpoint.NewTargets("5.6.7.8"),
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := p.ApplyChanges(context.Background(), changes); err != nil {
|
||||
t.Errorf("Failed to get records: %v", err)
|
||||
}
|
||||
endpoints, err = p.Records(context.Background())
|
||||
if err != nil {
|
||||
t.Errorf("Failed to get records: %v", err)
|
||||
} else {
|
||||
if len(endpoints) != 2 {
|
||||
t.Errorf("Incorrect number of records: %d", len(endpoints))
|
||||
}
|
||||
for _, endpoint := range endpoints {
|
||||
t.Logf("Endpoint for %+v", *endpoint)
|
||||
}
|
||||
}
|
||||
|
||||
// Test for Delete another target
|
||||
changes = &plan.Changes{
|
||||
Delete: []*endpoint.Endpoint{
|
||||
{
|
||||
DNSName: "tencent.external-dns-test.com",
|
||||
RecordType: "A",
|
||||
RecordTTL: 600,
|
||||
Targets: endpoint.NewTargets("1.2.3.4"),
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := p.ApplyChanges(context.Background(), changes); err != nil {
|
||||
t.Errorf("Failed to get records: %v", err)
|
||||
}
|
||||
endpoints, err = p.Records(context.Background())
|
||||
if err != nil {
|
||||
t.Errorf("Failed to get records: %v", err)
|
||||
} else {
|
||||
if len(endpoints) != 1 {
|
||||
t.Errorf("Incorrect number of records: %d", len(endpoints))
|
||||
}
|
||||
for _, endpoint := range endpoints {
|
||||
t.Logf("Endpoint for %+v", *endpoint)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,498 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Kubernetes Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package ultradns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
udnssdk "github.com/ultradns/ultradns-sdk-go"
|
||||
|
||||
"sigs.k8s.io/external-dns/endpoint"
|
||||
"sigs.k8s.io/external-dns/plan"
|
||||
"sigs.k8s.io/external-dns/provider"
|
||||
)
|
||||
|
||||
const (
|
||||
ultradnsCreate = "CREATE"
|
||||
ultradnsDelete = "DELETE"
|
||||
ultradnsUpdate = "UPDATE"
|
||||
sbPoolPriority = 1
|
||||
sbPoolOrder = "ROUND_ROBIN"
|
||||
rdPoolOrder = "ROUND_ROBIN"
|
||||
)
|
||||
|
||||
var (
|
||||
sbPoolActOnProbes = true
|
||||
ultradnsPoolType = "rdpool"
|
||||
accountName string
|
||||
sbPoolRunProbes = true
|
||||
// Setting custom headers for ultradns api calls
|
||||
customHeader = []udnssdk.CustomHeader{
|
||||
{
|
||||
Key: "UltraClient",
|
||||
Value: "kube-client",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// UltraDNSProvider struct
|
||||
type UltraDNSProvider struct {
|
||||
provider.BaseProvider
|
||||
client udnssdk.Client
|
||||
domainFilter endpoint.DomainFilter
|
||||
dryRun bool
|
||||
}
|
||||
|
||||
// UltraDNSChanges struct
|
||||
type UltraDNSChanges struct {
|
||||
Action string
|
||||
ResourceRecordSetUltraDNS udnssdk.RRSet
|
||||
}
|
||||
|
||||
// NewUltraDNSProvider initializes a new UltraDNS DNS based provider
|
||||
func NewUltraDNSProvider(domainFilter endpoint.DomainFilter, dryRun bool) (*UltraDNSProvider, error) {
|
||||
username, ok := os.LookupEnv("ULTRADNS_USERNAME")
|
||||
udnssdk.SetCustomHeader = customHeader
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no username found")
|
||||
}
|
||||
|
||||
base64password, ok := os.LookupEnv("ULTRADNS_PASSWORD")
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no password found")
|
||||
}
|
||||
|
||||
// Base64 Standard Decoding
|
||||
password, err := base64.StdEncoding.DecodeString(base64password)
|
||||
if err != nil {
|
||||
fmt.Printf("Error decoding string: %s ", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
baseURL, ok := os.LookupEnv("ULTRADNS_BASEURL")
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no baseurl found")
|
||||
}
|
||||
accountName, ok = os.LookupEnv("ULTRADNS_ACCOUNTNAME")
|
||||
if !ok {
|
||||
accountName = ""
|
||||
}
|
||||
|
||||
probeValue, ok := os.LookupEnv("ULTRADNS_ENABLE_PROBING")
|
||||
if ok {
|
||||
if (probeValue != "true") && (probeValue != "false") {
|
||||
return nil, fmt.Errorf("please set proper probe value, the values can be either true or false")
|
||||
}
|
||||
sbPoolRunProbes, _ = strconv.ParseBool(probeValue)
|
||||
}
|
||||
|
||||
actOnProbeValue, ok := os.LookupEnv("ULTRADNS_ENABLE_ACTONPROBE")
|
||||
if ok {
|
||||
if (actOnProbeValue != "true") && (actOnProbeValue != "false") {
|
||||
return nil, fmt.Errorf("please set proper act on probe value, the values can be either true or false")
|
||||
}
|
||||
sbPoolActOnProbes, _ = strconv.ParseBool(actOnProbeValue)
|
||||
}
|
||||
|
||||
poolValue, ok := os.LookupEnv("ULTRADNS_POOL_TYPE")
|
||||
if ok {
|
||||
if (poolValue != "sbpool") && (poolValue != "rdpool") {
|
||||
return nil, fmt.Errorf(" please set proper ULTRADNS_POOL_TYPE, supported types are sbpool or rdpool")
|
||||
}
|
||||
ultradnsPoolType = poolValue
|
||||
}
|
||||
|
||||
client, err := udnssdk.NewClient(username, string(password), baseURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("connection cannot be established")
|
||||
}
|
||||
|
||||
return &UltraDNSProvider{
|
||||
client: *client,
|
||||
domainFilter: domainFilter,
|
||||
dryRun: dryRun,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Zones returns list of hosted zones
|
||||
func (p *UltraDNSProvider) Zones(ctx context.Context) ([]udnssdk.Zone, error) {
|
||||
zoneKey := &udnssdk.ZoneKey{}
|
||||
var err error
|
||||
|
||||
if p.domainFilter.IsConfigured() {
|
||||
zonesAppender := []udnssdk.Zone{}
|
||||
for _, zone := range p.domainFilter.Filters {
|
||||
zoneKey.Zone = zone
|
||||
zoneKey.AccountName = accountName
|
||||
zones, err := p.fetchZones(ctx, zoneKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
zonesAppender = append(zonesAppender, zones...)
|
||||
}
|
||||
return zonesAppender, nil
|
||||
}
|
||||
zoneKey.AccountName = accountName
|
||||
zones, err := p.fetchZones(ctx, zoneKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return zones, nil
|
||||
}
|
||||
|
||||
func (p *UltraDNSProvider) Records(ctx context.Context) ([]*endpoint.Endpoint, error) {
|
||||
var endpoints []*endpoint.Endpoint
|
||||
|
||||
zones, err := p.Zones(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, zone := range zones {
|
||||
log.Infof("zones : %v", zone)
|
||||
var rrsetType string
|
||||
var ownerName string
|
||||
rrsetKey := udnssdk.RRSetKey{
|
||||
Zone: zone.Properties.Name,
|
||||
Type: rrsetType,
|
||||
Name: ownerName,
|
||||
}
|
||||
|
||||
if zone.Properties.ResourceRecordCount != 0 {
|
||||
records, err := p.fetchRecords(ctx, rrsetKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, r := range records {
|
||||
recordTypeArray := strings.Fields(r.RRType)
|
||||
if provider.SupportedRecordType(recordTypeArray[0]) {
|
||||
log.Infof("owner name %s", r.OwnerName)
|
||||
name := r.OwnerName
|
||||
|
||||
// root name is identified by the empty string and should be
|
||||
// translated to zone name for the endpoint entry.
|
||||
if r.OwnerName == "" {
|
||||
name = zone.Properties.Name
|
||||
}
|
||||
|
||||
endPointTTL := endpoint.NewEndpointWithTTL(name, recordTypeArray[0], endpoint.TTL(r.TTL), r.RData...)
|
||||
endpoints = append(endpoints, endPointTTL)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Infof("endpoints %v", endpoints)
|
||||
return endpoints, nil
|
||||
}
|
||||
|
||||
func (p *UltraDNSProvider) fetchRecords(ctx context.Context, k udnssdk.RRSetKey) ([]udnssdk.RRSet, error) {
|
||||
// Logic to paginate through all available results
|
||||
maxerrs := 5
|
||||
waittime := 5 * time.Second
|
||||
|
||||
var rrsets []udnssdk.RRSet
|
||||
errcnt := 0
|
||||
offset := 0
|
||||
limit := 1000
|
||||
|
||||
for {
|
||||
reqRrsets, ri, res, err := p.client.RRSets.SelectWithOffsetWithLimit(k, offset, limit)
|
||||
if err != nil {
|
||||
if res != nil && res.StatusCode >= 500 {
|
||||
errcnt = errcnt + 1
|
||||
if errcnt < maxerrs {
|
||||
time.Sleep(waittime)
|
||||
continue
|
||||
}
|
||||
}
|
||||
return rrsets, err
|
||||
}
|
||||
rrsets = append(rrsets, reqRrsets...)
|
||||
|
||||
if ri.ReturnedCount+ri.Offset >= ri.TotalCount {
|
||||
return rrsets, nil
|
||||
}
|
||||
offset = ri.ReturnedCount + ri.Offset
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
func (p *UltraDNSProvider) fetchZones(ctx context.Context, zoneKey *udnssdk.ZoneKey) ([]udnssdk.Zone, error) {
|
||||
// Logic to paginate through all available results
|
||||
offset := 0
|
||||
limit := 1000
|
||||
maxerrs := 5
|
||||
waittime := 5 * time.Second
|
||||
|
||||
zones := []udnssdk.Zone{}
|
||||
|
||||
errcnt := 0
|
||||
|
||||
for {
|
||||
reqZones, ri, res, err := p.client.Zone.SelectWithOffsetWithLimit(zoneKey, offset, limit)
|
||||
if err != nil {
|
||||
if res != nil && res.StatusCode >= 500 {
|
||||
errcnt = errcnt + 1
|
||||
if errcnt < maxerrs {
|
||||
time.Sleep(waittime)
|
||||
continue
|
||||
}
|
||||
}
|
||||
return zones, err
|
||||
}
|
||||
|
||||
zones = append(zones, reqZones...)
|
||||
if ri.ReturnedCount+ri.Offset >= ri.TotalCount {
|
||||
return zones, nil
|
||||
}
|
||||
offset = ri.ReturnedCount + ri.Offset
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
func (p *UltraDNSProvider) submitChanges(ctx context.Context, changes []*UltraDNSChanges) error {
|
||||
cnameownerName := "cname"
|
||||
txtownerName := "txt"
|
||||
if len(changes) == 0 {
|
||||
log.Infof("All records are already up to date")
|
||||
return nil
|
||||
}
|
||||
|
||||
zones, err := p.Zones(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
zoneChanges := seperateChangeByZone(zones, changes)
|
||||
|
||||
for zoneName, changes := range zoneChanges {
|
||||
for _, change := range changes {
|
||||
switch change.ResourceRecordSetUltraDNS.RRType {
|
||||
case "CNAME":
|
||||
cnameownerName = change.ResourceRecordSetUltraDNS.OwnerName
|
||||
case "TXT":
|
||||
txtownerName = change.ResourceRecordSetUltraDNS.OwnerName
|
||||
}
|
||||
|
||||
if cnameownerName == txtownerName {
|
||||
rrsetKey := udnssdk.RRSetKey{
|
||||
Zone: zoneName,
|
||||
Type: endpoint.RecordTypeCNAME,
|
||||
Name: change.ResourceRecordSetUltraDNS.OwnerName,
|
||||
}
|
||||
err := p.getSpecificRecord(ctx, rrsetKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !p.dryRun {
|
||||
_, err = p.client.RRSets.Delete(rrsetKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("the 'cname' and 'txt' record name cannot be same please recreate external-dns with - --txt-prefix=")
|
||||
}
|
||||
rrsetKey := udnssdk.RRSetKey{
|
||||
Zone: zoneName,
|
||||
Type: change.ResourceRecordSetUltraDNS.RRType,
|
||||
Name: change.ResourceRecordSetUltraDNS.OwnerName,
|
||||
}
|
||||
record := udnssdk.RRSet{}
|
||||
if (change.ResourceRecordSetUltraDNS.RRType == "A" || change.ResourceRecordSetUltraDNS.RRType == "AAAA") && (len(change.ResourceRecordSetUltraDNS.RData) >= 2) {
|
||||
if ultradnsPoolType == "sbpool" && change.ResourceRecordSetUltraDNS.RRType == "A" {
|
||||
sbPoolObject, _ := p.newSBPoolObjectCreation(ctx, change)
|
||||
record = udnssdk.RRSet{
|
||||
RRType: change.ResourceRecordSetUltraDNS.RRType,
|
||||
OwnerName: change.ResourceRecordSetUltraDNS.OwnerName,
|
||||
RData: change.ResourceRecordSetUltraDNS.RData,
|
||||
TTL: change.ResourceRecordSetUltraDNS.TTL,
|
||||
Profile: sbPoolObject.RawProfile(),
|
||||
}
|
||||
} else if ultradnsPoolType == "rdpool" {
|
||||
rdPoolObject, _ := p.newRDPoolObjectCreation(ctx, change)
|
||||
record = udnssdk.RRSet{
|
||||
RRType: change.ResourceRecordSetUltraDNS.RRType,
|
||||
OwnerName: change.ResourceRecordSetUltraDNS.OwnerName,
|
||||
RData: change.ResourceRecordSetUltraDNS.RData,
|
||||
TTL: change.ResourceRecordSetUltraDNS.TTL,
|
||||
Profile: rdPoolObject.RawProfile(),
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("we do not support Multiple target 'aaaa' records in sb pool please contact to neustar for further details")
|
||||
}
|
||||
} else {
|
||||
record = udnssdk.RRSet{
|
||||
RRType: change.ResourceRecordSetUltraDNS.RRType,
|
||||
OwnerName: change.ResourceRecordSetUltraDNS.OwnerName,
|
||||
RData: change.ResourceRecordSetUltraDNS.RData,
|
||||
TTL: change.ResourceRecordSetUltraDNS.TTL,
|
||||
}
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"record": record.OwnerName,
|
||||
"type": record.RRType,
|
||||
"ttl": record.TTL,
|
||||
"action": change.Action,
|
||||
"zone": zoneName,
|
||||
"profile": record.Profile,
|
||||
}).Info("Changing record.")
|
||||
|
||||
switch change.Action {
|
||||
case ultradnsCreate:
|
||||
if !p.dryRun {
|
||||
res, err := p.client.RRSets.Create(rrsetKey, record)
|
||||
_ = res
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
case ultradnsDelete:
|
||||
err := p.getSpecificRecord(ctx, rrsetKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !p.dryRun {
|
||||
_, err = p.client.RRSets.Delete(rrsetKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case ultradnsUpdate:
|
||||
err := p.getSpecificRecord(ctx, rrsetKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !p.dryRun {
|
||||
_, err = p.client.RRSets.Update(rrsetKey, record)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *UltraDNSProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error {
|
||||
combinedChanges := make([]*UltraDNSChanges, 0, len(changes.Create)+len(changes.UpdateNew)+len(changes.Delete))
|
||||
log.Infof("value of changes %v,%v,%v", changes.Create, changes.UpdateNew, changes.Delete)
|
||||
combinedChanges = append(combinedChanges, newUltraDNSChanges(ultradnsCreate, changes.Create)...)
|
||||
combinedChanges = append(combinedChanges, newUltraDNSChanges(ultradnsUpdate, changes.UpdateNew)...)
|
||||
combinedChanges = append(combinedChanges, newUltraDNSChanges(ultradnsDelete, changes.Delete)...)
|
||||
|
||||
return p.submitChanges(ctx, combinedChanges)
|
||||
}
|
||||
|
||||
func newUltraDNSChanges(action string, endpoints []*endpoint.Endpoint) []*UltraDNSChanges {
|
||||
changes := make([]*UltraDNSChanges, 0, len(endpoints))
|
||||
var ttl int
|
||||
for _, e := range endpoints {
|
||||
if e.RecordTTL.IsConfigured() {
|
||||
ttl = int(e.RecordTTL)
|
||||
}
|
||||
|
||||
// Adding suffix dot to the record name
|
||||
recordName := fmt.Sprintf("%s.", e.DNSName)
|
||||
change := &UltraDNSChanges{
|
||||
Action: action,
|
||||
ResourceRecordSetUltraDNS: udnssdk.RRSet{
|
||||
RRType: e.RecordType,
|
||||
OwnerName: recordName,
|
||||
RData: e.Targets,
|
||||
TTL: ttl,
|
||||
},
|
||||
}
|
||||
changes = append(changes, change)
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
func seperateChangeByZone(zones []udnssdk.Zone, changes []*UltraDNSChanges) map[string][]*UltraDNSChanges {
|
||||
change := make(map[string][]*UltraDNSChanges)
|
||||
zoneNameID := provider.ZoneIDName{}
|
||||
for _, z := range zones {
|
||||
zoneNameID.Add(z.Properties.Name, z.Properties.Name)
|
||||
change[z.Properties.Name] = []*UltraDNSChanges{}
|
||||
}
|
||||
|
||||
for _, c := range changes {
|
||||
zone, _ := zoneNameID.FindZone(c.ResourceRecordSetUltraDNS.OwnerName)
|
||||
if zone == "" {
|
||||
log.Infof("Skipping record %s because no hosted zone matching record DNS Name was detected", c.ResourceRecordSetUltraDNS.OwnerName)
|
||||
continue
|
||||
}
|
||||
change[zone] = append(change[zone], c)
|
||||
}
|
||||
return change
|
||||
}
|
||||
|
||||
func (p *UltraDNSProvider) getSpecificRecord(ctx context.Context, rrsetKey udnssdk.RRSetKey) (err error) {
|
||||
_, err = p.client.RRSets.Select(rrsetKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("no record was found for %v", rrsetKey)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Creation of SBPoolObject
|
||||
func (p *UltraDNSProvider) newSBPoolObjectCreation(ctx context.Context, change *UltraDNSChanges) (sbPool udnssdk.SBPoolProfile, err error) {
|
||||
sbpoolRDataList := []udnssdk.SBRDataInfo{}
|
||||
for range change.ResourceRecordSetUltraDNS.RData {
|
||||
rrdataInfo := udnssdk.SBRDataInfo{
|
||||
RunProbes: sbPoolRunProbes,
|
||||
Priority: sbPoolPriority,
|
||||
State: "NORMAL",
|
||||
Threshold: 1,
|
||||
Weight: nil,
|
||||
}
|
||||
sbpoolRDataList = append(sbpoolRDataList, rrdataInfo)
|
||||
}
|
||||
sbPoolObject := udnssdk.SBPoolProfile{
|
||||
Context: udnssdk.SBPoolSchema,
|
||||
Order: sbPoolOrder,
|
||||
Description: change.ResourceRecordSetUltraDNS.OwnerName,
|
||||
MaxActive: len(change.ResourceRecordSetUltraDNS.RData),
|
||||
MaxServed: len(change.ResourceRecordSetUltraDNS.RData),
|
||||
RDataInfo: sbpoolRDataList,
|
||||
RunProbes: sbPoolRunProbes,
|
||||
ActOnProbes: sbPoolActOnProbes,
|
||||
}
|
||||
return sbPoolObject, nil
|
||||
}
|
||||
|
||||
// Creation of RDPoolObject
|
||||
func (p *UltraDNSProvider) newRDPoolObjectCreation(ctx context.Context, change *UltraDNSChanges) (rdPool udnssdk.RDPoolProfile, err error) {
|
||||
rdPoolObject := udnssdk.RDPoolProfile{
|
||||
Context: udnssdk.RDPoolSchema,
|
||||
Order: rdPoolOrder,
|
||||
Description: change.ResourceRecordSetUltraDNS.OwnerName,
|
||||
}
|
||||
return rdPoolObject, nil
|
||||
}
|
@ -1,756 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package ultradns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
_ "strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
udnssdk "github.com/ultradns/ultradns-sdk-go"
|
||||
|
||||
"sigs.k8s.io/external-dns/endpoint"
|
||||
"sigs.k8s.io/external-dns/plan"
|
||||
)
|
||||
|
||||
type mockUltraDNSZone struct {
|
||||
client *udnssdk.Client
|
||||
}
|
||||
|
||||
func (m *mockUltraDNSZone) SelectWithOffsetWithLimit(k *udnssdk.ZoneKey, offset int, limit int) (zones []udnssdk.Zone, ResultInfo udnssdk.ResultInfo, resp *http.Response, err error) {
|
||||
zones = []udnssdk.Zone{}
|
||||
zone := udnssdk.Zone{}
|
||||
zoneJson := `
|
||||
{
|
||||
"properties": {
|
||||
"name":"test-ultradns-provider.com.",
|
||||
"accountName":"teamrest",
|
||||
"type":"PRIMARY",
|
||||
"dnssecStatus":"UNSIGNED",
|
||||
"status":"ACTIVE",
|
||||
"owner":"teamrest",
|
||||
"resourceRecordCount":7,
|
||||
"lastModifiedDateTime":""
|
||||
}
|
||||
}`
|
||||
if err := json.Unmarshal([]byte(zoneJson), &zone); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
zones = append(zones, zone)
|
||||
return zones, udnssdk.ResultInfo{}, nil, nil
|
||||
}
|
||||
|
||||
type mockUltraDNSRecord struct {
|
||||
client *udnssdk.Client
|
||||
}
|
||||
|
||||
func (m *mockUltraDNSRecord) Create(_ udnssdk.RRSetKey, _ udnssdk.RRSet) (*http.Response, error) {
|
||||
return &http.Response{}, nil
|
||||
}
|
||||
|
||||
func (m *mockUltraDNSRecord) Select(_ udnssdk.RRSetKey) ([]udnssdk.RRSet, error) {
|
||||
return []udnssdk.RRSet{{
|
||||
OwnerName: "test-ultradns-provider.com.",
|
||||
RRType: endpoint.RecordTypeA,
|
||||
RData: []string{"1.1.1.1"},
|
||||
TTL: 86400,
|
||||
}}, nil
|
||||
}
|
||||
|
||||
func (m *mockUltraDNSRecord) SelectWithOffset(k udnssdk.RRSetKey, offset int) ([]udnssdk.RRSet, udnssdk.ResultInfo, *http.Response, error) {
|
||||
return nil, udnssdk.ResultInfo{}, nil, nil
|
||||
}
|
||||
|
||||
func (m *mockUltraDNSRecord) Update(udnssdk.RRSetKey, udnssdk.RRSet) (*http.Response, error) {
|
||||
return &http.Response{}, nil
|
||||
}
|
||||
|
||||
func (m *mockUltraDNSRecord) Delete(k udnssdk.RRSetKey) (*http.Response, error) {
|
||||
return &http.Response{}, nil
|
||||
}
|
||||
|
||||
func (m *mockUltraDNSRecord) SelectWithOffsetWithLimit(k udnssdk.RRSetKey, offset int, limit int) (rrsets []udnssdk.RRSet, ResultInfo udnssdk.ResultInfo, resp *http.Response, err error) {
|
||||
return []udnssdk.RRSet{{
|
||||
OwnerName: "test-ultradns-provider.com.",
|
||||
RRType: endpoint.RecordTypeA,
|
||||
RData: []string{"1.1.1.1"},
|
||||
TTL: 86400,
|
||||
}}, udnssdk.ResultInfo{}, nil, nil
|
||||
}
|
||||
|
||||
// NewUltraDNSProvider Test scenario
|
||||
func TestNewUltraDNSProvider(t *testing.T) {
|
||||
_ = os.Setenv("ULTRADNS_USERNAME", "")
|
||||
_ = os.Setenv("ULTRADNS_PASSWORD", "")
|
||||
_ = os.Setenv("ULTRADNS_BASEURL", "")
|
||||
_ = os.Setenv("ULTRADNS_ACCOUNTNAME", "")
|
||||
_, err := NewUltraDNSProvider(endpoint.NewDomainFilter([]string{"test-ultradns-provider.com"}), true)
|
||||
assert.NoError(t, err)
|
||||
|
||||
_ = os.Unsetenv("ULTRADNS_PASSWORD")
|
||||
_ = os.Unsetenv("ULTRADNS_USERNAME")
|
||||
_ = os.Unsetenv("ULTRADNS_BASEURL")
|
||||
_ = os.Unsetenv("ULTRADNS_ACCOUNTNAME")
|
||||
_, err = NewUltraDNSProvider(endpoint.NewDomainFilter([]string{"test-ultradns-provider.com"}), true)
|
||||
assert.Errorf(t, err, "Expected to fail %s", "formatted")
|
||||
}
|
||||
|
||||
// zones function test scenario
|
||||
func TestUltraDNSProvider_Zones(t *testing.T) {
|
||||
mocked := mockUltraDNSZone{}
|
||||
provider := &UltraDNSProvider{
|
||||
client: udnssdk.Client{
|
||||
Zone: &mocked,
|
||||
},
|
||||
}
|
||||
|
||||
zoneKey := &udnssdk.ZoneKey{
|
||||
Zone: "",
|
||||
AccountName: "teamrest",
|
||||
}
|
||||
|
||||
expected, _, _, err := provider.client.Zone.SelectWithOffsetWithLimit(zoneKey, 0, 1000)
|
||||
require.NoError(t, err)
|
||||
zones, err := provider.Zones(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.True(t, reflect.DeepEqual(expected, zones))
|
||||
}
|
||||
|
||||
// Records function test case
|
||||
func TestUltraDNSProvider_Records(t *testing.T) {
|
||||
mocked := mockUltraDNSRecord{}
|
||||
mockedDomain := mockUltraDNSZone{}
|
||||
|
||||
provider := &UltraDNSProvider{
|
||||
client: udnssdk.Client{
|
||||
RRSets: &mocked,
|
||||
Zone: &mockedDomain,
|
||||
},
|
||||
}
|
||||
rrsetKey := udnssdk.RRSetKey{}
|
||||
expected, _, _, err := provider.client.RRSets.SelectWithOffsetWithLimit(rrsetKey, 0, 1000)
|
||||
records, err := provider.Records(context.Background())
|
||||
require.NoError(t, err)
|
||||
for _, v := range records {
|
||||
assert.Equal(t, fmt.Sprintf("%s.", v.DNSName), expected[0].OwnerName)
|
||||
assert.Equal(t, v.RecordType, expected[0].RRType)
|
||||
assert.Equal(t, int(v.RecordTTL), expected[0].TTL)
|
||||
}
|
||||
}
|
||||
|
||||
// ApplyChanges function testcase
|
||||
func TestUltraDNSProvider_ApplyChanges(t *testing.T) {
|
||||
changes := &plan.Changes{}
|
||||
mocked := mockUltraDNSRecord{nil}
|
||||
mockedDomain := mockUltraDNSZone{nil}
|
||||
|
||||
provider := &UltraDNSProvider{
|
||||
client: udnssdk.Client{
|
||||
RRSets: &mocked,
|
||||
Zone: &mockedDomain,
|
||||
},
|
||||
}
|
||||
|
||||
changes.Create = []*endpoint.Endpoint{
|
||||
{DNSName: "test-ultradns-provider.com", Targets: endpoint.Targets{"1.1.1.1"}, RecordType: "A"},
|
||||
{DNSName: "ttl.test-ultradns-provider.com", Targets: endpoint.Targets{"1.1.1.1"}, RecordType: "A", RecordTTL: 100},
|
||||
}
|
||||
changes.Create = []*endpoint.Endpoint{{DNSName: "test-ultradns-provider.com", Targets: endpoint.Targets{"1.1.1.2"}, RecordType: "A"}}
|
||||
changes.UpdateNew = []*endpoint.Endpoint{{DNSName: "test-ultradns-provider.com", Targets: endpoint.Targets{"1.1.2.2"}, RecordType: "A", RecordTTL: 100}}
|
||||
changes.UpdateNew = []*endpoint.Endpoint{{DNSName: "test-ultradns-provider.com", Targets: endpoint.Targets{"1.1.2.2", "1.1.2.3", "1.1.2.4"}, RecordType: "A", RecordTTL: 100}}
|
||||
changes.Delete = []*endpoint.Endpoint{{DNSName: "test-ultradns-provider.com", Targets: endpoint.Targets{"1.1.2.2", "1.1.2.3", "1.1.2.4"}, RecordType: "A", RecordTTL: 100}}
|
||||
changes.Delete = []*endpoint.Endpoint{{DNSName: "ttl.test-ultradns-provider.com", Targets: endpoint.Targets{"1.1.1.1"}, RecordType: "A", RecordTTL: 100}}
|
||||
err := provider.ApplyChanges(context.Background(), changes)
|
||||
assert.NoErrorf(t, err, "Should not fail %s", "formatted")
|
||||
}
|
||||
|
||||
// Testing function getSpecificRecord
|
||||
func TestUltraDNSProvider_getSpecificRecord(t *testing.T) {
|
||||
mocked := mockUltraDNSRecord{nil}
|
||||
mockedDomain := mockUltraDNSZone{nil}
|
||||
|
||||
provider := &UltraDNSProvider{
|
||||
client: udnssdk.Client{
|
||||
RRSets: &mocked,
|
||||
Zone: &mockedDomain,
|
||||
},
|
||||
}
|
||||
|
||||
recordSetKey := udnssdk.RRSetKey{
|
||||
Zone: "test-ultradns-provider.com.",
|
||||
Type: "A",
|
||||
Name: "teamrest",
|
||||
}
|
||||
err := provider.getSpecificRecord(context.Background(), recordSetKey)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
// Fail case scenario testing where CNAME and TXT Record name are same
|
||||
func TestUltraDNSProvider_ApplyChangesCNAME(t *testing.T) {
|
||||
changes := &plan.Changes{}
|
||||
mocked := mockUltraDNSRecord{nil}
|
||||
mockedDomain := mockUltraDNSZone{nil}
|
||||
|
||||
provider := &UltraDNSProvider{
|
||||
client: udnssdk.Client{
|
||||
RRSets: &mocked,
|
||||
Zone: &mockedDomain,
|
||||
},
|
||||
}
|
||||
|
||||
changes.Create = []*endpoint.Endpoint{
|
||||
{DNSName: "test-ultradns-provider.com", Targets: endpoint.Targets{"1.1.1.1"}, RecordType: "CNAME"},
|
||||
{DNSName: "test-ultradns-provider.com", Targets: endpoint.Targets{"1.1.1.1"}, RecordType: "TXT"},
|
||||
}
|
||||
|
||||
err := provider.ApplyChanges(context.Background(), changes)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
// This will work if you would set the environment variables such as "ULTRADNS_INTEGRATION" and zone should be available "kubernetes-ultradns-provider-test.com"
|
||||
func TestUltraDNSProvider_ApplyChanges_Integration(t *testing.T) {
|
||||
_, ok := os.LookupEnv("ULTRADNS_INTEGRATION")
|
||||
if !ok {
|
||||
log.Printf("Skipping test")
|
||||
} else {
|
||||
|
||||
providerUltradns, err := NewUltraDNSProvider(endpoint.NewDomainFilter([]string{"kubernetes-ultradns-provider-test.com"}), false)
|
||||
changes := &plan.Changes{}
|
||||
changes.Create = []*endpoint.Endpoint{
|
||||
{DNSName: "kubernetes-ultradns-provider-test.com", Targets: endpoint.Targets{"1.1.1.1"}, RecordType: "A"},
|
||||
{DNSName: "ttl.kubernetes-ultradns-provider-test.com", Targets: endpoint.Targets{"2001:0db8:85a3:0000:0000:8a2e:0370:7334"}, RecordType: "AAAA", RecordTTL: 100},
|
||||
}
|
||||
|
||||
err = providerUltradns.ApplyChanges(context.Background(), changes)
|
||||
require.NoError(t, err)
|
||||
|
||||
rrsetKey := udnssdk.RRSetKey{
|
||||
Zone: "kubernetes-ultradns-provider-test.com.",
|
||||
Name: "kubernetes-ultradns-provider-test.com.",
|
||||
Type: "A",
|
||||
}
|
||||
|
||||
rrsets, _ := providerUltradns.client.RRSets.Select(rrsetKey)
|
||||
assert.Equal(t, "1.1.1.1", rrsets[0].RData[0])
|
||||
|
||||
rrsetKey = udnssdk.RRSetKey{
|
||||
Zone: "kubernetes-ultradns-provider-test.com.",
|
||||
Name: "ttl.kubernetes-ultradns-provider-test.com.",
|
||||
Type: "AAAA",
|
||||
}
|
||||
|
||||
rrsets, _ = providerUltradns.client.RRSets.Select(rrsetKey)
|
||||
assert.Equal(t, "2001:db8:85a3:0:0:8a2e:370:7334", rrsets[0].RData[0])
|
||||
|
||||
changes = &plan.Changes{}
|
||||
changes.UpdateNew = []*endpoint.Endpoint{
|
||||
{DNSName: "kubernetes-ultradns-provider-test.com", Targets: endpoint.Targets{"1.1.2.2"}, RecordType: "A", RecordTTL: 100},
|
||||
{DNSName: "ttl.kubernetes-ultradns-provider-test.com", Targets: endpoint.Targets{"2001:0db8:85a3:0000:0000:8a2e:0370:7335"}, RecordType: "AAAA", RecordTTL: 100},
|
||||
}
|
||||
err = providerUltradns.ApplyChanges(context.Background(), changes)
|
||||
require.NoError(t, err)
|
||||
|
||||
rrsetKey = udnssdk.RRSetKey{
|
||||
Zone: "kubernetes-ultradns-provider-test.com.",
|
||||
Name: "kubernetes-ultradns-provider-test.com.",
|
||||
Type: "A",
|
||||
}
|
||||
|
||||
rrsets, _ = providerUltradns.client.RRSets.Select(rrsetKey)
|
||||
assert.Equal(t, "1.1.2.2", rrsets[0].RData[0])
|
||||
|
||||
rrsetKey = udnssdk.RRSetKey{
|
||||
Zone: "kubernetes-ultradns-provider-test.com.",
|
||||
Name: "ttl.kubernetes-ultradns-provider-test.com.",
|
||||
Type: "AAAA",
|
||||
}
|
||||
|
||||
rrsets, _ = providerUltradns.client.RRSets.Select(rrsetKey)
|
||||
assert.Equal(t, "2001:db8:85a3:0:0:8a2e:370:7335", rrsets[0].RData[0])
|
||||
|
||||
changes = &plan.Changes{}
|
||||
changes.Delete = []*endpoint.Endpoint{
|
||||
{DNSName: "ttl.kubernetes-ultradns-provider-test.com", Targets: endpoint.Targets{"2001:0db8:85a3:0000:0000:8a2e:0370:7335"}, RecordType: "AAAA", RecordTTL: 100},
|
||||
{DNSName: "kubernetes-ultradns-provider-test.com", Targets: endpoint.Targets{"1.1.2.2"}, RecordType: "A", RecordTTL: 100},
|
||||
}
|
||||
|
||||
err = providerUltradns.ApplyChanges(context.Background(), changes)
|
||||
require.NoError(t, err)
|
||||
|
||||
resp, _ := providerUltradns.client.Do("GET", "zones/kubernetes-ultradns-provider-test.com./rrsets/AAAA/ttl.kubernetes-ultradns-provider-test.com.", nil, udnssdk.RRSetListDTO{})
|
||||
assert.Equal(t, "404 Not Found", resp.Status)
|
||||
|
||||
resp, _ = providerUltradns.client.Do("GET", "zones/kubernetes-ultradns-provider-test.com./rrsets/A/kubernetes-ultradns-provider-test.com.", nil, udnssdk.RRSetListDTO{})
|
||||
assert.Equal(t, "404 Not Found", resp.Status)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// This will work if you would set the environment variables such as "ULTRADNS_INTEGRATION" and zone should be available "kubernetes-ultradns-provider-test.com" for multiple target
|
||||
func TestUltraDNSProvider_ApplyChanges_MultipleTarget_integeration(t *testing.T) {
|
||||
_, ok := os.LookupEnv("ULTRADNS_INTEGRATION")
|
||||
if !ok {
|
||||
log.Printf("Skipping test")
|
||||
} else {
|
||||
|
||||
provider, err := NewUltraDNSProvider(endpoint.NewDomainFilter([]string{"kubernetes-ultradns-provider-test.com"}), false)
|
||||
changes := &plan.Changes{}
|
||||
changes.Create = []*endpoint.Endpoint{
|
||||
{DNSName: "kubernetes-ultradns-provider-test.com", Targets: endpoint.Targets{"1.1.1.1", "1.1.2.2"}, RecordType: "A"},
|
||||
}
|
||||
|
||||
err = provider.ApplyChanges(context.Background(), changes)
|
||||
assert.NoError(t, err)
|
||||
|
||||
rrsetKey := udnssdk.RRSetKey{
|
||||
Zone: "kubernetes-ultradns-provider-test.com.",
|
||||
Name: "kubernetes-ultradns-provider-test.com.",
|
||||
Type: "A",
|
||||
}
|
||||
|
||||
rrsets, _ := provider.client.RRSets.Select(rrsetKey)
|
||||
assert.Equal(t, []string{"1.1.1.1", "1.1.2.2"}, rrsets[0].RData)
|
||||
|
||||
changes = &plan.Changes{}
|
||||
changes.UpdateNew = []*endpoint.Endpoint{{DNSName: "kubernetes-ultradns-provider-test.com", Targets: endpoint.Targets{"1.1.2.2", "192.168.0.24", "1.2.3.4"}, RecordType: "A", RecordTTL: 100}}
|
||||
|
||||
err = provider.ApplyChanges(context.Background(), changes)
|
||||
require.NoError(t, err)
|
||||
|
||||
rrsetKey = udnssdk.RRSetKey{
|
||||
Zone: "kubernetes-ultradns-provider-test.com.",
|
||||
Name: "kubernetes-ultradns-provider-test.com.",
|
||||
Type: "A",
|
||||
}
|
||||
|
||||
rrsets, _ = provider.client.RRSets.Select(rrsetKey)
|
||||
assert.Equal(t, []string{"1.1.2.2", "192.168.0.24", "1.2.3.4"}, rrsets[0].RData)
|
||||
|
||||
changes = &plan.Changes{}
|
||||
changes.UpdateNew = []*endpoint.Endpoint{{DNSName: "kubernetes-ultradns-provider-test.com", Targets: endpoint.Targets{"1.1.2.2"}, RecordType: "A", RecordTTL: 100}}
|
||||
|
||||
err = provider.ApplyChanges(context.Background(), changes)
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
rrsetKey = udnssdk.RRSetKey{
|
||||
Zone: "kubernetes-ultradns-provider-test.com.",
|
||||
Name: "kubernetes-ultradns-provider-test.com.",
|
||||
Type: "A",
|
||||
}
|
||||
|
||||
rrsets, _ = provider.client.RRSets.Select(rrsetKey)
|
||||
assert.Equal(t, []string{"1.1.2.2"}, rrsets[0].RData)
|
||||
|
||||
changes = &plan.Changes{}
|
||||
changes.Delete = []*endpoint.Endpoint{{DNSName: "kubernetes-ultradns-provider-test.com", Targets: endpoint.Targets{"1.1.2.2", "192.168.0.24"}, RecordType: "A"}}
|
||||
|
||||
err = provider.ApplyChanges(context.Background(), changes)
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
resp, _ := provider.client.Do("GET", "zones/kubernetes-ultradns-provider-test.com./rrsets/A/kubernetes-ultradns-provider-test.com.", nil, udnssdk.RRSetListDTO{})
|
||||
assert.Equal(t, "404 Not Found", resp.Status)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Test case to check sbpool creation
|
||||
func TestUltraDNSProvider_newSBPoolObjectCreation(t *testing.T) {
|
||||
mocked := mockUltraDNSRecord{nil}
|
||||
mockedDomain := mockUltraDNSZone{nil}
|
||||
|
||||
provider := &UltraDNSProvider{
|
||||
client: udnssdk.Client{
|
||||
RRSets: &mocked,
|
||||
Zone: &mockedDomain,
|
||||
},
|
||||
}
|
||||
sbpoolRDataList := []udnssdk.SBRDataInfo{}
|
||||
changes := &plan.Changes{}
|
||||
changes.UpdateNew = []*endpoint.Endpoint{{DNSName: "kubernetes-ultradns-provider-test.com.", Targets: endpoint.Targets{"1.1.2.2", "192.168.0.24"}, RecordType: "A", RecordTTL: 100}}
|
||||
changesList := &UltraDNSChanges{
|
||||
Action: "UPDATE",
|
||||
ResourceRecordSetUltraDNS: udnssdk.RRSet{
|
||||
RRType: "A",
|
||||
OwnerName: "kubernetes-ultradns-provider-test.com.",
|
||||
RData: []string{"1.1.2.2", "192.168.0.24"},
|
||||
TTL: 100,
|
||||
},
|
||||
}
|
||||
|
||||
for range changesList.ResourceRecordSetUltraDNS.RData {
|
||||
|
||||
rrdataInfo := udnssdk.SBRDataInfo{
|
||||
RunProbes: true,
|
||||
Priority: 1,
|
||||
State: "NORMAL",
|
||||
Threshold: 1,
|
||||
Weight: nil,
|
||||
}
|
||||
sbpoolRDataList = append(sbpoolRDataList, rrdataInfo)
|
||||
}
|
||||
sbPoolObject := udnssdk.SBPoolProfile{
|
||||
Context: udnssdk.SBPoolSchema,
|
||||
Order: "ROUND_ROBIN",
|
||||
Description: "kubernetes-ultradns-provider-test.com.",
|
||||
MaxActive: 2,
|
||||
MaxServed: 2,
|
||||
RDataInfo: sbpoolRDataList,
|
||||
RunProbes: true,
|
||||
ActOnProbes: true,
|
||||
}
|
||||
|
||||
actualSBPoolObject, _ := provider.newSBPoolObjectCreation(context.Background(), changesList)
|
||||
assert.Equal(t, sbPoolObject, actualSBPoolObject)
|
||||
}
|
||||
|
||||
// Testcase to check fail scenario for multiple AAAA targets
|
||||
func TestUltraDNSProvider_MultipleTargetAAAA(t *testing.T) {
|
||||
_, ok := os.LookupEnv("ULTRADNS_INTEGRATION")
|
||||
if !ok {
|
||||
log.Printf("Skipping test")
|
||||
} else {
|
||||
_ = os.Setenv("ULTRADNS_POOL_TYPE", "sbpool")
|
||||
|
||||
provider, _ := NewUltraDNSProvider(endpoint.NewDomainFilter([]string{"kubernetes-ultradns-provider-test.com"}), false)
|
||||
changes := &plan.Changes{}
|
||||
changes.Create = []*endpoint.Endpoint{
|
||||
{DNSName: "ttl.kubernetes-ultradns-provider-test.com", Targets: endpoint.Targets{"2001:0db8:85a3:0000:0000:8a2e:0370:7334", "2001:0db8:85a3:0000:0000:8a2e:0370:7335"}, RecordType: "AAAA", RecordTTL: 100},
|
||||
}
|
||||
err := provider.ApplyChanges(context.Background(), changes)
|
||||
assert.Errorf(t, err, "We wanted it to fail since multiple AAAA targets are not allowed %s", "formatted")
|
||||
|
||||
resp, _ := provider.client.Do("GET", "zones/kubernetes-ultradns-provider-test.com./rrsets/AAAA/ttl.kubernetes-ultradns-provider-test.com.", nil, udnssdk.RRSetListDTO{})
|
||||
assert.Equal(t, "404 Not Found", resp.Status)
|
||||
_ = os.Unsetenv("ULTRADNS_POOL_TYPE")
|
||||
}
|
||||
}
|
||||
|
||||
// Testcase to check fail scenario for multiple AAAA targets
|
||||
func TestUltraDNSProvider_MultipleTargetAAAARDPool(t *testing.T) {
|
||||
_, ok := os.LookupEnv("ULTRADNS_INTEGRATION")
|
||||
if !ok {
|
||||
log.Printf("Skipping test")
|
||||
} else {
|
||||
_ = os.Setenv("ULTRADNS_POOL_TYPE", "rdpool")
|
||||
provider, _ := NewUltraDNSProvider(endpoint.NewDomainFilter([]string{"kubernetes-ultradns-provider-test.com"}), false)
|
||||
changes := &plan.Changes{}
|
||||
changes.Create = []*endpoint.Endpoint{
|
||||
{DNSName: "ttl.kubernetes-ultradns-provider-test.com", Targets: endpoint.Targets{"2001:0db8:85a3:0000:0000:8a2e:0370:7334", "2001:0db8:85a3:0000:0000:8a2e:0370:7335"}, RecordType: "AAAA", RecordTTL: 100},
|
||||
}
|
||||
err := provider.ApplyChanges(context.Background(), changes)
|
||||
require.NoErrorf(t, err, " multiple AAAA targets are allowed when pool is RDPool %s", "formatted")
|
||||
|
||||
resp, _ := provider.client.Do("GET", "zones/kubernetes-ultradns-provider-test.com./rrsets/AAAA/ttl.kubernetes-ultradns-provider-test.com.", nil, udnssdk.RRSetListDTO{})
|
||||
assert.Equal(t, "200 OK", resp.Status)
|
||||
|
||||
changes = &plan.Changes{}
|
||||
changes.Delete = []*endpoint.Endpoint{{DNSName: "ttl.kubernetes-ultradns-provider-test.com", Targets: endpoint.Targets{"2001:0db8:85a3:0000:0000:8a2e:0370:7334", "2001:0db8:85a3:0000:0000:8a2e:0370:7335"}, RecordType: "AAAA"}}
|
||||
|
||||
err = provider.ApplyChanges(context.Background(), changes)
|
||||
require.NoError(t, err)
|
||||
|
||||
resp, _ = provider.client.Do("GET", "zones/kubernetes-ultradns-provider-test.com./rrsets/A/kubernetes-ultradns-provider-test.com.", nil, udnssdk.RRSetListDTO{})
|
||||
assert.Equal(t, "404 Not Found", resp.Status)
|
||||
}
|
||||
}
|
||||
|
||||
// Test case to check multiple CNAME targets.
|
||||
func TestUltraDNSProvider_MultipleTargetCNAME(t *testing.T) {
|
||||
_, ok := os.LookupEnv("ULTRADNS_INTEGRATION")
|
||||
if !ok {
|
||||
log.Printf("Skipping test")
|
||||
} else {
|
||||
provider, err := NewUltraDNSProvider(endpoint.NewDomainFilter([]string{"kubernetes-ultradns-provider-test.com"}), false)
|
||||
changes := &plan.Changes{}
|
||||
|
||||
changes.Create = []*endpoint.Endpoint{
|
||||
{DNSName: "ttl.kubernetes-ultradns-provider-test.com", Targets: endpoint.Targets{"nginx.loadbalancer.com.", "nginx1.loadbalancer.com."}, RecordType: "CNAME", RecordTTL: 100},
|
||||
}
|
||||
err = provider.ApplyChanges(context.Background(), changes)
|
||||
|
||||
assert.Errorf(t, err, "We wanted it to fail since multiple CNAME targets are not allowed %s", "formatted")
|
||||
|
||||
resp, _ := provider.client.Do("GET", "zones/kubernetes-ultradns-provider-test.com./rrsets/CNAME/kubernetes-ultradns-provider-test.com.", nil, udnssdk.RRSetListDTO{})
|
||||
assert.Equal(t, "404 Not Found", resp.Status)
|
||||
}
|
||||
}
|
||||
|
||||
// Testing creation of RD Pool
|
||||
func TestUltraDNSProvider_newRDPoolObjectCreation(t *testing.T) {
|
||||
mocked := mockUltraDNSRecord{nil}
|
||||
mockedDomain := mockUltraDNSZone{nil}
|
||||
|
||||
provider := &UltraDNSProvider{
|
||||
client: udnssdk.Client{
|
||||
RRSets: &mocked,
|
||||
Zone: &mockedDomain,
|
||||
},
|
||||
}
|
||||
changes := &plan.Changes{}
|
||||
changes.UpdateNew = []*endpoint.Endpoint{{DNSName: "kubernetes-ultradns-provider-test.com.", Targets: endpoint.Targets{"1.1.2.2", "192.168.0.24"}, RecordType: "A", RecordTTL: 100}}
|
||||
changesList := &UltraDNSChanges{
|
||||
Action: "UPDATE",
|
||||
ResourceRecordSetUltraDNS: udnssdk.RRSet{
|
||||
RRType: "A",
|
||||
OwnerName: "kubernetes-ultradns-provider-test.com.",
|
||||
RData: []string{"1.1.2.2", "192.168.0.24"},
|
||||
TTL: 100,
|
||||
},
|
||||
}
|
||||
rdPoolObject := udnssdk.RDPoolProfile{
|
||||
Context: udnssdk.RDPoolSchema,
|
||||
Order: "ROUND_ROBIN",
|
||||
Description: "kubernetes-ultradns-provider-test.com.",
|
||||
}
|
||||
|
||||
actualRDPoolObject, _ := provider.newRDPoolObjectCreation(context.Background(), changesList)
|
||||
assert.Equal(t, rdPoolObject, actualRDPoolObject)
|
||||
}
|
||||
|
||||
// Testing Failure scenarios over NewUltraDNS Provider
|
||||
func TestNewUltraDNSProvider_FailCases(t *testing.T) {
|
||||
_ = os.Setenv("ULTRADNS_USERNAME", "")
|
||||
_ = os.Setenv("ULTRADNS_PASSWORD", "")
|
||||
_ = os.Setenv("ULTRADNS_BASEURL", "")
|
||||
_ = os.Setenv("ULTRADNS_ACCOUNTNAME", "")
|
||||
_ = os.Setenv("ULTRADNS_POOL_TYPE", "xyz")
|
||||
_, err := NewUltraDNSProvider(endpoint.NewDomainFilter([]string{"test-ultradns-provider.com"}), true)
|
||||
assert.Errorf(t, err, "Pool Type other than given type not working %s", "formatted")
|
||||
|
||||
_ = os.Setenv("ULTRADNS_USERNAME", "")
|
||||
_ = os.Setenv("ULTRADNS_PASSWORD", "")
|
||||
_ = os.Setenv("ULTRADNS_BASEURL", "")
|
||||
_ = os.Setenv("ULTRADNS_ACCOUNTNAME", "")
|
||||
_ = os.Setenv("ULTRADNS_ENABLE_PROBING", "adefg")
|
||||
_, err = NewUltraDNSProvider(endpoint.NewDomainFilter([]string{"test-ultradns-provider.com"}), true)
|
||||
assert.Errorf(t, err, "Probe value other than given values not working %s", "formatted")
|
||||
|
||||
_ = os.Setenv("ULTRADNS_USERNAME", "")
|
||||
_ = os.Setenv("ULTRADNS_PASSWORD", "")
|
||||
_ = os.Setenv("ULTRADNS_BASEURL", "")
|
||||
_ = os.Setenv("ULTRADNS_ACCOUNTNAME", "")
|
||||
_ = os.Setenv("ULTRADNS_ENABLE_ACTONPROBE", "adefg")
|
||||
_, err = NewUltraDNSProvider(endpoint.NewDomainFilter([]string{"test-ultradns-provider.com"}), true)
|
||||
assert.Errorf(t, err, "ActOnProbe value other than given values not working %s", "formatted")
|
||||
|
||||
_ = os.Setenv("ULTRADNS_USERNAME", "")
|
||||
_ = os.Setenv("ULTRADNS_BASEURL", "")
|
||||
_ = os.Unsetenv("ULTRADNS_PASSWORD")
|
||||
_ = os.Setenv("ULTRADNS_ACCOUNTNAME", "")
|
||||
_, err = NewUltraDNSProvider(endpoint.NewDomainFilter([]string{"test-ultradns-provider.com"}), true)
|
||||
assert.Errorf(t, err, "Expected to give error if password is not set %s", "formatted")
|
||||
|
||||
_ = os.Setenv("ULTRADNS_USERNAME", "")
|
||||
_ = os.Setenv("ULTRADNS_PASSWORD", "")
|
||||
_ = os.Unsetenv("ULTRADNS_BASEURL")
|
||||
_ = os.Setenv("ULTRADNS_ACCOUNTNAME", "")
|
||||
_, err = NewUltraDNSProvider(endpoint.NewDomainFilter([]string{"test-ultradns-provider.com"}), true)
|
||||
assert.Errorf(t, err, "Expected to give error if baseurl is not set %s", "formatted")
|
||||
|
||||
_ = os.Setenv("ULTRADNS_USERNAME", "")
|
||||
_ = os.Setenv("ULTRADNS_BASEURL", "")
|
||||
_ = os.Setenv("ULTRADNS_PASSWORD", "")
|
||||
_ = os.Unsetenv("ULTRADNS_ACCOUNTNAME")
|
||||
_ = os.Unsetenv("ULTRADNS_ENABLE_ACTONPROBE")
|
||||
_ = os.Unsetenv("ULTRADNS_ENABLE_PROBING")
|
||||
_ = os.Unsetenv("ULTRADNS_POOL_TYPE")
|
||||
_, accounterr := NewUltraDNSProvider(endpoint.NewDomainFilter([]string{"test-ultradns-provider.com"}), true)
|
||||
assert.NoError(t, accounterr)
|
||||
}
|
||||
|
||||
// Testing success scenarios for newly introduced environment variables
|
||||
func TestNewUltraDNSProvider_NewEnvVariableSuccessCases(t *testing.T) {
|
||||
_ = os.Setenv("ULTRADNS_USERNAME", "")
|
||||
_ = os.Setenv("ULTRADNS_PASSWORD", "")
|
||||
_ = os.Setenv("ULTRADNS_BASEURL", "")
|
||||
_ = os.Setenv("ULTRADNS_ACCOUNTNAME", "")
|
||||
_ = os.Setenv("ULTRADNS_POOL_TYPE", "rdpool")
|
||||
_, err := NewUltraDNSProvider(endpoint.NewDomainFilter([]string{"test-ultradns-provider.com"}), true)
|
||||
assert.NoErrorf(t, err, "Pool Type not working in proper scenario %s", "formatted")
|
||||
|
||||
_ = os.Setenv("ULTRADNS_USERNAME", "")
|
||||
_ = os.Setenv("ULTRADNS_PASSWORD", "")
|
||||
_ = os.Setenv("ULTRADNS_BASEURL", "")
|
||||
_ = os.Setenv("ULTRADNS_ACCOUNTNAME", "")
|
||||
_ = os.Setenv("ULTRADNS_ENABLE_PROBING", "false")
|
||||
_, err1 := NewUltraDNSProvider(endpoint.NewDomainFilter([]string{"test-ultradns-provider.com"}), true)
|
||||
assert.NoErrorf(t, err1, "Probe given value is not working %s", "formatted")
|
||||
|
||||
_ = os.Setenv("ULTRADNS_USERNAME", "")
|
||||
_ = os.Setenv("ULTRADNS_PASSWORD", "")
|
||||
_ = os.Setenv("ULTRADNS_BASEURL", "")
|
||||
_ = os.Setenv("ULTRADNS_ACCOUNTNAME", "")
|
||||
_ = os.Setenv("ULTRADNS_ENABLE_ACTONPROBE", "true")
|
||||
_, err2 := NewUltraDNSProvider(endpoint.NewDomainFilter([]string{"test-ultradns-provider.com"}), true)
|
||||
assert.NoErrorf(t, err2, "ActOnProbe given value is not working %s", "formatted")
|
||||
}
|
||||
|
||||
// Base64 Bad string decoding scenario
|
||||
func TestNewUltraDNSProvider_Base64DecodeFailcase(t *testing.T) {
|
||||
_ = os.Setenv("ULTRADNS_USERNAME", "")
|
||||
_ = os.Setenv("ULTRADNS_PASSWORD", "12345")
|
||||
_ = os.Setenv("ULTRADNS_BASEURL", "")
|
||||
_ = os.Setenv("ULTRADNS_ACCOUNTNAME", "")
|
||||
_ = os.Setenv("ULTRADNS_ENABLE_ACTONPROBE", "true")
|
||||
_, err := NewUltraDNSProvider(endpoint.NewDomainFilter([]string{"test-ultradns-provider.com"}), true)
|
||||
assert.Errorf(t, err, "Base64 decode should fail in this case %s", "formatted")
|
||||
}
|
||||
|
||||
func TestUltraDNSProvider_PoolConversionCase(t *testing.T) {
|
||||
_, ok := os.LookupEnv("ULTRADNS_INTEGRATION")
|
||||
if !ok {
|
||||
log.Printf("Skipping test")
|
||||
} else {
|
||||
// Creating SBPool Record
|
||||
_ = os.Setenv("ULTRADNS_POOL_TYPE", "sbpool")
|
||||
provider, _ := NewUltraDNSProvider(endpoint.NewDomainFilter([]string{"kubernetes-ultradns-provider-test.com"}), false)
|
||||
changes := &plan.Changes{}
|
||||
changes.Create = []*endpoint.Endpoint{{DNSName: "ttl.kubernetes-ultradns-provider-test.com", Targets: endpoint.Targets{"1.1.1.1", "1.2.3.4"}, RecordType: "A", RecordTTL: 100}}
|
||||
err := provider.ApplyChanges(context.Background(), changes)
|
||||
assert.NoErrorf(t, err, " multiple A record creation with SBPool %s", "formatted")
|
||||
|
||||
resp, _ := provider.client.Do("GET", "zones/kubernetes-ultradns-provider-test.com./rrsets/A/ttl.kubernetes-ultradns-provider-test.com.", nil, udnssdk.RRSetListDTO{})
|
||||
assert.Equal(t, "200 OK", resp.Status)
|
||||
|
||||
// Converting to RD Pool
|
||||
_ = os.Setenv("ULTRADNS_POOL_TYPE", "rdpool")
|
||||
provider, _ = NewUltraDNSProvider(endpoint.NewDomainFilter([]string{"kubernetes-ultradns-provider-test.com"}), false)
|
||||
changes = &plan.Changes{}
|
||||
changes.UpdateNew = []*endpoint.Endpoint{{DNSName: "ttl.kubernetes-ultradns-provider-test.com", Targets: endpoint.Targets{"1.1.1.1", "1.2.3.5"}, RecordType: "A"}}
|
||||
err = provider.ApplyChanges(context.Background(), changes)
|
||||
assert.NoError(t, err)
|
||||
resp, _ = provider.client.Do("GET", "zones/kubernetes-ultradns-provider-test.com./rrsets/A/ttl.kubernetes-ultradns-provider-test.com.", nil, udnssdk.RRSetListDTO{})
|
||||
assert.Equal(t, "200 OK", resp.Status)
|
||||
|
||||
// Converting back to SB Pool
|
||||
_ = os.Setenv("ULTRADNS_POOL_TYPE", "sbpool")
|
||||
provider, _ = NewUltraDNSProvider(endpoint.NewDomainFilter([]string{"kubernetes-ultradns-provider-test.com"}), false)
|
||||
changes = &plan.Changes{}
|
||||
changes.UpdateNew = []*endpoint.Endpoint{{DNSName: "ttl.kubernetes-ultradns-provider-test.com", Targets: endpoint.Targets{"1.1.1.1", "1.2.3.4"}, RecordType: "A"}}
|
||||
err = provider.ApplyChanges(context.Background(), changes)
|
||||
assert.NoError(t, err)
|
||||
resp, _ = provider.client.Do("GET", "zones/kubernetes-ultradns-provider-test.com./rrsets/A/ttl.kubernetes-ultradns-provider-test.com.", nil, udnssdk.RRSetListDTO{})
|
||||
assert.Equal(t, "200 OK", resp.Status)
|
||||
|
||||
// Deleting Record
|
||||
changes = &plan.Changes{}
|
||||
changes.Delete = []*endpoint.Endpoint{{DNSName: "ttl.kubernetes-ultradns-provider-test.com", Targets: endpoint.Targets{"1.1.1.1", "1.2.3.4"}, RecordType: "A"}}
|
||||
err = provider.ApplyChanges(context.Background(), changes)
|
||||
assert.NoError(t, err)
|
||||
resp, _ = provider.client.Do("GET", "zones/kubernetes-ultradns-provider-test.com./rrsets/A/kubernetes-ultradns-provider-test.com.", nil, udnssdk.RRSetListDTO{})
|
||||
assert.Equal(t, "404 Not Found", resp.Status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUltraDNSProvider_DomainFilter(t *testing.T) {
|
||||
_, ok := os.LookupEnv("ULTRADNS_INTEGRATION")
|
||||
if !ok {
|
||||
log.Printf("Skipping test")
|
||||
} else {
|
||||
provider, _ := NewUltraDNSProvider(endpoint.NewDomainFilter([]string{"kubernetes-ultradns-provider-test.com", "kubernetes-ultradns-provider-test.com"}), true)
|
||||
zones, err := provider.Zones(context.Background())
|
||||
assert.Equal(t, "kubernetes-ultradns-provider-test.com.", zones[0].Properties.Name)
|
||||
assert.Equal(t, "kubernetes-ultradns-provider-test.com.", zones[1].Properties.Name)
|
||||
assert.NoErrorf(t, err, " Multiple domain filter failed %s", "formatted")
|
||||
|
||||
provider, _ = NewUltraDNSProvider(endpoint.NewDomainFilter([]string{}), true)
|
||||
zones, err = provider.Zones(context.Background())
|
||||
assert.NoErrorf(t, err, " Multiple domain filter failed %s", "formatted")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestUltraDNSProvider_DomainFiltersZonesFailCase(t *testing.T) {
|
||||
_, ok := os.LookupEnv("ULTRADNS_INTEGRATION")
|
||||
if !ok {
|
||||
log.Printf("Skipping test")
|
||||
} else {
|
||||
provider, _ := NewUltraDNSProvider(endpoint.NewDomainFilter([]string{"kubernetes-ultradns-provider-test.com", "kubernetes-uldsvdsvadvvdsvadvstradns-provider-test.com"}), true)
|
||||
_, err := provider.Zones(context.Background())
|
||||
assert.Errorf(t, err, " Multiple domain filter failed %s", "formatted")
|
||||
}
|
||||
}
|
||||
|
||||
// zones function with domain filter test scenario
|
||||
func TestUltraDNSProvider_DomainFilterZonesMocked(t *testing.T) {
|
||||
mocked := mockUltraDNSZone{}
|
||||
provider := &UltraDNSProvider{
|
||||
client: udnssdk.Client{
|
||||
Zone: &mocked,
|
||||
},
|
||||
domainFilter: endpoint.NewDomainFilter([]string{"test-ultradns-provider.com."}),
|
||||
}
|
||||
|
||||
zoneKey := &udnssdk.ZoneKey{
|
||||
Zone: "test-ultradns-provider.com.",
|
||||
AccountName: "",
|
||||
}
|
||||
|
||||
// When AccountName not given
|
||||
expected, _, _, err := provider.client.Zone.SelectWithOffsetWithLimit(zoneKey, 0, 1000)
|
||||
assert.NoError(t, err)
|
||||
zones, err := provider.Zones(context.Background())
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, reflect.DeepEqual(expected, zones))
|
||||
accountName = "teamrest"
|
||||
// When AccountName is set
|
||||
provider = &UltraDNSProvider{
|
||||
client: udnssdk.Client{
|
||||
Zone: &mocked,
|
||||
},
|
||||
domainFilter: endpoint.NewDomainFilter([]string{"test-ultradns-provider.com."}),
|
||||
}
|
||||
|
||||
zoneKey = &udnssdk.ZoneKey{
|
||||
Zone: "test-ultradns-provider.com.",
|
||||
AccountName: "teamrest",
|
||||
}
|
||||
|
||||
expected, _, _, err = provider.client.Zone.SelectWithOffsetWithLimit(zoneKey, 0, 1000)
|
||||
assert.NoError(t, err)
|
||||
zones, err = provider.Zones(context.Background())
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, reflect.DeepEqual(expected, zones))
|
||||
|
||||
// When zone is not given but account is provided
|
||||
provider = &UltraDNSProvider{
|
||||
client: udnssdk.Client{
|
||||
Zone: &mocked,
|
||||
},
|
||||
}
|
||||
|
||||
zoneKey = &udnssdk.ZoneKey{
|
||||
AccountName: "teamrest",
|
||||
}
|
||||
|
||||
expected, _, _, err = provider.client.Zone.SelectWithOffsetWithLimit(zoneKey, 0, 1000)
|
||||
assert.NoError(t, err)
|
||||
zones, err = provider.Zones(context.Background())
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, reflect.DeepEqual(expected, zones))
|
||||
}
|
@ -26,7 +26,6 @@ const (
|
||||
|
||||
AWSPrefix = "external-dns.alpha.kubernetes.io/aws-"
|
||||
SCWPrefix = "external-dns.alpha.kubernetes.io/scw-"
|
||||
IBMCloudPrefix = "external-dns.alpha.kubernetes.io/ibmcloud-"
|
||||
WebhookPrefix = "external-dns.alpha.kubernetes.io/webhook-"
|
||||
CloudflarePrefix = "external-dns.alpha.kubernetes.io/cloudflare-"
|
||||
|
||||
|
@ -45,12 +45,6 @@ func ProviderSpecificAnnotations(annotations map[string]string) (endpoint.Provid
|
||||
Name: fmt.Sprintf("scw/%s", attr),
|
||||
Value: v,
|
||||
})
|
||||
} else if strings.HasPrefix(k, IBMCloudPrefix) {
|
||||
attr := strings.TrimPrefix(k, IBMCloudPrefix)
|
||||
providerSpecificAnnotations = append(providerSpecificAnnotations, endpoint.ProviderSpecificProperty{
|
||||
Name: fmt.Sprintf("ibmcloud-%s", attr),
|
||||
Value: v,
|
||||
})
|
||||
} else if strings.HasPrefix(k, WebhookPrefix) {
|
||||
// Support for wildcard annotations for webhook providers
|
||||
attr := strings.TrimPrefix(k, WebhookPrefix)
|
||||
|
@ -300,19 +300,6 @@ func TestGetProviderSpecificIdentifierAnnotations(t *testing.T) {
|
||||
},
|
||||
expectedIdentifier: "id1",
|
||||
},
|
||||
{
|
||||
title: "ibmcloud- provider specific annotations are set correctly",
|
||||
annotations: map[string]string{
|
||||
"external-dns.alpha.kubernetes.io/ibmcloud-annotation-1": "value 1",
|
||||
SetIdentifierKey: "id1",
|
||||
"external-dns.alpha.kubernetes.io/ibmcloud-annotation-2": "value 2",
|
||||
},
|
||||
expectedResult: map[string]string{
|
||||
"ibmcloud-annotation-1": "value 1",
|
||||
"ibmcloud-annotation-2": "value 2",
|
||||
},
|
||||
expectedIdentifier: "id1",
|
||||
},
|
||||
{
|
||||
title: "webhook- provider specific annotations are set correctly",
|
||||
annotations: map[string]string{
|
||||
|
Loading…
Reference in New Issue
Block a user