mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2025-08-06 09:36:58 +02:00
make sure that external-dns will create PTR records for records that are already managed by external dns
This commit is contained in:
parent
9a6e004a2d
commit
ae07a2d2cb
@ -159,6 +159,7 @@ spec:
|
|||||||
- --infoblox-wapi-port=443 # (optional) Infoblox WAPI port. The default is "443".
|
- --infoblox-wapi-port=443 # (optional) Infoblox WAPI port. The default is "443".
|
||||||
- --infoblox-wapi-version=2.3.1 # (optional) Infoblox WAPI version. The default is "2.3.1"
|
- --infoblox-wapi-version=2.3.1 # (optional) Infoblox WAPI version. The default is "2.3.1"
|
||||||
- --infoblox-ssl-verify # (optional) Use --no-infoblox-ssl-verify to skip server certificate verification.
|
- --infoblox-ssl-verify # (optional) Use --no-infoblox-ssl-verify to skip server certificate verification.
|
||||||
|
- --infoblox-create-ptr # (optional) Use --infoblox-create-ptr to create a ptr entry in addition to an entry.
|
||||||
env:
|
env:
|
||||||
- name: EXTERNAL_DNS_INFOBLOX_HTTP_POOL_CONNECTIONS
|
- name: EXTERNAL_DNS_INFOBLOX_HTTP_POOL_CONNECTIONS
|
||||||
value: "10" # (optional) Infoblox WAPI request connection pool size. The default is "10".
|
value: "10" # (optional) Infoblox WAPI request connection pool size. The default is "10".
|
||||||
@ -269,3 +270,11 @@ There is also the ability to filter results from the Infoblox zone_auth service
|
|||||||
```
|
```
|
||||||
--infoblox-fqdn-regex=^staging.*test.com$
|
--infoblox-fqdn-regex=^staging.*test.com$
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Infoblox PTR record support
|
||||||
|
|
||||||
|
There is an option to enable PTR records support for infoblox provider. PTR records allow to do reverse dns search. To enable PTR records support, add following into arguments for external-dns:
|
||||||
|
`--infoblox-create-ptr` to allow management of PTR records.
|
||||||
|
You can also add a filter for reverse dns zone to limit PTR records to specific zones only:
|
||||||
|
`--domain-filter=10.196.0.0/16` change this to the reverse zone(s) as defined in your infoblox.
|
||||||
|
Now external-dns will manage PTR records for you.
|
||||||
|
1
go.mod
1
go.mod
@ -10,6 +10,7 @@ require (
|
|||||||
github.com/Azure/go-autorest/autorest/adal v0.9.16
|
github.com/Azure/go-autorest/autorest/adal v0.9.16
|
||||||
github.com/Azure/go-autorest/autorest/to v0.4.0
|
github.com/Azure/go-autorest/autorest/to v0.4.0
|
||||||
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.1.1
|
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.1.1
|
||||||
|
github.com/StackExchange/dnscontrol v0.2.8
|
||||||
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 // indirect
|
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 // indirect
|
||||||
github.com/alecthomas/colour v0.1.0 // indirect
|
github.com/alecthomas/colour v0.1.0 // indirect
|
||||||
github.com/alecthomas/kingpin v2.2.5+incompatible
|
github.com/alecthomas/kingpin v2.2.5+incompatible
|
||||||
|
2
go.sum
2
go.sum
@ -124,6 +124,8 @@ github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:H
|
|||||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||||
github.com/Venafi/vcert/v4 v4.13.1/go.mod h1:Z3sJFoAurFNXPpoSUSHq46aIeHLiGQEMDhprfxlpofQ=
|
github.com/Venafi/vcert/v4 v4.13.1/go.mod h1:Z3sJFoAurFNXPpoSUSHq46aIeHLiGQEMDhprfxlpofQ=
|
||||||
|
github.com/StackExchange/dnscontrol v0.2.8 h1:7jviqDH9cIqRSRpH0UxgmpT7a8CwEhs9mLHBhoYhXo8=
|
||||||
|
github.com/StackExchange/dnscontrol v0.2.8/go.mod h1:BH+5nX50JxHDdb3+AD/z/UfYMCc7iaqEkRtQ+NjcFGE=
|
||||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||||
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
||||||
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
transform "github.com/StackExchange/dnscontrol/pkg/transform"
|
||||||
ibclient "github.com/infobloxopen/infoblox-go-client"
|
ibclient "github.com/infobloxopen/infoblox-go-client"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
@ -34,6 +35,11 @@ import (
|
|||||||
"sigs.k8s.io/external-dns/provider"
|
"sigs.k8s.io/external-dns/provider"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// provider specific key to track if PTR record was already created or not for A records
|
||||||
|
providerSpecificInfobloxPtrRecord = "infoblox-ptr-record-exists"
|
||||||
|
)
|
||||||
|
|
||||||
// InfobloxConfig clarifies the method signature
|
// InfobloxConfig clarifies the method signature
|
||||||
type InfobloxConfig struct {
|
type InfobloxConfig struct {
|
||||||
DomainFilter endpoint.DomainFilter
|
DomainFilter endpoint.DomainFilter
|
||||||
@ -174,6 +180,9 @@ func (p *InfobloxProvider) Records(ctx context.Context) (endpoints []*endpoint.E
|
|||||||
}
|
}
|
||||||
for _, res := range resA {
|
for _, res := range resA {
|
||||||
newEndpoint := endpoint.NewEndpoint(res.Name, endpoint.RecordTypeA, res.Ipv4Addr)
|
newEndpoint := endpoint.NewEndpoint(res.Name, endpoint.RecordTypeA, res.Ipv4Addr)
|
||||||
|
if p.createPTR {
|
||||||
|
newEndpoint.WithProviderSpecific(providerSpecificInfobloxPtrRecord, "false")
|
||||||
|
}
|
||||||
// Check if endpoint already exists and add to existing endpoint if it does
|
// Check if endpoint already exists and add to existing endpoint if it does
|
||||||
foundExisting := false
|
foundExisting := false
|
||||||
for _, ep := range endpoints {
|
for _, ep := range endpoints {
|
||||||
@ -207,7 +216,13 @@ func (p *InfobloxProvider) Records(ctx context.Context) (endpoints []*endpoint.E
|
|||||||
}
|
}
|
||||||
for _, res := range resH {
|
for _, res := range resH {
|
||||||
for _, ip := range res.Ipv4Addrs {
|
for _, ip := range res.Ipv4Addrs {
|
||||||
endpoints = append(endpoints, endpoint.NewEndpoint(res.Name, endpoint.RecordTypeA, ip.Ipv4Addr))
|
// host record is an abstraction in infoblox that combines A and PTR records
|
||||||
|
// for any host record we already should have a PTR record in infoblox, so mark it as created
|
||||||
|
newEndpoint := endpoint.NewEndpoint(res.Name, endpoint.RecordTypeA, ip.Ipv4Addr)
|
||||||
|
if p.createPTR {
|
||||||
|
newEndpoint.WithProviderSpecific(providerSpecificInfobloxPtrRecord, "true")
|
||||||
|
}
|
||||||
|
endpoints = append(endpoints, newEndpoint)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,19 +242,25 @@ func (p *InfobloxProvider) Records(ctx context.Context) (endpoints []*endpoint.E
|
|||||||
}
|
}
|
||||||
|
|
||||||
if p.createPTR {
|
if p.createPTR {
|
||||||
var resP []ibclient.RecordPTR
|
// infoblox doesn't accept reverse zone's fqdn, and instead expects .in-addr.arpa zone
|
||||||
objP := ibclient.NewRecordPTR(
|
// so convert our zone fqdn (if it is a correct cidr block) into in-addr.arpa address and pass that into infoblox
|
||||||
ibclient.RecordPTR{
|
// example: 10.196.38.0/24 becomes 38.196.10.in-addr.arpa
|
||||||
Zone: zone.Fqdn,
|
arpaZone, err := transform.ReverseDomainName(zone.Fqdn)
|
||||||
View: p.view,
|
if err == nil {
|
||||||
},
|
var resP []ibclient.RecordPTR
|
||||||
)
|
objP := ibclient.NewRecordPTR(
|
||||||
err = p.client.GetObject(objP, "", &resP)
|
ibclient.RecordPTR{
|
||||||
if err != nil {
|
Zone: arpaZone,
|
||||||
return nil, fmt.Errorf("could not fetch PTR records from zone '%s': %s", zone.Fqdn, err)
|
View: p.view,
|
||||||
}
|
},
|
||||||
for _, res := range resP {
|
)
|
||||||
endpoints = append(endpoints, endpoint.NewEndpoint(res.PtrdName, endpoint.RecordTypePTR, res.Ipv4Addr))
|
err = p.client.GetObject(objP, "", &resP)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not fetch PTR records from zone '%s': %s", zone.Fqdn, err)
|
||||||
|
}
|
||||||
|
for _, res := range resP {
|
||||||
|
endpoints = append(endpoints, endpoint.NewEndpoint(res.PtrdName, endpoint.RecordTypePTR, res.Ipv4Addr))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,10 +284,66 @@ func (p *InfobloxProvider) Records(ctx context.Context) (endpoints []*endpoint.E
|
|||||||
endpoints = append(endpoints, endpoint.NewEndpoint(res.Name, endpoint.RecordTypeTXT, res.Text))
|
endpoints = append(endpoints, endpoint.NewEndpoint(res.Name, endpoint.RecordTypeTXT, res.Text))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update A records that have PTR record created for them already
|
||||||
|
if p.createPTR {
|
||||||
|
// save all ptr records into map for a quick look up
|
||||||
|
ptrRecordsMap := make(map[string]bool)
|
||||||
|
for _, ptrRecord := range endpoints {
|
||||||
|
if ptrRecord.RecordType != endpoint.RecordTypePTR {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ptrRecordsMap[ptrRecord.DNSName] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range endpoints {
|
||||||
|
if endpoints[i].RecordType != endpoint.RecordTypeA {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// if PTR record already exists for A record, then mark it as such
|
||||||
|
if ptrRecordsMap[endpoints[i].DNSName] {
|
||||||
|
found := false
|
||||||
|
for j := range endpoints[i].ProviderSpecific {
|
||||||
|
if endpoints[i].ProviderSpecific[j].Name == providerSpecificInfobloxPtrRecord {
|
||||||
|
endpoints[i].ProviderSpecific[j].Value = "true"
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
endpoints[i].WithProviderSpecific(providerSpecificInfobloxPtrRecord, "true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
logrus.Debugf("fetched %d records from infoblox", len(endpoints))
|
logrus.Debugf("fetched %d records from infoblox", len(endpoints))
|
||||||
return endpoints, nil
|
return endpoints, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *InfobloxProvider) AdjustEndpoints(endpoints []*endpoint.Endpoint) []*endpoint.Endpoint {
|
||||||
|
if !p.createPTR {
|
||||||
|
return endpoints
|
||||||
|
}
|
||||||
|
|
||||||
|
// for all A records, we want to create PTR records
|
||||||
|
// so add provider specific property to track if the record was created or not
|
||||||
|
for i := range endpoints {
|
||||||
|
if endpoints[i].RecordType == endpoint.RecordTypeA {
|
||||||
|
found := false
|
||||||
|
for j := range endpoints[i].ProviderSpecific {
|
||||||
|
if endpoints[i].ProviderSpecific[j].Name == providerSpecificInfobloxPtrRecord {
|
||||||
|
endpoints[i].ProviderSpecific[j].Value = "true"
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
endpoints[i].WithProviderSpecific(providerSpecificInfobloxPtrRecord, "true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return endpoints
|
||||||
|
}
|
||||||
|
|
||||||
// ApplyChanges applies the given changes.
|
// ApplyChanges applies the given changes.
|
||||||
func (p *InfobloxProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error {
|
func (p *InfobloxProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error {
|
||||||
zones, err := p.zones()
|
zones, err := p.zones()
|
||||||
@ -418,7 +495,7 @@ func (p *InfobloxProvider) recordSet(ep *endpoint.Endpoint, getObject bool, targ
|
|||||||
obj := ibclient.NewRecordPTR(
|
obj := ibclient.NewRecordPTR(
|
||||||
ibclient.RecordPTR{
|
ibclient.RecordPTR{
|
||||||
PtrdName: ep.DNSName,
|
PtrdName: ep.DNSName,
|
||||||
Ipv4Addr: ep.Targets[0],
|
Ipv4Addr: ep.Targets[targetIndex],
|
||||||
View: p.view,
|
View: p.view,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -91,7 +91,6 @@ func (client *mockIBConnector) CreateObject(obj ibclient.IBObject) (ref string,
|
|||||||
obj.(*ibclient.RecordTXT).Ref = ref
|
obj.(*ibclient.RecordTXT).Ref = ref
|
||||||
ref = fmt.Sprintf("%s/%s:%s/default", obj.ObjectType(), base64.StdEncoding.EncodeToString([]byte(obj.(*ibclient.RecordTXT).Name)), obj.(*ibclient.RecordTXT).Name)
|
ref = fmt.Sprintf("%s/%s:%s/default", obj.ObjectType(), base64.StdEncoding.EncodeToString([]byte(obj.(*ibclient.RecordTXT).Name)), obj.(*ibclient.RecordTXT).Name)
|
||||||
case "record:ptr":
|
case "record:ptr":
|
||||||
fmt.Printf("create ptr record\n")
|
|
||||||
client.createdEndpoints = append(
|
client.createdEndpoints = append(
|
||||||
client.createdEndpoints,
|
client.createdEndpoints,
|
||||||
endpoint.NewEndpoint(
|
endpoint.NewEndpoint(
|
||||||
@ -459,7 +458,38 @@ func TestInfobloxRecords(t *testing.T) {
|
|||||||
validateEndpoints(t, actual, expected)
|
validateEndpoints(t, actual, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestInfobloxAdjustEndpoints(t *testing.T) {
|
||||||
|
client := mockIBConnector{
|
||||||
|
mockInfobloxZones: &[]ibclient.ZoneAuth{
|
||||||
|
createMockInfobloxZone("example.com"),
|
||||||
|
createMockInfobloxZone("other.com"),
|
||||||
|
},
|
||||||
|
mockInfobloxObjects: &[]ibclient.IBObject{
|
||||||
|
createMockInfobloxObject("example.com", endpoint.RecordTypeA, "123.123.123.122"),
|
||||||
|
createMockInfobloxObject("example.com", endpoint.RecordTypeTXT, "heritage=external-dns,external-dns/owner=default"),
|
||||||
|
createMockInfobloxObject("hack.example.com", endpoint.RecordTypeCNAME, "cerberus.infoblox.com"),
|
||||||
|
createMockInfobloxObject("host.example.com", "HOST", "125.1.1.1"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
provider := newInfobloxProvider(endpoint.NewDomainFilter([]string{"example.com"}), provider.NewZoneIDFilter([]string{""}), true, true, &client)
|
||||||
|
actual, err := provider.Records(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
provider.AdjustEndpoints(actual)
|
||||||
|
|
||||||
|
expected := []*endpoint.Endpoint{
|
||||||
|
endpoint.NewEndpoint("example.com", endpoint.RecordTypeA, "123.123.123.122").WithProviderSpecific(providerSpecificInfobloxPtrRecord, "true"),
|
||||||
|
endpoint.NewEndpoint("example.com", endpoint.RecordTypeTXT, "\"heritage=external-dns,external-dns/owner=default\""),
|
||||||
|
endpoint.NewEndpoint("hack.example.com", endpoint.RecordTypeCNAME, "cerberus.infoblox.com"),
|
||||||
|
endpoint.NewEndpoint("host.example.com", endpoint.RecordTypeA, "125.1.1.1").WithProviderSpecific(providerSpecificInfobloxPtrRecord, "true"),
|
||||||
|
}
|
||||||
|
validateEndpoints(t, actual, expected)
|
||||||
|
}
|
||||||
|
|
||||||
func TestInfobloxRecordsReverse(t *testing.T) {
|
func TestInfobloxRecordsReverse(t *testing.T) {
|
||||||
|
|
||||||
client := mockIBConnector{
|
client := mockIBConnector{
|
||||||
mockInfobloxZones: &[]ibclient.ZoneAuth{
|
mockInfobloxZones: &[]ibclient.ZoneAuth{
|
||||||
createMockInfobloxZone("10.0.0.0/24"),
|
createMockInfobloxZone("10.0.0.0/24"),
|
||||||
|
Loading…
Reference in New Issue
Block a user