Skip to content

Commit e0f82d3

Browse files
Merge pull request openshift#216 from aliceh/dns
Added output of response status from cloudflare
2 parents 7a0eccc + e68c882 commit e0f82d3

File tree

3 files changed

+63
-28
lines changed

3 files changed

+63
-28
lines changed

pkg/controller/certificaterequest/cloudflare.go

Lines changed: 49 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,31 +25,32 @@ import (
2525
"time"
2626

2727
"github.com/go-logr/logr"
28+
"github.com/openshift/certman-operator/pkg/localmetrics"
2829
"github.com/pkg/errors"
2930
)
3031

31-
type CloudflareQuestion struct {
32+
type DnsServerQuestion struct {
3233
Name string `json:"name"`
3334
Type int `json:"type"`
3435
}
3536

36-
type CloudflareAnswer struct {
37+
type DnsServerAnswer struct {
3738
Name string `json:"name"`
3839
Type int `json:"type"`
3940
TTL int `json:"TTL"`
4041
Data string `json:"data"`
4142
}
4243

43-
type CloudflareResponse struct {
44-
Status int `json:"Status"`
45-
TC bool `json:"TC"`
46-
RC bool `json:"RC"`
47-
RA bool `json:"RA"`
48-
AD bool `json:"AD"`
49-
CD bool `json:"CD"`
50-
Questions []CloudflareQuestion `json:"Question"`
51-
Answers []CloudflareAnswer `json:"Answer"`
52-
Authority []CloudflareAnswer `json:"Authority"`
44+
type DnsServerResponse struct {
45+
Status int `json:"Status"`
46+
TC bool `json:"TC"`
47+
RC bool `json:"RC"`
48+
RA bool `json:"RA"`
49+
AD bool `json:"AD"`
50+
CD bool `json:"CD"`
51+
Questions []DnsServerQuestion `json:"Question"`
52+
Answers []DnsServerAnswer `json:"Answer"`
53+
Authority []DnsServerAnswer `json:"Authority"`
5354
}
5455

5556
// VerifyDnsResourceRecordUpdate verifies the presence of a TXT record with Cloudflare DNS.
@@ -83,7 +84,7 @@ func VerifyDnsResourceRecordUpdate(reqLogger logr.Logger, fqdn string, txtValue
8384

8485
negativeCacheTTL = 0
8586

86-
response, err := FetchResourceRecordUsingCloudflareDNS(reqLogger, fqdn)
87+
response, err := TryFetchResourceRecordUsingPublicDNS(reqLogger, fqdn)
8788
if err != nil {
8889
reqLogger.Error(err, "failed to fetch DNS records")
8990
continue
@@ -121,22 +122,37 @@ func VerifyDnsResourceRecordUpdate(reqLogger logr.Logger, fqdn string, txtValue
121122
return false
122123
}
123124

124-
// FetchResourceRecordUsingCloudflareDNS contacts cloudflareDnsOverHttpsEndpoint and returns the json response.
125-
func FetchResourceRecordUsingCloudflareDNS(reqLogger logr.Logger, name string) (*CloudflareResponse, error) {
126-
requestUrl := cloudflareDNSOverHttpsEndpoint + "?name=" + name + "&type=TXT"
125+
//Added TryFetchResourceRecordUsingPublicDNS which will run FetchResourceRecordUsingPublicDNS with cloudflareDNSOverHttpsEndpoint first,
126+
// and if that call fails (for instance, if cloudflare is down) will run FetchResourceRecordUsingPublicDNS with googleDNSOverHttpsEndpoint
127+
func TryFetchResourceRecordUsingPublicDNS(reqLogger logr.Logger, name string) (*DnsServerResponse, error) {
127128

128-
reqLogger.Info(fmt.Sprintf("cloudflare dns-over-https Request URL: %v", requestUrl))
129+
130+
response, err := FetchResourceRecordUsingPublicDNS(reqLogger, name, cloudflareDNSOverHttpsEndpoint)
131+
if err != nil {
132+
response, err = FetchResourceRecordUsingPublicDNS(reqLogger, name, googleDNSOverHttpsEndpoint)
133+
}
134+
if err != nil {
135+
localmetrics.IncrementDnsErrorCount()
136+
}
137+
return response, err
138+
}
139+
140+
// FetchResourceRecordUsingPublicDNS contacts dnsOverHttpsEndpoint and returns the json response.
141+
func FetchResourceRecordUsingPublicDNS(reqLogger logr.Logger, name string, dnsOverHttpsEndpoint string) (*DnsServerResponse, error) {
142+
requestUrl := dnsOverHttpsEndpoint + "?name=" + name + "&type=TXT"
143+
144+
reqLogger.Info(fmt.Sprintf("public DNS dns-over-https Request URL: %v", requestUrl))
129145

130146
var request, err = http.NewRequest("GET", requestUrl, nil)
131147
if err != nil {
132-
reqLogger.Error(err, "error occurred creating new cloudflare dns-over-https request")
148+
reqLogger.Error(err, "error occurred creating new dns-over-https request")
133149
return nil, err
134150
}
135151

136-
request.Header.Set("accept", cloudflareRequestContentType)
152+
request.Header.Set("accept", dnsServerRequestContentType)
137153

138154
netClient := &http.Client{
139-
Timeout: time.Second * cloudflareRequestTimeout,
155+
Timeout: time.Second * dnsServerRequestTimeout,
140156
}
141157

142158
response, err := netClient.Do(request)
@@ -152,15 +168,23 @@ func FetchResourceRecordUsingCloudflareDNS(reqLogger logr.Logger, name string) (
152168
return nil, err
153169
}
154170

155-
reqLogger.Info("response from Cloudflare: " + string(responseBody))
171+
if 400 <= response.StatusCode && response.StatusCode <= 499 {
172+
reqLogger.Info("Client Error: " + response.Status)
173+
} else if 500 <= response.StatusCode && response.StatusCode <= 599 {
174+
reqLogger.Info("Server Error: " + response.Status)
175+
} else {
176+
reqLogger.Info("response Status from the public DNS Server : " + response.Status)
177+
}
178+
179+
reqLogger.Info("response from the public DNS Server: " + string(responseBody))
156180

157-
var cloudflareResponse CloudflareResponse
181+
var dnsServerResponse DnsServerResponse
158182

159-
err = json.Unmarshal(responseBody, &cloudflareResponse)
183+
err = json.Unmarshal(responseBody, &dnsServerResponse)
160184
if err != nil {
161-
reqLogger.Error(err, "there was problem parsing the json response from cloudflare.")
185+
reqLogger.Error(err, "there was problem parsing the json response from the public DNS Server.")
162186
return nil, err
163187
}
164188

165-
return &cloudflareResponse, nil
189+
return &dnsServerResponse, nil
166190
}

pkg/controller/certificaterequest/constants.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,15 @@ type dnsRCode int
2020

2121
const (
2222
cloudflareDNSOverHttpsEndpoint = "https://cloudflare-dns.com/dns-query"
23-
cloudflareRequestContentType = "application/dns-json"
24-
cloudflareRequestTimeout = 60
23+
googleDNSOverHttpsEndpoint = "https://dns.google/dns-query"
24+
dnsServerRequestContentType = "application/dns-json"
25+
dnsServerRequestTimeout = 60
2526
maxAttemptsForDnsPropagationCheck = 10 // Try 10 times (5 minutes total)
2627
waitTimePeriodDnsPropagationCheck = 30 // Wait 30 seconds between checks
2728
maxNegativeCacheTTL = 600 // Sleep no more than 10 minutes
2829
reissueCertificateBeforeDays = 45 // This helps us avoid getting email notifications from Let's Encrypt.
2930
rSAKeyBitSize = 2048
3031

3132
// From golang.org/x/net/dns/dnsmessage
32-
dnsRCodeNameError dnsRCode = 3
33+
dnsRCodeNameError dnsRCode = 3
3334
)

pkg/localmetrics/localmetrics.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ var (
8080
Name: "certman_operator_lets_encrypt_maintenance_error_count",
8181
Help: "The number of Let's Encrypt maintenance errors received",
8282
})
83+
MetricDnsErrorCount = prometheus.NewCounter(prometheus.CounterOpts{
84+
Name: "cloudflare_failed_requests_count",
85+
Help: "Counter on the number of failed DNS requests",
86+
})
8387

8488
MetricsList = []prometheus.Collector{
8589
MetricCertsIssuedInLastDayDevshiftOrg,
@@ -92,6 +96,7 @@ var (
9296
MetricClusterDeploymentReconcileDuration,
9397
MetricCertRequestsCount,
9498
MetricCertIssuanceRate,
99+
MetricDnsErrorCount,
95100
MetricCertValidDuration,
96101
MetricLetsEncryptMaintenanceErrorCount,
97102
}
@@ -182,3 +187,8 @@ func UpdateCertValidDuration(cert *x509.Certificate) {
182187
func IncrementLetsEncryptMaintenanceErrorCount() {
183188
MetricLetsEncryptMaintenanceErrorCount.Inc()
184189
}
190+
191+
// IncrementDnsErrorCount Increment the count of DNS errors
192+
func IncrementDnsErrorCount() {
193+
MetricDnsErrorCount.Inc()
194+
}

0 commit comments

Comments
 (0)