external-dns/provider/infoblox/infoblox_test.go

758 lines
27 KiB
Go

/*
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 infoblox
import (
"context"
"encoding/base64"
"fmt"
"regexp"
"strings"
"testing"
ibclient "github.com/infobloxopen/infoblox-go-client"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/external-dns/endpoint"
"sigs.k8s.io/external-dns/internal/testutils"
"sigs.k8s.io/external-dns/plan"
"sigs.k8s.io/external-dns/provider"
)
type mockIBConnector struct {
mockInfobloxZones *[]ibclient.ZoneAuth
mockInfobloxObjects *[]ibclient.IBObject
createdEndpoints []*endpoint.Endpoint
deletedEndpoints []*endpoint.Endpoint
updatedEndpoints []*endpoint.Endpoint
}
func (client *mockIBConnector) CreateObject(obj ibclient.IBObject) (ref string, err error) {
switch obj.ObjectType() {
case "record:a":
client.createdEndpoints = append(
client.createdEndpoints,
endpoint.NewEndpoint(
obj.(*ibclient.RecordA).Name,
endpoint.RecordTypeA,
obj.(*ibclient.RecordA).Ipv4Addr,
),
)
ref = fmt.Sprintf("%s/%s:%s/default", obj.ObjectType(), base64.StdEncoding.EncodeToString([]byte(obj.(*ibclient.RecordA).Name)), obj.(*ibclient.RecordA).Name)
obj.(*ibclient.RecordA).Ref = ref
case "record:cname":
client.createdEndpoints = append(
client.createdEndpoints,
endpoint.NewEndpoint(
obj.(*ibclient.RecordCNAME).Name,
endpoint.RecordTypeCNAME,
obj.(*ibclient.RecordCNAME).Canonical,
),
)
ref = fmt.Sprintf("%s/%s:%s/default", obj.ObjectType(), base64.StdEncoding.EncodeToString([]byte(obj.(*ibclient.RecordCNAME).Name)), obj.(*ibclient.RecordCNAME).Name)
obj.(*ibclient.RecordCNAME).Ref = ref
case "record:host":
for _, i := range obj.(*ibclient.HostRecord).Ipv4Addrs {
client.createdEndpoints = append(
client.createdEndpoints,
endpoint.NewEndpoint(
obj.(*ibclient.HostRecord).Name,
endpoint.RecordTypeA,
i.Ipv4Addr,
),
)
}
ref = fmt.Sprintf("%s/%s:%s/default", obj.ObjectType(), base64.StdEncoding.EncodeToString([]byte(obj.(*ibclient.HostRecord).Name)), obj.(*ibclient.HostRecord).Name)
obj.(*ibclient.HostRecord).Ref = ref
case "record:txt":
client.createdEndpoints = append(
client.createdEndpoints,
endpoint.NewEndpoint(
obj.(*ibclient.RecordTXT).Name,
endpoint.RecordTypeTXT,
obj.(*ibclient.RecordTXT).Text,
),
)
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)
case "record:ptr":
client.createdEndpoints = append(
client.createdEndpoints,
endpoint.NewEndpoint(
obj.(*ibclient.RecordPTR).PtrdName,
endpoint.RecordTypePTR,
obj.(*ibclient.RecordPTR).Ipv4Addr,
),
)
obj.(*ibclient.RecordPTR).Ref = ref
reverseAddr, err := dns.ReverseAddr(obj.(*ibclient.RecordPTR).Ipv4Addr)
if err != nil {
return ref, fmt.Errorf("unable to create reverse addr from %s", obj.(*ibclient.RecordPTR).Ipv4Addr)
}
ref = fmt.Sprintf("%s/%s:%s/default", obj.ObjectType(), base64.StdEncoding.EncodeToString([]byte(obj.(*ibclient.RecordPTR).PtrdName)), reverseAddr)
}
*client.mockInfobloxObjects = append(
*client.mockInfobloxObjects,
obj,
)
return ref, nil
}
func (client *mockIBConnector) GetObject(obj ibclient.IBObject, ref string, res interface{}) (err error) {
switch obj.ObjectType() {
case "record:a":
var result []ibclient.RecordA
for _, object := range *client.mockInfobloxObjects {
if object.ObjectType() == "record:a" {
if ref != "" &&
ref != object.(*ibclient.RecordA).Ref {
continue
}
if obj.(*ibclient.RecordA).Name != "" &&
obj.(*ibclient.RecordA).Name != object.(*ibclient.RecordA).Name {
continue
}
result = append(result, *object.(*ibclient.RecordA))
}
}
*res.(*[]ibclient.RecordA) = result
case "record:cname":
var result []ibclient.RecordCNAME
for _, object := range *client.mockInfobloxObjects {
if object.ObjectType() == "record:cname" {
if ref != "" &&
ref != object.(*ibclient.RecordCNAME).Ref {
continue
}
if obj.(*ibclient.RecordCNAME).Name != "" &&
obj.(*ibclient.RecordCNAME).Name != object.(*ibclient.RecordCNAME).Name {
continue
}
result = append(result, *object.(*ibclient.RecordCNAME))
}
}
*res.(*[]ibclient.RecordCNAME) = result
case "record:host":
var result []ibclient.HostRecord
for _, object := range *client.mockInfobloxObjects {
if object.ObjectType() == "record:host" {
if ref != "" &&
ref != object.(*ibclient.HostRecord).Ref {
continue
}
if obj.(*ibclient.HostRecord).Name != "" &&
obj.(*ibclient.HostRecord).Name != object.(*ibclient.HostRecord).Name {
continue
}
result = append(result, *object.(*ibclient.HostRecord))
}
}
*res.(*[]ibclient.HostRecord) = result
case "record:txt":
var result []ibclient.RecordTXT
for _, object := range *client.mockInfobloxObjects {
if object.ObjectType() == "record:txt" {
if ref != "" &&
ref != object.(*ibclient.RecordTXT).Ref {
continue
}
if obj.(*ibclient.RecordTXT).Name != "" &&
obj.(*ibclient.RecordTXT).Name != object.(*ibclient.RecordTXT).Name {
continue
}
result = append(result, *object.(*ibclient.RecordTXT))
}
}
*res.(*[]ibclient.RecordTXT) = result
case "record:ptr":
var result []ibclient.RecordPTR
for _, object := range *client.mockInfobloxObjects {
if object.ObjectType() == "record:ptr" {
if ref != "" &&
ref != object.(*ibclient.RecordPTR).Ref {
continue
}
if obj.(*ibclient.RecordPTR).PtrdName != "" &&
obj.(*ibclient.RecordPTR).PtrdName != object.(*ibclient.RecordPTR).PtrdName {
continue
}
result = append(result, *object.(*ibclient.RecordPTR))
}
}
*res.(*[]ibclient.RecordPTR) = result
case "zone_auth":
*res.(*[]ibclient.ZoneAuth) = *client.mockInfobloxZones
}
return
}
func (client *mockIBConnector) DeleteObject(ref string) (refRes string, err error) {
re := regexp.MustCompile(`([^/]+)/[^:]+:([^/]+)/default`)
result := re.FindStringSubmatch(ref)
switch result[1] {
case "record:a":
var records []ibclient.RecordA
obj := ibclient.NewRecordA(
ibclient.RecordA{
Name: result[2],
},
)
client.GetObject(obj, ref, &records)
for _, record := range records {
client.deletedEndpoints = append(
client.deletedEndpoints,
endpoint.NewEndpoint(
record.Name,
endpoint.RecordTypeA,
"",
),
)
}
case "record:cname":
var records []ibclient.RecordCNAME
obj := ibclient.NewRecordCNAME(
ibclient.RecordCNAME{
Name: result[2],
},
)
client.GetObject(obj, ref, &records)
for _, record := range records {
client.deletedEndpoints = append(
client.deletedEndpoints,
endpoint.NewEndpoint(
record.Name,
endpoint.RecordTypeCNAME,
"",
),
)
}
case "record:host":
var records []ibclient.HostRecord
obj := ibclient.NewHostRecord(
ibclient.HostRecord{
Name: result[2],
},
)
client.GetObject(obj, ref, &records)
for _, record := range records {
client.deletedEndpoints = append(
client.deletedEndpoints,
endpoint.NewEndpoint(
record.Name,
endpoint.RecordTypeA,
"",
),
)
}
case "record:txt":
var records []ibclient.RecordTXT
obj := ibclient.NewRecordTXT(
ibclient.RecordTXT{
Name: result[2],
},
)
client.GetObject(obj, ref, &records)
for _, record := range records {
client.deletedEndpoints = append(
client.deletedEndpoints,
endpoint.NewEndpoint(
record.Name,
endpoint.RecordTypeTXT,
"",
),
)
}
case "record:ptr":
var records []ibclient.RecordPTR
obj := ibclient.NewRecordPTR(
ibclient.RecordPTR{
Name: result[2],
},
)
client.GetObject(obj, ref, &records)
for _, record := range records {
client.deletedEndpoints = append(
client.deletedEndpoints,
endpoint.NewEndpoint(
record.PtrdName,
endpoint.RecordTypePTR,
"",
),
)
}
}
return "", nil
}
func (client *mockIBConnector) UpdateObject(obj ibclient.IBObject, ref string) (refRes string, err error) {
switch obj.ObjectType() {
case "record:a":
client.updatedEndpoints = append(
client.updatedEndpoints,
endpoint.NewEndpoint(
obj.(*ibclient.RecordA).Name,
obj.(*ibclient.RecordA).Ipv4Addr,
endpoint.RecordTypeA,
),
)
case "record:cname":
client.updatedEndpoints = append(
client.updatedEndpoints,
endpoint.NewEndpoint(
obj.(*ibclient.RecordCNAME).Name,
obj.(*ibclient.RecordCNAME).Canonical,
endpoint.RecordTypeCNAME,
),
)
case "record:host":
for _, i := range obj.(*ibclient.HostRecord).Ipv4Addrs {
client.updatedEndpoints = append(
client.updatedEndpoints,
endpoint.NewEndpoint(
obj.(*ibclient.HostRecord).Name,
i.Ipv4Addr,
endpoint.RecordTypeA,
),
)
}
case "record:txt":
client.updatedEndpoints = append(
client.updatedEndpoints,
endpoint.NewEndpoint(
obj.(*ibclient.RecordTXT).Name,
obj.(*ibclient.RecordTXT).Text,
endpoint.RecordTypeTXT,
),
)
}
return "", nil
}
func createMockInfobloxZone(fqdn string) ibclient.ZoneAuth {
return ibclient.ZoneAuth{
Fqdn: fqdn,
}
}
func createMockInfobloxObject(name, recordType, value string) ibclient.IBObject {
ref := fmt.Sprintf("record:%s/%s:%s/default", strings.ToLower(recordType), base64.StdEncoding.EncodeToString([]byte(name)), name)
switch recordType {
case endpoint.RecordTypeA:
return ibclient.NewRecordA(
ibclient.RecordA{
Ref: ref,
Name: name,
Ipv4Addr: value,
},
)
case endpoint.RecordTypeCNAME:
return ibclient.NewRecordCNAME(
ibclient.RecordCNAME{
Ref: ref,
Name: name,
Canonical: value,
},
)
case endpoint.RecordTypeTXT:
return ibclient.NewRecordTXT(
ibclient.RecordTXT{
Ref: ref,
Name: name,
Text: value,
},
)
case "HOST":
return ibclient.NewHostRecord(
ibclient.HostRecord{
Ref: ref,
Name: name,
Ipv4Addrs: []ibclient.HostRecordIpv4Addr{
{
Ipv4Addr: value,
},
},
},
)
case endpoint.RecordTypePTR:
return ibclient.NewRecordPTR(
ibclient.RecordPTR{
Ref: ref,
PtrdName: name,
Ipv4Addr: value,
},
)
}
return nil
}
func newInfobloxProvider(domainFilter endpoint.DomainFilter, zoneIDFilter provider.ZoneIDFilter, dryRun bool, createPTR bool, client ibclient.IBConnector) *InfobloxProvider {
return &InfobloxProvider{
client: client,
domainFilter: domainFilter,
zoneIDFilter: zoneIDFilter,
dryRun: dryRun,
createPTR: createPTR,
}
}
func TestInfobloxRecords(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("nginx.example.com", endpoint.RecordTypeA, "123.123.123.123"),
createMockInfobloxObject("nginx.example.com", endpoint.RecordTypeTXT, "heritage=external-dns,external-dns/owner=default"),
createMockInfobloxObject("whitespace.example.com", endpoint.RecordTypeA, "123.123.123.124"),
createMockInfobloxObject("whitespace.example.com", endpoint.RecordTypeTXT, "heritage=external-dns,external-dns/owner=white space"),
createMockInfobloxObject("hack.example.com", endpoint.RecordTypeCNAME, "cerberus.infoblox.com"),
createMockInfobloxObject("multiple.example.com", endpoint.RecordTypeA, "123.123.123.122"),
createMockInfobloxObject("multiple.example.com", endpoint.RecordTypeA, "123.123.123.121"),
createMockInfobloxObject("multiple.example.com", endpoint.RecordTypeTXT, "heritage=external-dns,external-dns/owner=default"),
createMockInfobloxObject("existing.example.com", endpoint.RecordTypeA, "124.1.1.1"),
createMockInfobloxObject("existing.example.com", endpoint.RecordTypeA, "124.1.1.2"),
createMockInfobloxObject("existing.example.com", endpoint.RecordTypeTXT, "heritage=external-dns,external-dns/owner=existing"),
createMockInfobloxObject("host.example.com", "HOST", "125.1.1.1"),
},
}
provider := newInfobloxProvider(endpoint.NewDomainFilter([]string{"example.com"}), provider.NewZoneIDFilter([]string{""}), true, false, &client)
actual, err := provider.Records(context.Background())
if err != nil {
t.Fatal(err)
}
expected := []*endpoint.Endpoint{
endpoint.NewEndpoint("example.com", endpoint.RecordTypeA, "123.123.123.122"),
endpoint.NewEndpoint("example.com", endpoint.RecordTypeTXT, "\"heritage=external-dns,external-dns/owner=default\""),
endpoint.NewEndpoint("nginx.example.com", endpoint.RecordTypeA, "123.123.123.123"),
endpoint.NewEndpoint("nginx.example.com", endpoint.RecordTypeTXT, "\"heritage=external-dns,external-dns/owner=default\""),
endpoint.NewEndpoint("whitespace.example.com", endpoint.RecordTypeA, "123.123.123.124"),
endpoint.NewEndpoint("whitespace.example.com", endpoint.RecordTypeTXT, "\"heritage=external-dns,external-dns/owner=white space\""),
endpoint.NewEndpoint("hack.example.com", endpoint.RecordTypeCNAME, "cerberus.infoblox.com"),
endpoint.NewEndpoint("multiple.example.com", endpoint.RecordTypeA, "123.123.123.122", "123.123.123.121"),
endpoint.NewEndpoint("multiple.example.com", endpoint.RecordTypeTXT, "\"heritage=external-dns,external-dns/owner=default\""),
endpoint.NewEndpoint("existing.example.com", endpoint.RecordTypeA, "124.1.1.1", "124.1.1.2"),
endpoint.NewEndpoint("existing.example.com", endpoint.RecordTypeTXT, "\"heritage=external-dns,external-dns/owner=existing\""),
endpoint.NewEndpoint("host.example.com", endpoint.RecordTypeA, "125.1.1.1"),
}
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) {
client := mockIBConnector{
mockInfobloxZones: &[]ibclient.ZoneAuth{
createMockInfobloxZone("10.0.0.0/24"),
createMockInfobloxZone("10.0.1.0/24"),
},
mockInfobloxObjects: &[]ibclient.IBObject{
createMockInfobloxObject("example.com", endpoint.RecordTypePTR, "10.0.0.1"),
createMockInfobloxObject("example2.com", endpoint.RecordTypePTR, "10.0.0.2"),
},
}
provider := newInfobloxProvider(endpoint.NewDomainFilter([]string{"10.0.0.0/24"}), provider.NewZoneIDFilter([]string{""}), true, true, &client)
actual, err := provider.Records(context.Background())
if err != nil {
t.Fatal(err)
}
expected := []*endpoint.Endpoint{
endpoint.NewEndpoint("example.com", endpoint.RecordTypePTR, "10.0.0.1"),
endpoint.NewEndpoint("example2.com", endpoint.RecordTypePTR, "10.0.0.2"),
}
validateEndpoints(t, actual, expected)
}
func TestInfobloxApplyChanges(t *testing.T) {
client := mockIBConnector{}
testInfobloxApplyChangesInternal(t, false, false, &client)
validateEndpoints(t, client.createdEndpoints, []*endpoint.Endpoint{
endpoint.NewEndpoint("example.com", endpoint.RecordTypeA, "1.2.3.4"),
endpoint.NewEndpoint("example.com", endpoint.RecordTypeTXT, "tag"),
endpoint.NewEndpoint("foo.example.com", endpoint.RecordTypeA, "1.2.3.4"),
endpoint.NewEndpoint("foo.example.com", endpoint.RecordTypeTXT, "tag"),
endpoint.NewEndpoint("bar.example.com", endpoint.RecordTypeCNAME, "other.com"),
endpoint.NewEndpoint("bar.example.com", endpoint.RecordTypeTXT, "tag"),
endpoint.NewEndpoint("other.com", endpoint.RecordTypeA, "5.6.7.8"),
endpoint.NewEndpoint("other.com", endpoint.RecordTypeTXT, "tag"),
endpoint.NewEndpoint("new.example.com", endpoint.RecordTypeA, "111.222.111.222"),
endpoint.NewEndpoint("newcname.example.com", endpoint.RecordTypeCNAME, "other.com"),
endpoint.NewEndpoint("multiple.example.com", endpoint.RecordTypeA, "1.2.3.4,3.4.5.6,8.9.10.11"),
endpoint.NewEndpoint("multiple.example.com", endpoint.RecordTypeTXT, "tag-multiple-A-records"),
})
validateEndpoints(t, client.deletedEndpoints, []*endpoint.Endpoint{
endpoint.NewEndpoint("old.example.com", endpoint.RecordTypeA, ""),
endpoint.NewEndpoint("oldcname.example.com", endpoint.RecordTypeCNAME, ""),
endpoint.NewEndpoint("deleted.example.com", endpoint.RecordTypeA, ""),
endpoint.NewEndpoint("deletedcname.example.com", endpoint.RecordTypeCNAME, ""),
})
validateEndpoints(t, client.updatedEndpoints, []*endpoint.Endpoint{})
}
func TestInfobloxApplyChangesReverse(t *testing.T) {
client := mockIBConnector{}
testInfobloxApplyChangesInternal(t, false, true, &client)
validateEndpoints(t, client.createdEndpoints, []*endpoint.Endpoint{
endpoint.NewEndpoint("example.com", endpoint.RecordTypeA, "1.2.3.4"),
endpoint.NewEndpoint("example.com", endpoint.RecordTypePTR, "1.2.3.4"),
endpoint.NewEndpoint("example.com", endpoint.RecordTypeTXT, "tag"),
endpoint.NewEndpoint("foo.example.com", endpoint.RecordTypeA, "1.2.3.4"),
endpoint.NewEndpoint("foo.example.com", endpoint.RecordTypePTR, "1.2.3.4"),
endpoint.NewEndpoint("foo.example.com", endpoint.RecordTypeTXT, "tag"),
endpoint.NewEndpoint("bar.example.com", endpoint.RecordTypeCNAME, "other.com"),
endpoint.NewEndpoint("bar.example.com", endpoint.RecordTypeTXT, "tag"),
endpoint.NewEndpoint("other.com", endpoint.RecordTypeA, "5.6.7.8"),
endpoint.NewEndpoint("other.com", endpoint.RecordTypeTXT, "tag"),
endpoint.NewEndpoint("new.example.com", endpoint.RecordTypeA, "111.222.111.222"),
endpoint.NewEndpoint("newcname.example.com", endpoint.RecordTypeCNAME, "other.com"),
endpoint.NewEndpoint("multiple.example.com", endpoint.RecordTypeA, "1.2.3.4,3.4.5.6,8.9.10.11"),
endpoint.NewEndpoint("multiple.example.com", endpoint.RecordTypeTXT, "tag-multiple-A-records"),
})
validateEndpoints(t, client.deletedEndpoints, []*endpoint.Endpoint{
endpoint.NewEndpoint("old.example.com", endpoint.RecordTypeA, ""),
endpoint.NewEndpoint("oldcname.example.com", endpoint.RecordTypeCNAME, ""),
endpoint.NewEndpoint("deleted.example.com", endpoint.RecordTypeA, ""),
endpoint.NewEndpoint("deleted.example.com", endpoint.RecordTypePTR, ""),
endpoint.NewEndpoint("deletedcname.example.com", endpoint.RecordTypeCNAME, ""),
})
validateEndpoints(t, client.updatedEndpoints, []*endpoint.Endpoint{})
}
func TestInfobloxApplyChangesDryRun(t *testing.T) {
client := mockIBConnector{
mockInfobloxObjects: &[]ibclient.IBObject{},
}
testInfobloxApplyChangesInternal(t, true, false, &client)
validateEndpoints(t, client.createdEndpoints, []*endpoint.Endpoint{})
validateEndpoints(t, client.deletedEndpoints, []*endpoint.Endpoint{})
validateEndpoints(t, client.updatedEndpoints, []*endpoint.Endpoint{})
}
func testInfobloxApplyChangesInternal(t *testing.T, dryRun, createPTR bool, client ibclient.IBConnector) {
client.(*mockIBConnector).mockInfobloxZones = &[]ibclient.ZoneAuth{
createMockInfobloxZone("example.com"),
createMockInfobloxZone("other.com"),
createMockInfobloxZone("1.2.3.0/24"),
}
client.(*mockIBConnector).mockInfobloxObjects = &[]ibclient.IBObject{
createMockInfobloxObject("deleted.example.com", endpoint.RecordTypeA, "121.212.121.212"),
createMockInfobloxObject("deleted.example.com", endpoint.RecordTypeTXT, "test-deleting-txt"),
createMockInfobloxObject("deleted.example.com", endpoint.RecordTypePTR, "121.212.121.212"),
createMockInfobloxObject("deletedcname.example.com", endpoint.RecordTypeCNAME, "other.com"),
createMockInfobloxObject("old.example.com", endpoint.RecordTypeA, "121.212.121.212"),
createMockInfobloxObject("oldcname.example.com", endpoint.RecordTypeCNAME, "other.com"),
}
provider := newInfobloxProvider(
endpoint.NewDomainFilter([]string{""}),
provider.NewZoneIDFilter([]string{""}),
dryRun,
createPTR,
client,
)
createRecords := []*endpoint.Endpoint{
endpoint.NewEndpoint("example.com", endpoint.RecordTypeA, "1.2.3.4"),
endpoint.NewEndpoint("example.com", endpoint.RecordTypeTXT, "tag"),
endpoint.NewEndpoint("foo.example.com", endpoint.RecordTypeA, "1.2.3.4"),
endpoint.NewEndpoint("foo.example.com", endpoint.RecordTypeTXT, "tag"),
endpoint.NewEndpoint("bar.example.com", endpoint.RecordTypeCNAME, "other.com"),
endpoint.NewEndpoint("bar.example.com", endpoint.RecordTypeTXT, "tag"),
endpoint.NewEndpoint("other.com", endpoint.RecordTypeA, "5.6.7.8"),
endpoint.NewEndpoint("other.com", endpoint.RecordTypeTXT, "tag"),
endpoint.NewEndpoint("nope.com", endpoint.RecordTypeA, "4.4.4.4"),
endpoint.NewEndpoint("nope.com", endpoint.RecordTypeTXT, "tag"),
endpoint.NewEndpoint("multiple.example.com", endpoint.RecordTypeA, "1.2.3.4,3.4.5.6,8.9.10.11"),
endpoint.NewEndpoint("multiple.example.com", endpoint.RecordTypeTXT, "tag-multiple-A-records"),
}
updateOldRecords := []*endpoint.Endpoint{
endpoint.NewEndpoint("old.example.com", endpoint.RecordTypeA, "121.212.121.212"),
endpoint.NewEndpoint("oldcname.example.com", endpoint.RecordTypeCNAME, "other.com"),
endpoint.NewEndpoint("old.nope.com", endpoint.RecordTypeA, "121.212.121.212"),
}
updateNewRecords := []*endpoint.Endpoint{
endpoint.NewEndpoint("new.example.com", endpoint.RecordTypeA, "111.222.111.222"),
endpoint.NewEndpoint("newcname.example.com", endpoint.RecordTypeCNAME, "other.com"),
endpoint.NewEndpoint("new.nope.com", endpoint.RecordTypeA, "222.111.222.111"),
}
deleteRecords := []*endpoint.Endpoint{
endpoint.NewEndpoint("deleted.example.com", endpoint.RecordTypeA, "121.212.121.212"),
endpoint.NewEndpoint("deletedcname.example.com", endpoint.RecordTypeCNAME, "other.com"),
endpoint.NewEndpoint("deleted.nope.com", endpoint.RecordTypeA, "222.111.222.111"),
}
if createPTR {
deleteRecords = append(deleteRecords, endpoint.NewEndpoint("deleted.example.com", endpoint.RecordTypePTR, "121.212.121.212"))
}
changes := &plan.Changes{
Create: createRecords,
UpdateNew: updateNewRecords,
UpdateOld: updateOldRecords,
Delete: deleteRecords,
}
if err := provider.ApplyChanges(context.Background(), changes); err != nil {
t.Fatal(err)
}
}
func TestInfobloxZones(t *testing.T) {
client := mockIBConnector{
mockInfobloxZones: &[]ibclient.ZoneAuth{
createMockInfobloxZone("example.com"),
createMockInfobloxZone("lvl1-1.example.com"),
createMockInfobloxZone("lvl2-1.lvl1-1.example.com"),
createMockInfobloxZone("1.2.3.0/24"),
},
mockInfobloxObjects: &[]ibclient.IBObject{},
}
provider := newInfobloxProvider(endpoint.NewDomainFilter([]string{"example.com", "1.2.3.0/24"}), provider.NewZoneIDFilter([]string{""}), true, false, &client)
zones, _ := provider.zones()
var emptyZoneAuth *ibclient.ZoneAuth
assert.Equal(t, provider.findZone(zones, "example.com").Fqdn, "example.com")
assert.Equal(t, provider.findZone(zones, "nomatch-example.com"), emptyZoneAuth)
assert.Equal(t, provider.findZone(zones, "nginx.example.com").Fqdn, "example.com")
assert.Equal(t, provider.findZone(zones, "lvl1-1.example.com").Fqdn, "lvl1-1.example.com")
assert.Equal(t, provider.findZone(zones, "lvl1-2.example.com").Fqdn, "example.com")
assert.Equal(t, provider.findZone(zones, "lvl2-1.lvl1-1.example.com").Fqdn, "lvl2-1.lvl1-1.example.com")
assert.Equal(t, provider.findZone(zones, "lvl2-2.lvl1-1.example.com").Fqdn, "lvl1-1.example.com")
assert.Equal(t, provider.findZone(zones, "lvl2-2.lvl1-2.example.com").Fqdn, "example.com")
assert.Equal(t, provider.findZone(zones, "1.2.3.0/24").Fqdn, "1.2.3.0/24")
}
func TestInfobloxReverseZones(t *testing.T) {
client := mockIBConnector{
mockInfobloxZones: &[]ibclient.ZoneAuth{
createMockInfobloxZone("example.com"),
createMockInfobloxZone("1.2.3.0/24"),
createMockInfobloxZone("10.0.0.0/8"),
},
mockInfobloxObjects: &[]ibclient.IBObject{},
}
provider := newInfobloxProvider(endpoint.NewDomainFilter([]string{"example.com", "1.2.3.0/24", "10.0.0.0/8"}), provider.NewZoneIDFilter([]string{""}), true, false, &client)
zones, _ := provider.zones()
var emptyZoneAuth *ibclient.ZoneAuth
assert.Equal(t, provider.findReverseZone(zones, "nomatch-example.com"), emptyZoneAuth)
assert.Equal(t, provider.findReverseZone(zones, "192.168.0.1"), emptyZoneAuth)
assert.Equal(t, provider.findReverseZone(zones, "1.2.3.4").Fqdn, "1.2.3.0/24")
assert.Equal(t, provider.findReverseZone(zones, "10.28.29.30").Fqdn, "10.0.0.0/8")
}
func TestExtendedRequestFDQDRegExBuilder(t *testing.T) {
hostConfig := ibclient.HostConfig{
Host: "localhost",
Port: "8080",
Username: "user",
Password: "abcd",
Version: "2.3.1",
}
requestBuilder := NewExtendedRequestBuilder(0, "^staging.*test.com$")
requestBuilder.Init(hostConfig)
obj := ibclient.NewZoneAuth(ibclient.ZoneAuth{})
req, _ := requestBuilder.BuildRequest(ibclient.GET, obj, "", ibclient.QueryParams{})
assert.True(t, req.URL.Query().Get("fqdn~") == "^staging.*test.com$")
req, _ = requestBuilder.BuildRequest(ibclient.CREATE, obj, "", ibclient.QueryParams{})
assert.True(t, req.URL.Query().Get("fqdn~") == "")
}
func TestExtendedRequestMaxResultsBuilder(t *testing.T) {
hostConfig := ibclient.HostConfig{
Host: "localhost",
Port: "8080",
Username: "user",
Password: "abcd",
Version: "2.3.1",
}
requestBuilder := NewExtendedRequestBuilder(54321, "")
requestBuilder.Init(hostConfig)
obj := ibclient.NewRecordCNAME(ibclient.RecordCNAME{Zone: "foo.bar.com"})
req, _ := requestBuilder.BuildRequest(ibclient.GET, obj, "", ibclient.QueryParams{})
assert.True(t, req.URL.Query().Get("_max_results") == "54321")
req, _ = requestBuilder.BuildRequest(ibclient.CREATE, obj, "", ibclient.QueryParams{})
assert.True(t, req.URL.Query().Get("_max_results") == "")
}
func validateEndpoints(t *testing.T, endpoints []*endpoint.Endpoint, expected []*endpoint.Endpoint) {
assert.True(t, testutils.SameEndpoints(endpoints, expected), "actual and expected endpoints don't match. %s:%s", endpoints, expected)
}