mirror of
				https://github.com/kubernetes-sigs/external-dns.git
				synced 2025-10-31 02:31:00 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			417 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			417 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
| Copyright 2019 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 rcode0
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 	"testing"
 | |
| 
 | |
| 	rc0 "github.com/nic-at/rc0go"
 | |
| 	"github.com/stretchr/testify/require"
 | |
| 
 | |
| 	"sigs.k8s.io/external-dns/endpoint"
 | |
| 	"sigs.k8s.io/external-dns/plan"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	testZoneOne = "testzone1.at"
 | |
| 	testZoneTwo = "testzone2.at"
 | |
| 
 | |
| 	rrsetChangesUnsupportedChangeType = 0
 | |
| )
 | |
| 
 | |
| type mockRcodeZeroClient rc0.Client
 | |
| 
 | |
| type mockZoneManagementService struct {
 | |
| 	TestNilZonesReturned bool
 | |
| 	TestErrorReturned    bool
 | |
| }
 | |
| 
 | |
| type mockRRSetService struct {
 | |
| 	TestErrorReturned bool
 | |
| }
 | |
| 
 | |
| func (m *mockZoneManagementService) resetTestConditions() {
 | |
| 	m.TestNilZonesReturned = false
 | |
| 	m.TestErrorReturned = false
 | |
| }
 | |
| 
 | |
| func TestRcodeZeroProvider_Records(t *testing.T) {
 | |
| 
 | |
| 	mockRRSetService := &mockRRSetService{}
 | |
| 	mockZoneManagementService := &mockZoneManagementService{}
 | |
| 
 | |
| 	provider := &RcodeZeroProvider{
 | |
| 		Client: (*rc0.Client)(&mockRcodeZeroClient{
 | |
| 			Zones: mockZoneManagementService,
 | |
| 			RRSet: mockRRSetService,
 | |
| 		}),
 | |
| 	}
 | |
| 
 | |
| 	ctx := context.Background()
 | |
| 
 | |
| 	endpoints, err := provider.Records(ctx) // should return 6 rrs
 | |
| 
 | |
| 	if err != nil {
 | |
| 		t.Errorf("should not fail, %s", err)
 | |
| 	}
 | |
| 	require.Equal(t, 10, len(endpoints))
 | |
| 
 | |
| 	mockRRSetService.TestErrorReturned = true
 | |
| 
 | |
| 	_, err = provider.Records(ctx)
 | |
| 	if err == nil {
 | |
| 		t.Errorf("expected to fail, %s", err)
 | |
| 	}
 | |
| 
 | |
| }
 | |
| 
 | |
| func TestRcodeZeroProvider_ApplyChanges(t *testing.T) {
 | |
| 
 | |
| 	mockRRSetService := &mockRRSetService{}
 | |
| 	mockZoneManagementService := &mockZoneManagementService{}
 | |
| 
 | |
| 	provider := &RcodeZeroProvider{
 | |
| 		Client: (*rc0.Client)(&mockRcodeZeroClient{
 | |
| 			Zones: mockZoneManagementService,
 | |
| 			RRSet: mockRRSetService,
 | |
| 		}),
 | |
| 		DomainFilter: endpoint.NewDomainFilter([]string{testZoneOne}),
 | |
| 	}
 | |
| 
 | |
| 	changes := mockChanges()
 | |
| 
 | |
| 	err := provider.ApplyChanges(context.Background(), changes)
 | |
| 
 | |
| 	if err != nil {
 | |
| 		t.Errorf("should not fail, %s", err)
 | |
| 	}
 | |
| 
 | |
| }
 | |
| 
 | |
| func TestRcodeZeroProvider_NewRcodezeroChanges(t *testing.T) {
 | |
| 
 | |
| 	provider := &RcodeZeroProvider{}
 | |
| 
 | |
| 	changes := mockChanges()
 | |
| 
 | |
| 	createChanges := provider.NewRcodezeroChanges(testZoneOne, changes.Create)
 | |
| 	require.Equal(t, 4, len(createChanges))
 | |
| 
 | |
| 	deleteChanges := provider.NewRcodezeroChanges(testZoneOne, changes.Delete)
 | |
| 	require.Equal(t, 1, len(deleteChanges))
 | |
| 
 | |
| 	updateOldChanges := provider.NewRcodezeroChanges(testZoneOne, changes.UpdateOld)
 | |
| 	require.Equal(t, 1, len(updateOldChanges))
 | |
| 
 | |
| 	updateNewChanges := provider.NewRcodezeroChanges(testZoneOne, changes.UpdateNew)
 | |
| 	require.Equal(t, 1, len(updateNewChanges))
 | |
| }
 | |
