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 }