-
Notifications
You must be signed in to change notification settings - Fork 192
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
OCPBUGS-32776: Fix IBM Public Cloud DNS Provider Update Logic #1133
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -103,6 +103,9 @@ func (p *Provider) Delete(record *iov1.DNSRecord, zone configv1.DNSZone) error { | |||
|
||||
for _, resourceRecord := range result.ResourceRecords { | ||||
var resourceRecordTarget string | ||||
if resourceRecord.ID == nil { | ||||
return fmt.Errorf("delete: record id is nil") | ||||
} | ||||
rData, ok := resourceRecord.Rdata.(map[string]interface{}) | ||||
if !ok { | ||||
return fmt.Errorf("delete: failed to get resource data: %v", resourceRecord.Rdata) | ||||
|
@@ -126,7 +129,8 @@ func (p *Provider) Delete(record *iov1.DNSRecord, zone configv1.DNSZone) error { | |||
default: | ||||
return fmt.Errorf("delete: resource data has record with unknown type: %v", *resourceRecord.Type) | ||||
} | ||||
|
||||
// While creating DNS records with multiple targets is unsupported, we still | ||||
// iterate through all targets during deletion to be extra cautious. | ||||
for _, target := range record.Spec.Targets { | ||||
if *resourceRecord.Name == dnsName { | ||||
if resourceRecordTarget != target { | ||||
|
@@ -190,9 +194,15 @@ func (p *Provider) createOrUpdateDNSRecord(record *iov1.DNSRecord, zone configv1 | |||
log.Info("Warning: TTL must be one of [1 60 120 300 600 900 1800 3600 7200 18000 43200]. RecordTTL set to default", "default DSNSVCS record TTL", defaultDNSSVCSRecordTTL) | ||||
record.Spec.RecordTTL = defaultDNSSVCSRecordTTL | ||||
} | ||||
// We only support one target, warn the user. | ||||
if len(record.Spec.Targets) > 1 { | ||||
log.Error(nil, "Only one DNSRecord target is supported. Additional targets will be ignored", "targets", record.Spec.Targets) | ||||
} | ||||
|
||||
listResult, response, err := p.dnsService.ListResourceRecords(listOpt) | ||||
if err != nil { | ||||
// Avoid continuing with an invalid list response, as we can't determine | ||||
// whether to create or update the DNS record, which may lead to further issues. | ||||
if response == nil || response.StatusCode != http.StatusNotFound { | ||||
return fmt.Errorf("createOrUpdateDNSRecord: failed to list the dns record: %w", err) | ||||
} | ||||
|
@@ -201,72 +211,74 @@ func (p *Provider) createOrUpdateDNSRecord(record *iov1.DNSRecord, zone configv1 | |||
return fmt.Errorf("createOrUpdateDNSRecord: ListResourceRecords returned nil as result") | ||||
} | ||||
|
||||
for _, target := range record.Spec.Targets { | ||||
updated := false | ||||
for _, resourceRecord := range listResult.ResourceRecords { | ||||
if *resourceRecord.Name == dnsName { | ||||
updateOpt := p.dnsService.NewUpdateResourceRecordOptions(p.config.InstanceID, zone.ID, *resourceRecord.ID) | ||||
updateOpt.SetName(dnsName) | ||||
|
||||
if resourceRecord.Type == nil { | ||||
return fmt.Errorf("createOrUpdateDNSRecord: failed to get resource type, resourceRecord.Type is nil") | ||||
} | ||||
target := record.Spec.Targets[0] | ||||
updated := false | ||||
for _, resourceRecord := range listResult.ResourceRecords { | ||||
if *resourceRecord.Name == dnsName { | ||||
if resourceRecord.ID == nil { | ||||
return fmt.Errorf("createOrUpdateDNSRecord: record id is nil") | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not continue here instead of returning an error? Wouldn't we want to find a matching resourceRecord if possible? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was added because if the
|
||||
} | ||||
updateOpt := p.dnsService.NewUpdateResourceRecordOptions(p.config.InstanceID, zone.ID, *resourceRecord.ID) | ||||
updateOpt.SetName(dnsName) | ||||
|
||||
// TODO DNS record update should handle the case where we have an A record and want a CNAME record or vice versa | ||||
switch *resourceRecord.Type { | ||||
case string(iov1.CNAMERecordType): | ||||
inputRData, err := p.dnsService.NewResourceRecordUpdateInputRdataRdataCnameRecord(target) | ||||
if err != nil { | ||||
return fmt.Errorf("createOrUpdateDNSRecord: failed to create CNAME inputRData for the dns record: %w", err) | ||||
} | ||||
updateOpt.SetRdata(inputRData) | ||||
case string(iov1.ARecordType): | ||||
inputRData, err := p.dnsService.NewResourceRecordUpdateInputRdataRdataARecord(target) | ||||
if err != nil { | ||||
return fmt.Errorf("createOrUpdateDNSRecord: failed to create A inputRData for the dns record: %w", err) | ||||
} | ||||
updateOpt.SetRdata(inputRData) | ||||
default: | ||||
return fmt.Errorf("createOrUpdateDNSRecord: resource data has record with unknown type: %v", *resourceRecord.Type) | ||||
} | ||||
updateOpt.SetTTL(record.Spec.RecordTTL) | ||||
_, _, err := p.dnsService.UpdateResourceRecord(updateOpt) | ||||
if err != nil { | ||||
return fmt.Errorf("createOrUpdateDNSRecord: failed to update the dns record: %w", err) | ||||
} | ||||
updated = true | ||||
log.Info("updated DNS record", "record", record.Spec, "zone", zone, "target", target) | ||||
if resourceRecord.Type == nil { | ||||
return fmt.Errorf("createOrUpdateDNSRecord: failed to get resource type, resourceRecord.Type is nil") | ||||
} | ||||
} | ||||
if !updated { | ||||
createOpt := p.dnsService.NewCreateResourceRecordOptions(p.config.InstanceID, zone.ID) | ||||
createOpt.SetName(dnsName) | ||||
createOpt.SetType(string(record.Spec.RecordType)) | ||||
|
||||
switch record.Spec.RecordType { | ||||
case iov1.CNAMERecordType: | ||||
inputRData, err := p.dnsService.NewResourceRecordInputRdataRdataCnameRecord(target) | ||||
|
||||
// TODO DNS record update should handle the case where we have an A record and want a CNAME record or vice versa | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see this is a carried-over TODO, but should it be done now in order to fix the bug? Or is it out of scope? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's out of scope for this bug since it can be fixed independently. This TODO is for when someone changes the |
||||
switch *resourceRecord.Type { | ||||
case string(iov1.CNAMERecordType): | ||||
inputRData, err := p.dnsService.NewResourceRecordUpdateInputRdataRdataCnameRecord(target) | ||||
if err != nil { | ||||
return fmt.Errorf("createOrUpdateDNSRecord: failed to create CNAME inputRData for the dns record: %w", err) | ||||
} | ||||
createOpt.SetRdata(inputRData) | ||||
case iov1.ARecordType: | ||||
inputRData, err := p.dnsService.NewResourceRecordInputRdataRdataARecord(target) | ||||
updateOpt.SetRdata(inputRData) | ||||
case string(iov1.ARecordType): | ||||
inputRData, err := p.dnsService.NewResourceRecordUpdateInputRdataRdataARecord(target) | ||||
if err != nil { | ||||
return fmt.Errorf("createOrUpdateDNSRecord: failed to create A inputRData for the dns record: %w", err) | ||||
} | ||||
createOpt.SetRdata(inputRData) | ||||
updateOpt.SetRdata(inputRData) | ||||
default: | ||||
return fmt.Errorf("createOrUpdateDNSRecord: resource data has record with unknown type: %v", record.Spec.RecordType) | ||||
|
||||
return fmt.Errorf("createOrUpdateDNSRecord: resource data has record with unknown type: %v", *resourceRecord.Type) | ||||
} | ||||
updateOpt.SetTTL(record.Spec.RecordTTL) | ||||
_, _, err := p.dnsService.UpdateResourceRecord(updateOpt) | ||||
if err != nil { | ||||
return fmt.Errorf("createOrUpdateDNSRecord: failed to update the dns record: %w", err) | ||||
} | ||||
updated = true | ||||
log.Info("updated DNS record", "record", record.Spec, "zone", zone, "target", target) | ||||
} | ||||
} | ||||
if !updated { | ||||
createOpt := p.dnsService.NewCreateResourceRecordOptions(p.config.InstanceID, zone.ID) | ||||
createOpt.SetName(dnsName) | ||||
createOpt.SetType(string(record.Spec.RecordType)) | ||||
|
||||
switch record.Spec.RecordType { | ||||
case iov1.CNAMERecordType: | ||||
inputRData, err := p.dnsService.NewResourceRecordInputRdataRdataCnameRecord(target) | ||||
if err != nil { | ||||
return fmt.Errorf("createOrUpdateDNSRecord: failed to create CNAME inputRData for the dns record: %w", err) | ||||
} | ||||
createOpt.SetTTL(record.Spec.RecordTTL) | ||||
_, _, err := p.dnsService.CreateResourceRecord(createOpt) | ||||
createOpt.SetRdata(inputRData) | ||||
case iov1.ARecordType: | ||||
inputRData, err := p.dnsService.NewResourceRecordInputRdataRdataARecord(target) | ||||
if err != nil { | ||||
return fmt.Errorf("createOrUpdateDNSRecord: failed to create the dns record: %w", err) | ||||
return fmt.Errorf("createOrUpdateDNSRecord: failed to create A inputRData for the dns record: %w", err) | ||||
} | ||||
log.Info("created DNS record", "record", record.Spec, "zone", zone, "target", target) | ||||
createOpt.SetRdata(inputRData) | ||||
default: | ||||
return fmt.Errorf("createOrUpdateDNSRecord: resource data has record with unknown type: %v", record.Spec.RecordType) | ||||
|
||||
} | ||||
createOpt.SetTTL(record.Spec.RecordTTL) | ||||
_, _, err := p.dnsService.CreateResourceRecord(createOpt) | ||||
if err != nil { | ||||
return fmt.Errorf("createOrUpdateDNSRecord: failed to create the dns record: %w", err) | ||||
} | ||||
log.Info("created DNS record", "record", record.Spec, "zone", zone, "target", target) | ||||
} | ||||
return nil | ||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why would we check the
InputId
against theName
here? Can you add a comment to explain?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did this mainly to be consistent with the existing patterns, but it ensures that the
incoming
createResourceRecordOptions.Name
parameter is getting configured correctly.InputID
is equivalent to the name, it's just named generically to keep all update/create/delete structs similar.I'll add a comment.