| 
 | |
| func TestRcodeZeroProvider_NewRcodezeroChange(t *testing.T) {
 | |
| 
 | |
| 	_endpoint := &endpoint.Endpoint{
 | |
| 		RecordType: "A",
 | |
| 		DNSName:    "app." + testZoneOne,
 | |
| 		RecordTTL:  300,
 | |
| 		Targets:    endpoint.Targets{"target"},
 | |
| 	}
 | |
| 
 | |
| 	provider := &RcodeZeroProvider{}
 | |
| 
 | |
| 	rrsetChange := provider.NewRcodezeroChange(testZoneOne, _endpoint)
 | |
| 
 | |
| 	require.Equal(t, _endpoint.RecordType, rrsetChange.Type)
 | |
| 	require.Equal(t, _endpoint.DNSName, rrsetChange.Name)
 | |
| 	require.Equal(t, _endpoint.Targets[0], rrsetChange.Records[0].Content)
 | |
| 	//require.Equal(t, endpoint.RecordTTL, rrsetChange.TTL)
 | |
| 
 | |
| }
 | |
| 
 | |
| func Test_submitChanges(t *testing.T) {
 | |
| 
 | |
| 	mockRRSetService := &mockRRSetService{}
 | |
| 	mockZoneManagementService := &mockZoneManagementService{}
 | |
| 
 | |
| 	provider := &RcodeZeroProvider{
 | |
| 		Client: (*rc0.Client)(&mockRcodeZeroClient{
 | |
| 			Zones: mockZoneManagementService,
 | |
| 			RRSet: mockRRSetService,
 | |
| 		}),
 | |
| 		DomainFilter: endpoint.NewDomainFilter([]string{testZoneOne}),
 | |
| 	}
 | |
| 
 | |
| 	changes := mockRRSetChanges(rrsetChangesUnsupportedChangeType)
 | |
| 
 | |
| 	err := provider.submitChanges(changes)
 | |
| 
 | |
| 	if err == nil {
 | |
| 		t.Errorf("expected to fail, %s", err)
 | |
| 	}
 | |
| 
 | |
| }
 | |
| 
 | |
