Skip to content

Commit

Permalink
replace the azcore.ResponseError error message to make it stable acro…
Browse files Browse the repository at this point in the history
…ss retries

Signed-off-by: Tim Ramlot <42113979+inteon@users.noreply.github.com>
  • Loading branch information
inteon committed Jan 30, 2024
1 parent 68605bd commit 90cbbc9
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 3 deletions.
51 changes: 48 additions & 3 deletions pkg/issuer/acme/dns/azuredns/azuredns.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ package azuredns

import (
"context"
"errors"
"fmt"
"os"
"strings"
Expand Down Expand Up @@ -154,7 +155,7 @@ func (c *DNSProvider) CleanUp(domain, fqdn, value string) error {
c.trimFqdn(fqdn, z),
dns.RecordTypeTXT, nil)
if err != nil {
return err
return stabilizeError(err)
}
return nil
}
Expand Down Expand Up @@ -184,7 +185,7 @@ func (c *DNSProvider) createRecord(fqdn, value string, ttl int) error {
*rparams, nil)
if err != nil {
c.log.Error(err, "Error creating TXT:", z)
return err
return stabilizeError(err)
}
return nil
}
Expand All @@ -205,7 +206,7 @@ func (c *DNSProvider) getHostedZoneName(fqdn string) (string, error) {
_, err = c.zoneClient.Get(context.TODO(), c.resourceGroupName, util.UnFqdn(z), nil)

if err != nil {
return "", fmt.Errorf("Zone %s not found in AzureDNS for domain %s. Err: %v", z, fqdn, err)
return "", fmt.Errorf("Zone %s not found in AzureDNS for domain %s. Err: %v", z, fqdn, stabilizeError(err))
}

return util.UnFqdn(z), nil
Expand All @@ -219,3 +220,47 @@ func (c *DNSProvider) trimFqdn(fqdn string, zone string) string {
}
return strings.TrimSuffix(strings.TrimSuffix(fqdn, "."), "."+z)
}

// The azure-sdk library returns the contents of the HTTP requests in its
// error messages. We want our error messages to be the same when the cause
// is the same to avoid spurious challenge updates.
//
// The given error must not be nil. This function must be called everywhere
// we have a non-nil error coming from a azure-sdk func that makes API calls.
func stabilizeError(err error) error {
if err == nil {
return nil
}

var respErr *azcore.ResponseError
if errors.As(err, &respErr) {
method := "<UNKNOWN-METHOD>"
url := "<UNKNOWN-URL>"
response := "<UNKNOWN-RESPONSE>"
if respErr.RawResponse.Request != nil {
method = respErr.RawResponse.Request.Method
url = fmt.Sprintf(
"%s://%s%s",
respErr.RawResponse.Request.URL.Scheme,
respErr.RawResponse.Request.URL.Host,
respErr.RawResponse.Request.URL.Path,
)
response = fmt.Sprintf("%d: %s", respErr.RawResponse.StatusCode, respErr.RawResponse.Status)
}

errorCode := "<UNKNOWN-ERROR-CODE>"
if respErr.ErrorCode != "" {
errorCode = respErr.ErrorCode
}

return fmt.Errorf(
"Error making AzureDNS API request:\n%s %s\nRESPONSE %s\nERROR CODE: %s",
method,
url,
response,
errorCode,
)
}

return err
}
50 changes: 50 additions & 0 deletions pkg/issuer/acme/dns/azuredns/azuredns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ package azuredns
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/http/httptest"
Expand All @@ -20,12 +21,16 @@ import (
"testing"
"time"

"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
dns "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns"
v1 "github.com/cert-manager/cert-manager/pkg/apis/acme/v1"
"github.com/cert-manager/cert-manager/pkg/issuer/acme/dns/util"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/util/rand"
)

var (
Expand Down Expand Up @@ -264,3 +269,48 @@ func TestGetAuthorizationFederatedSPT(t *testing.T) {
assert.NotEmpty(t, token.Token, "Access token should have been set to a value returned by the webserver")
})
}

// TestStabilizeError tests that the errors returned by the AzureDNS API are
// changed to be stable. We want our error messages to be the same when the cause
// is the same to avoid spurious challenge updates.
func TestStabilizeError(t *testing.T) {
ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadGateway)
randomMessage := "test error message: " + rand.String(10)
payload := fmt.Sprintf(`{"error":{"code":"TEST_ERROR_CODE","message":"%s"}}`, randomMessage)
if _, err := w.Write([]byte(payload)); err != nil {
assert.FailNow(t, err.Error())
}
}))

defer ts.Close()

clientOpt := policy.ClientOptions{
Cloud: cloud.Configuration{
ActiveDirectoryAuthorityHost: ts.URL,
Services: map[cloud.ServiceName]cloud.ServiceConfiguration{
cloud.ResourceManager: {
Audience: ts.URL,
Endpoint: ts.URL,
},
},
},
Transport: ts.Client(),
}

zc, err := dns.NewZonesClient("subscriptionID", nil, &arm.ClientOptions{ClientOptions: clientOpt})
require.NoError(t, err)

dnsProvider := DNSProvider{
dns01Nameservers: util.RecursiveNameservers,
resourceGroupName: "resourceGroupName",
zoneClient: zc,
}

err = dnsProvider.Present("test.com", "fqdn.test.com.", "test123")
require.Error(t, err)
require.ErrorContains(t, err, fmt.Sprintf(`Zone test.com. not found in AzureDNS for domain fqdn.test.com.. Err: Error making AzureDNS API request:
GET %s/subscriptions/subscriptionID/resourceGroups/resourceGroupName/providers/Microsoft.Network/dnsZones/test.com
RESPONSE 502: 502 Bad Gateway
ERROR CODE: TEST_ERROR_CODE`, ts.URL))
}

0 comments on commit 90cbbc9

Please sign in to comment.