sigs.k8s.io/external-dns@v0.14.1/provider/alibabacloud/alibaba_cloud_test.go (about)

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package alibabacloud
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  
    23  	"github.com/aliyun/alibaba-cloud-sdk-go/services/alidns"
    24  	"github.com/aliyun/alibaba-cloud-sdk-go/services/pvtz"
    25  
    26  	"sigs.k8s.io/external-dns/endpoint"
    27  	"sigs.k8s.io/external-dns/plan"
    28  )
    29  
    30  type MockAlibabaCloudDNSAPI struct {
    31  	records []alidns.Record
    32  }
    33  
    34  func NewMockAlibabaCloudDNSAPI() *MockAlibabaCloudDNSAPI {
    35  	api := MockAlibabaCloudDNSAPI{}
    36  	api.records = []alidns.Record{
    37  		{
    38  			RecordId:   "1",
    39  			DomainName: "container-service.top",
    40  			Type:       "A",
    41  			TTL:        300,
    42  			RR:         "abc",
    43  			Value:      "1.2.3.4",
    44  		},
    45  		{
    46  			RecordId:   "2",
    47  			DomainName: "container-service.top",
    48  			Type:       "TXT",
    49  			TTL:        300,
    50  			RR:         "abc",
    51  			Value:      "heritage=external-dns;external-dns/owner=default",
    52  		},
    53  	}
    54  	return &api
    55  }
    56  
    57  func (m *MockAlibabaCloudDNSAPI) AddDomainRecord(request *alidns.AddDomainRecordRequest) (response *alidns.AddDomainRecordResponse, err error) {
    58  	ttl, _ := request.TTL.GetValue()
    59  	m.records = append(m.records, alidns.Record{
    60  		RecordId:   "3",
    61  		DomainName: request.DomainName,
    62  		Type:       request.Type,
    63  		TTL:        int64(ttl),
    64  		RR:         request.RR,
    65  		Value:      request.Value,
    66  	})
    67  	response = alidns.CreateAddDomainRecordResponse()
    68  	return response, nil
    69  }
    70  
    71  func (m *MockAlibabaCloudDNSAPI) DeleteDomainRecord(request *alidns.DeleteDomainRecordRequest) (response *alidns.DeleteDomainRecordResponse, err error) {
    72  	var result []alidns.Record
    73  	for _, record := range m.records {
    74  		if record.RecordId != request.RecordId {
    75  			result = append(result, record)
    76  		}
    77  	}
    78  	m.records = result
    79  	response = alidns.CreateDeleteDomainRecordResponse()
    80  	response.RecordId = request.RecordId
    81  	return response, nil
    82  }
    83  
    84  func (m *MockAlibabaCloudDNSAPI) UpdateDomainRecord(request *alidns.UpdateDomainRecordRequest) (response *alidns.UpdateDomainRecordResponse, err error) {
    85  	ttl, _ := request.TTL.GetValue64()
    86  	for i := range m.records {
    87  		if m.records[i].RecordId == request.RecordId {
    88  			m.records[i].TTL = ttl
    89  		}
    90  	}
    91  	response = alidns.CreateUpdateDomainRecordResponse()
    92  	response.RecordId = request.RecordId
    93  	return response, nil
    94  }
    95  
    96  func (m *MockAlibabaCloudDNSAPI) DescribeDomains(request *alidns.DescribeDomainsRequest) (response *alidns.DescribeDomainsResponse, err error) {
    97  	var result alidns.DomainsInDescribeDomains
    98  	for _, record := range m.records {
    99  		domain := alidns.Domain{}
   100  		domain.DomainName = record.DomainName
   101  		result.Domain = append(result.Domain, alidns.DomainInDescribeDomains{
   102  			DomainName: domain.DomainName,
   103  		})
   104  	}
   105  	response = alidns.CreateDescribeDomainsResponse()
   106  	response.Domains = result
   107  	return response, nil
   108  }
   109  
   110  func (m *MockAlibabaCloudDNSAPI) DescribeDomainRecords(request *alidns.DescribeDomainRecordsRequest) (response *alidns.DescribeDomainRecordsResponse, err error) {
   111  	var result []alidns.Record
   112  	for _, record := range m.records {
   113  		if record.DomainName == request.DomainName {
   114  			result = append(result, record)
   115  		}
   116  	}
   117  	response = alidns.CreateDescribeDomainRecordsResponse()
   118  	response.DomainRecords.Record = result
   119  	return response, nil
   120  }
   121  
   122  type MockAlibabaCloudPrivateZoneAPI struct {
   123  	zone    pvtz.Zone
   124  	records []pvtz.Record
   125  }
   126  
   127  func NewMockAlibabaCloudPrivateZoneAPI() *MockAlibabaCloudPrivateZoneAPI {
   128  	vpc := pvtz.Vpc{
   129  		RegionId: "cn-beijing",
   130  		VpcId:    "vpc-xxxxxx",
   131  	}
   132  
   133  	api := MockAlibabaCloudPrivateZoneAPI{zone: pvtz.Zone{
   134  		ZoneId:   "test-zone",
   135  		ZoneName: "container-service.top",
   136  		Vpcs: pvtz.Vpcs{
   137  			Vpc: []pvtz.Vpc{vpc},
   138  		},
   139  	}}
   140  
   141  	api.records = []pvtz.Record{
   142  		{
   143  			RecordId: 1,
   144  			Type:     "A",
   145  			Ttl:      300,
   146  			Rr:       "abc",
   147  			Value:    "1.2.3.4",
   148  		},
   149  		{
   150  			RecordId: 2,
   151  			Type:     "TXT",
   152  			Ttl:      300,
   153  			Rr:       "abc",
   154  			Value:    "heritage=external-dns;external-dns/owner=default",
   155  		},
   156  	}
   157  	return &api
   158  }
   159  
   160  func (m *MockAlibabaCloudPrivateZoneAPI) AddZoneRecord(request *pvtz.AddZoneRecordRequest) (response *pvtz.AddZoneRecordResponse, err error) {
   161  	ttl, _ := request.Ttl.GetValue()
   162  	m.records = append(m.records, pvtz.Record{
   163  		RecordId: 3,
   164  		Type:     request.Type,
   165  		Ttl:      ttl,
   166  		Rr:       request.Rr,
   167  		Value:    request.Value,
   168  	})
   169  	response = pvtz.CreateAddZoneRecordResponse()
   170  	return response, nil
   171  }
   172  
   173  func (m *MockAlibabaCloudPrivateZoneAPI) DeleteZoneRecord(request *pvtz.DeleteZoneRecordRequest) (response *pvtz.DeleteZoneRecordResponse, err error) {
   174  	recordID, _ := request.RecordId.GetValue64()
   175  
   176  	var result []pvtz.Record
   177  	for _, record := range m.records {
   178  		if record.RecordId != recordID {
   179  			result = append(result, record)
   180  		}
   181  	}
   182  	m.records = result
   183  	response = pvtz.CreateDeleteZoneRecordResponse()
   184  	return response, nil
   185  }
   186  
   187  func (m *MockAlibabaCloudPrivateZoneAPI) UpdateZoneRecord(request *pvtz.UpdateZoneRecordRequest) (response *pvtz.UpdateZoneRecordResponse, err error) {
   188  	recordID, _ := request.RecordId.GetValue64()
   189  	ttl, _ := request.Ttl.GetValue()
   190  	for i := range m.records {
   191  		if m.records[i].RecordId == recordID {
   192  			m.records[i].Ttl = ttl
   193  		}
   194  	}
   195  	response = pvtz.CreateUpdateZoneRecordResponse()
   196  	return response, nil
   197  }
   198  
   199  func (m *MockAlibabaCloudPrivateZoneAPI) DescribeZoneRecords(request *pvtz.DescribeZoneRecordsRequest) (response *pvtz.DescribeZoneRecordsResponse, err error) {
   200  	response = pvtz.CreateDescribeZoneRecordsResponse()
   201  	response.Records.Record = append(response.Records.Record, m.records...)
   202  	return response, nil
   203  }
   204  
   205  func (m *MockAlibabaCloudPrivateZoneAPI) DescribeZones(request *pvtz.DescribeZonesRequest) (response *pvtz.DescribeZonesResponse, err error) {
   206  	response = pvtz.CreateDescribeZonesResponse()
   207  	response.Zones.Zone = append(response.Zones.Zone, m.zone)
   208  	return response, nil
   209  }
   210  
   211  func (m *MockAlibabaCloudPrivateZoneAPI) DescribeZoneInfo(request *pvtz.DescribeZoneInfoRequest) (response *pvtz.DescribeZoneInfoResponse, err error) {
   212  	response = pvtz.CreateDescribeZoneInfoResponse()
   213  	response.ZoneId = m.zone.ZoneId
   214  	response.ZoneName = m.zone.ZoneName
   215  	response.BindVpcs = pvtz.BindVpcsInDescribeZoneInfo{Vpc: m.zone.Vpcs.Vpc}
   216  	return response, nil
   217  }
   218  
   219  func newTestAlibabaCloudProvider(private bool) *AlibabaCloudProvider {
   220  	cfg := alibabaCloudConfig{
   221  		RegionID:        "cn-beijing",
   222  		AccessKeyID:     "xxxxxx",
   223  		AccessKeySecret: "xxxxxx",
   224  		VPCID:           "vpc-xxxxxx",
   225  	}
   226  	//
   227  	//dnsClient, _ := alidns.NewClientWithAccessKey(
   228  	//	cfg.RegionID,
   229  	//	cfg.AccessKeyID,
   230  	//	cfg.AccessKeySecret,
   231  	//)
   232  	//
   233  	//pvtzClient, _ := pvtz.NewClientWithAccessKey(
   234  	//	"cn-hangzhou",
   235  	//	cfg.AccessKeyID,
   236  	//	cfg.AccessKeySecret,
   237  	//)
   238  	domainFilterTest := endpoint.NewDomainFilter([]string{"container-service.top.", "example.org"})
   239  
   240  	return &AlibabaCloudProvider{
   241  		domainFilter: domainFilterTest,
   242  		vpcID:        cfg.VPCID,
   243  		dryRun:       false,
   244  		dnsClient:    NewMockAlibabaCloudDNSAPI(),
   245  		pvtzClient:   NewMockAlibabaCloudPrivateZoneAPI(),
   246  		privateZone:  private,
   247  	}
   248  }
   249  
   250  func TestAlibabaCloudPrivateProvider_Records(t *testing.T) {
   251  	p := newTestAlibabaCloudProvider(true)
   252  	endpoints, err := p.Records(context.Background())
   253  	if err != nil {
   254  		t.Errorf("Failed to get records: %v", err)
   255  	} else {
   256  		if len(endpoints) != 2 {
   257  			t.Errorf("Incorrect number of records: %d", len(endpoints))
   258  		}
   259  		for _, endpoint := range endpoints {
   260  			t.Logf("Endpoint for %++v", *endpoint)
   261  		}
   262  	}
   263  }
   264  
   265  func TestAlibabaCloudProvider_Records(t *testing.T) {
   266  	p := newTestAlibabaCloudProvider(false)
   267  	endpoints, err := p.Records(context.Background())
   268  	if err != nil {
   269  		t.Errorf("Failed to get records: %v", err)
   270  	} else {
   271  		if len(endpoints) != 2 {
   272  			t.Errorf("Incorrect number of records: %d", len(endpoints))
   273  		}
   274  		for _, endpoint := range endpoints {
   275  			t.Logf("Endpoint for %++v", *endpoint)
   276  		}
   277  	}
   278  }
   279  
   280  func TestAlibabaCloudProvider_ApplyChanges(t *testing.T) {
   281  	p := newTestAlibabaCloudProvider(false)
   282  	defaultTtlPlan := &endpoint.Endpoint{
   283  		DNSName:    "ttl.container-service.top",
   284  		RecordType: "A",
   285  		RecordTTL:  defaultAlibabaCloudRecordTTL,
   286  		Targets:    endpoint.NewTargets("4.3.2.1"),
   287  	}
   288  	changes := plan.Changes{
   289  		Create: []*endpoint.Endpoint{
   290  			{
   291  				DNSName:    "xyz.container-service.top",
   292  				RecordType: "A",
   293  				RecordTTL:  300,
   294  				Targets:    endpoint.NewTargets("4.3.2.1"),
   295  			},
   296  			defaultTtlPlan,
   297  		},
   298  		UpdateNew: []*endpoint.Endpoint{
   299  			{
   300  				DNSName:    "abc.container-service.top",
   301  				RecordType: "A",
   302  				RecordTTL:  500,
   303  				Targets:    endpoint.NewTargets("1.2.3.4", "5.6.7.8"),
   304  			},
   305  		},
   306  		Delete: []*endpoint.Endpoint{
   307  			{
   308  				DNSName:    "abc.container-service.top",
   309  				RecordType: "TXT",
   310  				RecordTTL:  300,
   311  				Targets:    endpoint.NewTargets("\"heritage=external-dns,external-dns/owner=default\""),
   312  			},
   313  		},
   314  	}
   315  	ctx := context.Background()
   316  	p.ApplyChanges(ctx, &changes)
   317  	endpoints, err := p.Records(ctx)
   318  	if err != nil {
   319  		t.Errorf("Failed to get records: %v", err)
   320  	} else {
   321  		if len(endpoints) != 3 {
   322  			t.Errorf("Incorrect number of records: %d", len(endpoints))
   323  		}
   324  		for _, endpoint := range endpoints {
   325  			t.Logf("Endpoint for %++v", *endpoint)
   326  		}
   327  	}
   328  	for _, ep := range endpoints {
   329  		if ep.DNSName == defaultTtlPlan.DNSName {
   330  			if ep.RecordTTL != defaultTtlPlan.RecordTTL {
   331  				t.Error("default ttl execute error")
   332  			}
   333  		}
   334  	}
   335  }
   336  
   337  func TestAlibabaCloudProvider_Records_PrivateZone(t *testing.T) {
   338  	p := newTestAlibabaCloudProvider(true)
   339  	endpoints, err := p.Records(context.Background())
   340  	if err != nil {
   341  		t.Errorf("Failed to get records: %v", err)
   342  	} else {
   343  		if len(endpoints) != 2 {
   344  			t.Errorf("Incorrect number of records: %d", len(endpoints))
   345  		}
   346  		for _, endpoint := range endpoints {
   347  			t.Logf("Endpoint for %++v", *endpoint)
   348  		}
   349  	}
   350  }
   351  
   352  func TestAlibabaCloudProvider_ApplyChanges_PrivateZone(t *testing.T) {
   353  	p := newTestAlibabaCloudProvider(true)
   354  	changes := plan.Changes{
   355  		Create: []*endpoint.Endpoint{
   356  			{
   357  				DNSName:    "xyz.container-service.top",
   358  				RecordType: "A",
   359  				RecordTTL:  300,
   360  				Targets:    endpoint.NewTargets("4.3.2.1"),
   361  			},
   362  		},
   363  		UpdateNew: []*endpoint.Endpoint{
   364  			{
   365  				DNSName:    "abc.container-service.top",
   366  				RecordType: "A",
   367  				RecordTTL:  500,
   368  				Targets:    endpoint.NewTargets("1.2.3.4", "5.6.7.8"),
   369  			},
   370  		},
   371  		Delete: []*endpoint.Endpoint{
   372  			{
   373  				DNSName:    "abc.container-service.top",
   374  				RecordType: "TXT",
   375  				RecordTTL:  300,
   376  				Targets:    endpoint.NewTargets("\"heritage=external-dns,external-dns/owner=default\""),
   377  			},
   378  		},
   379  	}
   380  	ctx := context.Background()
   381  	p.ApplyChanges(ctx, &changes)
   382  	endpoints, err := p.Records(ctx)
   383  	if err != nil {
   384  		t.Errorf("Failed to get records: %v", err)
   385  	} else {
   386  		if len(endpoints) != 2 {
   387  			t.Errorf("Incorrect number of records: %d", len(endpoints))
   388  		}
   389  		for _, endpoint := range endpoints {
   390  			t.Logf("Endpoint for %++v", *endpoint)
   391  		}
   392  	}
   393  }
   394  
   395  func TestAlibabaCloudProvider_splitDNSName(t *testing.T) {
   396  	p := newTestAlibabaCloudProvider(false)
   397  	endpoint := &endpoint.Endpoint{}
   398  	hostedZoneDomains := []string{"container-service.top", "example.org"}
   399  
   400  	endpoint.DNSName = "www.example.org"
   401  	rr, domain := p.splitDNSName(endpoint.DNSName, hostedZoneDomains)
   402  	if rr != "www" || domain != "example.org" {
   403  		t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain)
   404  	}
   405  	endpoint.DNSName = ".example.org"
   406  	rr, domain = p.splitDNSName(endpoint.DNSName, hostedZoneDomains)
   407  	if rr != "@" || domain != "example.org" {
   408  		t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain)
   409  	}
   410  	endpoint.DNSName = "www"
   411  	rr, domain = p.splitDNSName(endpoint.DNSName, hostedZoneDomains)
   412  	if rr != "@" || domain != "" {
   413  		t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain)
   414  	}
   415  	endpoint.DNSName = ""
   416  	rr, domain = p.splitDNSName(endpoint.DNSName, hostedZoneDomains)
   417  	if rr != "@" || domain != "" {
   418  		t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain)
   419  	}
   420  	endpoint.DNSName = "_30000._tcp.container-service.top"
   421  	rr, domain = p.splitDNSName(endpoint.DNSName, hostedZoneDomains)
   422  	if rr != "_30000._tcp" || domain != "container-service.top" {
   423  		t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain)
   424  	}
   425  	endpoint.DNSName = "container-service.top"
   426  	rr, domain = p.splitDNSName(endpoint.DNSName, hostedZoneDomains)
   427  	if rr != "@" || domain != "container-service.top" {
   428  		t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain)
   429  	}
   430  	endpoint.DNSName = "a.b.container-service.top"
   431  	rr, domain = p.splitDNSName(endpoint.DNSName, hostedZoneDomains)
   432  	if rr != "a.b" || domain != "container-service.top" {
   433  		t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain)
   434  	}
   435  	endpoint.DNSName = "a.b.c.container-service.top"
   436  	rr, domain = p.splitDNSName(endpoint.DNSName, hostedZoneDomains)
   437  	if rr != "a.b.c" || domain != "container-service.top" {
   438  		t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain)
   439  	}
   440  	endpoint.DNSName = "a.b.c.container-service.top"
   441  	rr, domain = p.splitDNSName(endpoint.DNSName, []string{"c.container-service.top"})
   442  	if rr != "a.b" || domain != "c.container-service.top" {
   443  		t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain)
   444  	}
   445  
   446  	endpoint.DNSName = "a.b.c.container-service.top"
   447  	rr, domain = p.splitDNSName(endpoint.DNSName, []string{"container-service.top", "c.container-service.top"})
   448  	if rr != "a.b" || domain != "c.container-service.top" {
   449  		t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain)
   450  	}
   451  }
   452  
   453  func TestAlibabaCloudProvider_TXTEndpoint(t *testing.T) {
   454  	p := newTestAlibabaCloudProvider(false)
   455  	const recordValue = "heritage=external-dns,external-dns/owner=default"
   456  	const endpointTarget = "\"heritage=external-dns,external-dns/owner=default\""
   457  
   458  	if p.escapeTXTRecordValue(endpointTarget) != endpointTarget {
   459  		t.Errorf("Failed to escapeTXTRecordValue: %s", p.escapeTXTRecordValue(endpointTarget))
   460  	}
   461  	if p.unescapeTXTRecordValue(recordValue) != endpointTarget {
   462  		t.Errorf("Failed to unescapeTXTRecordValue: %s", p.unescapeTXTRecordValue(recordValue))
   463  	}
   464  }
   465  
   466  // TestAlibabaCloudProvider_TXTEndpoint_PrivateZone
   467  func TestAlibabaCloudProvider_TXTEndpoint_PrivateZone(t *testing.T) {
   468  	p := newTestAlibabaCloudProvider(true)
   469  	const recordValue = "heritage=external-dns,external-dns/owner=default"
   470  	const endpointTarget = "\"heritage=external-dns,external-dns/owner=default\""
   471  
   472  	if p.escapeTXTRecordValue(endpointTarget) != endpointTarget {
   473  		t.Errorf("Failed to escapeTXTRecordValue: %s", p.escapeTXTRecordValue(endpointTarget))
   474  	}
   475  	if p.unescapeTXTRecordValue(recordValue) != endpointTarget {
   476  		t.Errorf("Failed to unescapeTXTRecordValue: %s", p.unescapeTXTRecordValue(recordValue))
   477  	}
   478  }