mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2025-08-05 17:16:59 +02:00
321 lines
8.2 KiB
Go
321 lines
8.2 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 ns1
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/mock"
|
|
"github.com/stretchr/testify/require"
|
|
api "gopkg.in/ns1/ns1-go.v2/rest"
|
|
"gopkg.in/ns1/ns1-go.v2/rest/model/dns"
|
|
|
|
"sigs.k8s.io/external-dns/endpoint"
|
|
"sigs.k8s.io/external-dns/plan"
|
|
"sigs.k8s.io/external-dns/provider"
|
|
)
|
|
|
|
type MockNS1DomainClient struct {
|
|
mock.Mock
|
|
}
|
|
|
|
func (m *MockNS1DomainClient) CreateRecord(r *dns.Record) (*http.Response, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *MockNS1DomainClient) DeleteRecord(zone string, domain string, t string) (*http.Response, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *MockNS1DomainClient) UpdateRecord(r *dns.Record) (*http.Response, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *MockNS1DomainClient) GetZone(zone string) (*dns.Zone, *http.Response, error) {
|
|
r := &dns.ZoneRecord{
|
|
Domain: "test.foo.com",
|
|
ShortAns: []string{"2.2.2.2"},
|
|
TTL: 3600,
|
|
Type: "A",
|
|
ID: "123456789abcdefghijklmno",
|
|
}
|
|
z := &dns.Zone{
|
|
Zone: "foo.com",
|
|
Records: []*dns.ZoneRecord{r},
|
|
TTL: 3600,
|
|
ID: "12345678910111213141516a",
|
|
}
|
|
|
|
if zone == "foo.com" {
|
|
return z, nil, nil
|
|
}
|
|
return nil, nil, nil
|
|
}
|
|
|
|
func (m *MockNS1DomainClient) ListZones() ([]*dns.Zone, *http.Response, error) {
|
|
zones := []*dns.Zone{
|
|
{Zone: "foo.com", ID: "12345678910111213141516a"},
|
|
{Zone: "bar.com", ID: "12345678910111213141516b"},
|
|
}
|
|
return zones, nil, nil
|
|
}
|
|
|
|
type MockNS1GetZoneFail struct{}
|
|
|
|
func (m *MockNS1GetZoneFail) CreateRecord(r *dns.Record) (*http.Response, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *MockNS1GetZoneFail) DeleteRecord(zone string, domain string, t string) (*http.Response, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *MockNS1GetZoneFail) UpdateRecord(r *dns.Record) (*http.Response, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *MockNS1GetZoneFail) GetZone(zone string) (*dns.Zone, *http.Response, error) {
|
|
return nil, nil, api.ErrZoneMissing
|
|
}
|
|
|
|
func (m *MockNS1GetZoneFail) ListZones() ([]*dns.Zone, *http.Response, error) {
|
|
zones := []*dns.Zone{
|
|
{Zone: "foo.com", ID: "12345678910111213141516a"},
|
|
{Zone: "bar.com", ID: "12345678910111213141516b"},
|
|
}
|
|
return zones, nil, nil
|
|
}
|
|
|
|
type MockNS1ListZonesFail struct{}
|
|
|
|
func (m *MockNS1ListZonesFail) CreateRecord(r *dns.Record) (*http.Response, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *MockNS1ListZonesFail) DeleteRecord(zone string, domain string, t string) (*http.Response, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *MockNS1ListZonesFail) UpdateRecord(r *dns.Record) (*http.Response, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *MockNS1ListZonesFail) GetZone(zone string) (*dns.Zone, *http.Response, error) {
|
|
return &dns.Zone{}, nil, nil
|
|
}
|
|
|
|
func (m *MockNS1ListZonesFail) ListZones() ([]*dns.Zone, *http.Response, error) {
|
|
return nil, nil, fmt.Errorf("no zones available")
|
|
}
|
|
|
|
func TestNS1Records(t *testing.T) {
|
|
provider := &NS1Provider{
|
|
client: &MockNS1DomainClient{},
|
|
domainFilter: endpoint.NewDomainFilter([]string{"foo.com."}),
|
|
zoneIDFilter: provider.NewZoneIDFilter([]string{""}),
|
|
minTTLSeconds: 3600,
|
|
}
|
|
ctx := context.Background()
|
|
|
|
records, err := provider.Records(ctx)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 1, len(records))
|
|
|
|
provider.client = &MockNS1GetZoneFail{}
|
|
_, err = provider.Records(ctx)
|
|
require.Error(t, err)
|
|
|
|
provider.client = &MockNS1ListZonesFail{}
|
|
_, err = provider.Records(ctx)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestNewNS1Provider(t *testing.T) {
|
|
_ = os.Setenv("NS1_APIKEY", "xxxxxxxxxxxxxxxxx")
|
|
testNS1Config := NS1Config{
|
|
DomainFilter: endpoint.NewDomainFilter([]string{"foo.com."}),
|
|
ZoneIDFilter: provider.NewZoneIDFilter([]string{""}),
|
|
DryRun: false,
|
|
}
|
|
_, err := NewNS1Provider(testNS1Config)
|
|
require.NoError(t, err)
|
|
|
|
_ = os.Unsetenv("NS1_APIKEY")
|
|
_, err = NewNS1Provider(testNS1Config)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestNS1Zones(t *testing.T) {
|
|
provider := &NS1Provider{
|
|
client: &MockNS1DomainClient{},
|
|
domainFilter: endpoint.NewDomainFilter([]string{"foo.com."}),
|
|
zoneIDFilter: provider.NewZoneIDFilter([]string{""}),
|
|
}
|
|
|
|
zones, err := provider.zonesFiltered()
|
|
require.NoError(t, err)
|
|
|
|
validateNS1Zones(t, zones, []*dns.Zone{
|
|
{Zone: "foo.com"},
|
|
})
|
|
}
|
|
|
|
func validateNS1Zones(t *testing.T, zones []*dns.Zone, expected []*dns.Zone) {
|
|
require.Len(t, zones, len(expected))
|
|
|
|
for i, zone := range zones {
|
|
assert.Equal(t, expected[i].Zone, zone.Zone)
|
|
}
|
|
}
|
|
|
|
func TestNS1BuildRecord(t *testing.T) {
|
|
change := &ns1Change{
|
|
Action: ns1Create,
|
|
Endpoint: &endpoint.Endpoint{
|
|
DNSName: "new",
|
|
Targets: endpoint.Targets{"target"},
|
|
RecordType: "A",
|
|
},
|
|
}
|
|
|
|
provider := &NS1Provider{
|
|
client: &MockNS1DomainClient{},
|
|
domainFilter: endpoint.NewDomainFilter([]string{"foo.com."}),
|
|
zoneIDFilter: provider.NewZoneIDFilter([]string{""}),
|
|
minTTLSeconds: 300,
|
|
}
|
|
|
|
record := provider.ns1BuildRecord("foo.com", change)
|
|
assert.Equal(t, "foo.com", record.Zone)
|
|
assert.Equal(t, "new.foo.com", record.Domain)
|
|
assert.Equal(t, 300, record.TTL)
|
|
|
|
changeWithTTL := &ns1Change{
|
|
Action: ns1Create,
|
|
Endpoint: &endpoint.Endpoint{
|
|
DNSName: "new-b",
|
|
Targets: endpoint.Targets{"target"},
|
|
RecordType: "A",
|
|
RecordTTL: 3600,
|
|
},
|
|
}
|
|
record = provider.ns1BuildRecord("foo.com", changeWithTTL)
|
|
assert.Equal(t, "foo.com", record.Zone)
|
|
assert.Equal(t, "new-b.foo.com", record.Domain)
|
|
assert.Equal(t, 3600, record.TTL)
|
|
}
|
|
|
|
func TestNS1ApplyChanges(t *testing.T) {
|
|
changes := &plan.Changes{}
|
|
provider := &NS1Provider{
|
|
client: &MockNS1DomainClient{},
|
|
}
|
|
changes.Create = []*endpoint.Endpoint{
|
|
{DNSName: "new.foo.com", Targets: endpoint.Targets{"target"}},
|
|
{DNSName: "new.subdomain.bar.com", Targets: endpoint.Targets{"target"}},
|
|
}
|
|
changes.Delete = []*endpoint.Endpoint{{DNSName: "test.foo.com", Targets: endpoint.Targets{"target"}}}
|
|
changes.UpdateNew = []*endpoint.Endpoint{{DNSName: "test.foo.com", Targets: endpoint.Targets{"target-new"}}}
|
|
err := provider.ApplyChanges(context.Background(), changes)
|
|
require.NoError(t, err)
|
|
|
|
// empty changes
|
|
changes.Create = []*endpoint.Endpoint{}
|
|
changes.Delete = []*endpoint.Endpoint{}
|
|
changes.UpdateNew = []*endpoint.Endpoint{}
|
|
err = provider.ApplyChanges(context.Background(), changes)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestNewNS1Changes(t *testing.T) {
|
|
endpoints := []*endpoint.Endpoint{
|
|
{
|
|
DNSName: "testa.foo.com",
|
|
Targets: endpoint.Targets{"target-old"},
|
|
RecordType: "A",
|
|
},
|
|
{
|
|
DNSName: "testba.bar.com",
|
|
Targets: endpoint.Targets{"target-new"},
|
|
RecordType: "A",
|
|
},
|
|
}
|
|
expected := []*ns1Change{
|
|
{
|
|
Action: "ns1Create",
|
|
Endpoint: endpoints[0],
|
|
},
|
|
{
|
|
Action: "ns1Create",
|
|
Endpoint: endpoints[1],
|
|
},
|
|
}
|
|
changes := newNS1Changes("ns1Create", endpoints)
|
|
require.Len(t, changes, len(expected))
|
|
assert.Equal(t, expected, changes)
|
|
}
|
|
|
|
func TestNewNS1ChangesByZone(t *testing.T) {
|
|
provider := &NS1Provider{
|
|
client: &MockNS1DomainClient{},
|
|
}
|
|
zones, _ := provider.zonesFiltered()
|
|
changeSets := []*ns1Change{
|
|
{
|
|
Action: "ns1Create",
|
|
Endpoint: &endpoint.Endpoint{
|
|
DNSName: "new.foo.com",
|
|
Targets: endpoint.Targets{"target"},
|
|
RecordType: "A",
|
|
},
|
|
},
|
|
{
|
|
Action: "ns1Create",
|
|
Endpoint: &endpoint.Endpoint{
|
|
DNSName: "unrelated.bar.com",
|
|
Targets: endpoint.Targets{"target"},
|
|
RecordType: "A",
|
|
},
|
|
},
|
|
{
|
|
Action: "ns1Delete",
|
|
Endpoint: &endpoint.Endpoint{
|
|
DNSName: "test.foo.com",
|
|
Targets: endpoint.Targets{"target"},
|
|
RecordType: "A",
|
|
},
|
|
},
|
|
{
|
|
Action: "ns1Update",
|
|
Endpoint: &endpoint.Endpoint{
|
|
DNSName: "test.foo.com",
|
|
Targets: endpoint.Targets{"target-new"},
|
|
RecordType: "A",
|
|
},
|
|
},
|
|
}
|
|
|
|
changes := ns1ChangesByZone(zones, changeSets)
|
|
assert.Len(t, changes["bar.com"], 1)
|
|
assert.Len(t, changes["foo.com"], 3)
|
|
}
|