| func mockRRSetChanges(condition int) []*rc0.RRSetChange {
 | |
| 
 | |
| 	switch condition {
 | |
| 	case rrsetChangesUnsupportedChangeType:
 | |
| 		return []*rc0.RRSetChange{
 | |
| 			{
 | |
| 				Name:       testZoneOne,
 | |
| 				Type:       "A",
 | |
| 				ChangeType: "UNSUPPORTED",
 | |
| 				Records:    []*rc0.Record{{Content: "fail"}},
 | |
| 			},
 | |
| 		}
 | |
| 	default:
 | |
| 		return nil
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func mockChanges() *plan.Changes {
 | |
| 
 | |
| 	changes := &plan.Changes{}
 | |
| 
 | |
| 	changes.Create = []*endpoint.Endpoint{
 | |
| 		{DNSName: "new.ext-dns-test." + testZoneOne, Targets: endpoint.Targets{"target"}, RecordType: "A"},
 | |
| 		{DNSName: "new.ext-dns-test-with-ttl." + testZoneOne, Targets: endpoint.Targets{"target"}, RecordType: "A", RecordTTL: 100},
 | |
| 		{DNSName: "new.ext-dns-test.unexpected.com", Targets: endpoint.Targets{"target"}, RecordType: "AAAA"},
 | |
| 		{DNSName: testZoneOne, Targets: endpoint.Targets{"target"}, RecordType: "CNAME"},
 | |
| 	}
 | |
| 	changes.Delete = []*endpoint.Endpoint{{DNSName: "foobar.ext-dns-test." + testZoneOne, Targets: endpoint.Targets{"target"}}}
 | |
| 	changes.UpdateOld = []*endpoint.Endpoint{{DNSName: "foobar.ext-dns-test." + testZoneOne, Targets: endpoint.Targets{"target-old"}}}
 | |
| 	changes.UpdateNew = []*endpoint.Endpoint{{DNSName: "foobar.ext-dns-test." + testZoneOne, Targets: endpoint.Targets{"target-new"}, RecordType: "CNAME", RecordTTL: 100}}
 | |
| 
 | |
| 	return changes
 | |
| }
 | |
| 
 | |
| func TestRcodeZeroProvider_Zones(t *testing.T) {
 | |
| 
 | |
| 	mockRRSetService := &mockRRSetService{}
 | |
| 	mockZoneManagementService := &mockZoneManagementService{}
 | |
| 
 | |
| 	provider := &RcodeZeroProvider{
 | |
| 		Client: (*rc0.Client)(&mockRcodeZeroClient{
 | |
| 			Zones: mockZoneManagementService,
 | |
| 			RRSet: mockRRSetService,
 | |
| 		}),
 | |
| 	}
 | |
| 
 | |
| 	mockZoneManagementService.TestNilZonesReturned = true
 | |
| 
 | |
| 	zones, err := provider.Zones()
 | |
| 
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	require.Equal(t, 0, len(zones))
 | |
| 	mockZoneManagementService.resetTestConditions()
 | |
| 
 | |
| 	mockZoneManagementService.TestErrorReturned = true
 | |
| 
 | |
| 	_, err = provider.Zones()
 | |
| 	if err == nil {
 | |
| 		t.Errorf("expected to fail, %s", err)
 | |
| 	}
 | |
| 
 | |
| }
 | |
| 
 | |
| func TestNewRcodeZeroProvider(t *testing.T) {
 | |
| 
 | |
| 	_ = os.Setenv("RC0_API_KEY", "123")
 | |
| 	p, err := NewRcodeZeroProvider(endpoint.NewDomainFilter([]string{"ext-dns-test." + testZoneOne + "."}), true, true)
 | |
| 
 | |
| 	if err != nil {
 | |
| 		t.Errorf("should not fail, %s", err)
 | |
| 	}
 | |
| 
 | |
| 	require.Equal(t, true, p.DryRun)
 | |
| 	require.Equal(t, true, p.TXTEncrypt)
 | |
| 	require.Equal(t, true, p.DomainFilter.IsConfigured())
 | |
| 	require.Equal(t, false, p.DomainFilter.Match("ext-dns-test."+testZoneTwo+".")) // filter is set, so it should match only provided domains
 | |
| 
 | |
| 	p, err = NewRcodeZeroProvider(endpoint.DomainFilter{}, false, false)
 | |
| 
 | |
| 	if err != nil {
 | |
| 		t.Errorf("should not fail, %s", err)
 | |
| 	}
 | |
| 
 | |
| 	require.Equal(t, false, p.DryRun)
 | |
| 	require.Equal(t, false, p.DomainFilter.IsConfigured())
 | |
| 	require.Equal(t, true, p.DomainFilter.Match("ext-dns-test."+testZoneOne+".")) // filter is not set, so it should match any
 | |
| 
 | |
| 	_ = os.Unsetenv("RC0_API_KEY")
 | |
| 	_, err = NewRcodeZeroProvider(endpoint.DomainFilter{}, false, false)
 | |
| 
 | |
| 	if err == nil {
 | |
| 		t.Errorf("expected to fail")
 | |
| 	}
 | |
| 
 | |
| }
 | |
| 
 | |
| /* mocking mockRRSetServiceInterface */
 | |
| 
 | |
| func (m *mockRRSetService) List(zone string, options *rc0.ListOptions) ([]*rc0.RRType, *rc0.Page, error) {
 | |
| 
 | |
| 	if m.TestErrorReturned {
 | |
| 		return nil, nil, fmt.Errorf("operation RRSet.List failed")
 | |
| 	}
 | |
| 
 | |
| 	return mockRRSet(zone), nil, nil
 | |
| }
 | |
| 
 | |
| func mockRRSet(zone string) []*rc0.RRType {
 | |
| 	return []*rc0.RRType{
 | |
| 		{
 | |
| 			Name: "app." + zone + ".",
 | |
| 			Type: "TXT",
 | |
| 			TTL:  300,
 | |
| 			Records: []*rc0.Record{
 | |
| 				{
 | |
| 					Content:  "\"heritage=external-dns,external-dns/owner=default,external-dns/resource=ingress/default/app\"",
 | |
| 					Disabled: false,
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			Name: "app." + zone + ".",
 | |
| 			Type: "A",
 | |
| 			TTL:  300,
 | |
| 			Records: []*rc0.Record{
 | |
| 				{
 | |
| 					Content:  "127.0.0.1",
 | |
| 					Disabled: false,
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			Name: "www." + zone + ".",
 | |
| 			Type: "A",
 | |
| 			TTL:  300,
 | |
| 			Records: []*rc0.Record{
 | |
| 				{
 | |
| 					Content:  "127.0.0.1",
 | |
| 					Disabled: false,
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			Name: zone + ".",
 | |
| 			Type: "SOA",
 | |
| 			TTL:  3600,
 | |
| 			Records: []*rc0.Record{
 | |
| 				{
 | |
| 					Content:  "sec1.rcode0.net. rcodezero-soa.ipcom.at. 2019011616 10800 3600 604800 3600",
 | |
| 					Disabled: false,
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			Name: zone + ".",
 | |
| 			Type: "NS",
 | |
| 			TTL:  3600,
 | |
| 			Records: []*rc0.Record{
 | |
| 				{
 | |
| 					Content:  "sec2.rcode0.net.",
 | |
| 					Disabled: false,
 | |
| 				},
 | |
| 				{
 | |
| 					Content:  "sec1.rcode0.net.",
 | |
| 					Disabled: false,
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (m *mockRRSetService) Create(zone string, rrsetCreate []*rc0.RRSetChange) (*rc0.StatusResponse, error) {
 | |
| 
 | |
| 	return &rc0.StatusResponse{Status: "ok", Message: "pass"}, nil
 | |
| 
 | |
| }
 | |
| func (m *mockRRSetService) Edit(zone string, rrsetEdit []*rc0.RRSetChange) (*rc0.StatusResponse, error) {
 | |
| 
 | |
| 	return &rc0.StatusResponse{Status: "ok", Message: "pass"}, nil
 | |
| }
 | |
| func (m *mockRRSetService) Delete(zone string, rrsetDelete []*rc0.RRSetChange) (*rc0.StatusResponse, error) {
 | |
| 
 | |
| 	return &rc0.StatusResponse{Status: "ok", Message: "pass"}, nil
 | |
| }
 | |
| func (m *mockRRSetService) SubmitChangeSet(zone string, changeSet []*rc0.RRSetChange) (*rc0.StatusResponse, error) {
 | |
| 
 | |
| 	return &rc0.StatusResponse{Status: "ok", Message: "pass"}, nil
 | |
| }
 | |
| 
 | |
| func (m *mockRRSetService) EncryptTXT(key []byte, rrType *rc0.RRSetChange) {}
 | |
| 
 | |
| func (m *mockRRSetService) DecryptTXT(key []byte, rrType *rc0.RRType) {}
 | |
| 
 | |
| /* mocking ZoneManagementServiceInterface */
 | |
| 
 | |
| func (m *mockZoneManagementService) List(options *rc0.ListOptions) ([]*rc0.Zone, *rc0.Page, error) {
 | |
| 
 | |
| 	if m.TestNilZonesReturned {
 | |
| 		return nil, nil, nil
 | |
| 	}
 | |
| 
 | |
| 	if m.TestErrorReturned {
 | |
| 		return nil, nil, fmt.Errorf("operation Zone.List failed")
 | |
| 	}
 | |
| 
 | |
| 	zones := []*rc0.Zone{
 | |
| 		{
 | |
| 			Domain: testZoneOne,
 | |
| 			Type:   "SLAVE",
 | |
| 			// "dnssec": "yes",                   @todo: add this
 | |
| 			// "created": "2018-04-09T09:27:31Z", @todo: add this
 | |
| 			LastCheck: "",
 | |
| 			Serial:    20180411,
 | |
| 			Masters: []string{
 | |
| 				"193.0.2.2",
 | |
| 				"2001:db8::2",
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			Domain: testZoneTwo,
 | |
| 			Type:   "MASTER",
 | |
| 			// "dnssec": "no",                    @todo: add this
 | |
| 			// "created": "2019-01-15T13:20:10Z", @todo: add this
 | |
| 			LastCheck: "",
 | |
| 			Serial:    2019011616,
 | |
| 			Masters: []string{
 | |
| 				"",
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	return zones, nil, nil
 | |
| }
 | |
| 
 | |
| func (m *mockZoneManagementService) Get(zone string) (*rc0.Zone, error) { return nil, nil }
 | |
| func (m *mockZoneManagementService) Create(zoneCreate *rc0.ZoneCreate) (*rc0.StatusResponse, error) {
 | |
| 	return nil, nil
 | |
| }
 | |
| func (m *mockZoneManagementService) Edit(zone string, zoneEdit *rc0.ZoneEdit) (*rc0.StatusResponse, error) {
 | |
| 	return nil, nil
 | |
| }
 | |
| func (m *mockZoneManagementService) Delete(zone string) (*rc0.StatusResponse, error) { return nil, nil }
 | |
| func (m *mockZoneManagementService) Transfer(zone string) (*rc0.StatusResponse, error) {
 | |
| 	return nil, nil
 | |
| }
 |