diff --git a/cmd/cli/cli.go b/cmd/cli/cli.go index fc18f44..7f7a749 100644 --- a/cmd/cli/cli.go +++ b/cmd/cli/cli.go @@ -25,7 +25,14 @@ func main() { os.Exit(1) } - if len(probs) == 0 { + errorProbs := []letsdebug.Problem{} + for _, p := range probs { + if p.Severity != letsdebug.SeverityInfo && p.Severity != letsdebug.SeverityDebug { + errorProbs = append(errorProbs, p) + } + } + + if len(errorProbs) == 0 { fmt.Println("All OK!") return } diff --git a/generic.go b/generic.go index 7bffb1e..56fa177 100644 --- a/generic.go +++ b/generic.go @@ -7,10 +7,6 @@ import ( "encoding/pem" "encoding/xml" "errors" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promauto" - "golang.org/x/net/idna" - "golang.org/x/text/unicode/norm" "net" "os" "regexp" @@ -18,6 +14,11 @@ import ( "strings" "sync" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + "golang.org/x/net/idna" + "golang.org/x/text/unicode/norm" + "github.com/eggsampler/acme/v3" "fmt" @@ -462,7 +463,7 @@ func statusioNotOperational(status string, updated time.Time) Problem { Explanation: fmt.Sprintf(`The current status as reported by the Let's Encrypt status page is %s as at %v. `+ `Depending on the reported problem, this may affect certificate issuance. For more information, please visit the status page.`, status, updated), Detail: "https://letsencrypt.status.io/", - Severity: SeverityWarning, + Severity: SeverityInfo, } } @@ -787,12 +788,20 @@ func (c *acmeStagingChecker) Check(ctx *scanContext, domain string, method Valid authz, err := c.client.FetchAuthorization(c.account, authzURL) if err != nil { - unhandledError(err) + if p, stagingBroken := translateAcmeError(domain, err); p.Name != "" { + if stagingBroken { + stagingFailures.With(prometheus.Labels{"method": string(method)}).Inc() + } + probs = append(probs, p) + } else { + unhandledError(err) + } return } chal, ok := authz.ChallengeMap[string(method)] if !ok { + // TODO: we sometimes run into this if an authorization is reused unhandledError(fmt.Errorf("Missing challenge method (want %v): %v", method, authz.ChallengeMap)) return } @@ -830,6 +839,9 @@ func translateAcmeError(domain string, err error) (problem Problem, stagingBroke urn := strings.TrimPrefix(acmeErr.Type, "urn:ietf:params:acme:error:") switch urn { case "rejectedIdentifier", "unknownHost", "rateLimited", "caa", "dns", "connection": + if strings.Contains(acmeErr.Detail, "Service busy; retry later") { + return infoProblem("ServiceBusy", "The Let's Encrypt staging service refused our request for a test dry-run. The test outputs may not be accurate. Please retry the test at a later time.", "Let's Encrypt Staging Sever busy."), true + } // Boulder can send error:dns when _acme-challenge is NXDOMAIN, which is // equivalent to unauthorized if strings.Contains(acmeErr.Detail, "NXDOMAIN looking up TXT") { diff --git a/problem.go b/problem.go index 1a2689f..50a84ca 100644 --- a/problem.go +++ b/problem.go @@ -19,6 +19,7 @@ type Problem struct { } const ( + SeverityInfo SeverityLevel = "Info" // Represents informational messages which are not necessarily a problem. SeverityFatal SeverityLevel = "Fatal" // Represents a fatal error which will stop any further checks SeverityError SeverityLevel = "Error" SeverityWarning SeverityLevel = "Warning" @@ -73,3 +74,12 @@ func debugProblem(name, message, detail string) Problem { Severity: SeverityDebug, } } + +func infoProblem(name, message, detail string) Problem { + return Problem{ + Name: name, + Explanation: message, + Detail: detail, + Severity: SeverityInfo, + } +} diff --git a/web/db.go b/web/db.go index e55ce20..9225d0c 100644 --- a/web/db.go +++ b/web/db.go @@ -5,13 +5,14 @@ import ( "database/sql/driver" "embed" "fmt" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promauto" "log" "sort" "strings" "time" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/lib/pq" "encoding/json" @@ -79,6 +80,7 @@ func (probs problems) Less(i, j int) bool { type resultView struct { Error string `json:"error,omitempty"` Problems problems `json:"problems,omitempty"` + IsOk bool `json:"ok"` } func (rv *resultView) Scan(src interface{}) error { diff --git a/web/templates/layouts/results.tpl b/web/templates/layouts/results.tpl index b4a7af8..09e1859 100644 --- a/web/templates/layouts/results.tpl +++ b/web/templates/layouts/results.tpl @@ -32,6 +32,10 @@ color: #eee; background: rgb(0, 77, 0); } +.problem-Info, .problem-Info a, .problem-Info a:visited { + background: lightgray; + color: black; +} .problem-Debug, .problem-Debug a, .problem-Debug a:visited { background: lightskyblue; color: black; @@ -115,7 +119,8 @@
Unfortunately something went wrong when running the test.
Submitted {{ .Test.SubmitTime }}. {{ if .Test.QueueDuration }}Sat in queue for {{ .Test.QueueDuration }}.{{ end }} diff --git a/web/work.go b/web/work.go index 04c7881..c27a1e8 100644 --- a/web/work.go +++ b/web/work.go @@ -2,11 +2,12 @@ package web import ( "encoding/json" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promauto" "log" "sync/atomic" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/letsdebug/letsdebug" ) @@ -56,8 +57,20 @@ func (s *server) work() { HTTPExpectResponse: req.Options.HTTPExpectResponse, HTTPRequestPath: req.Options.HTTPRequestPath, }) + isOk := false + if err == nil { + isOk = true + for _, p := range res { + if p.Severity != letsdebug.SeverityInfo && p.Severity != letsdebug.SeverityDebug { + isOk = false + break + } + } + } else { + isOk = false + } testsRun.With(prometheus.Labels{"method": string(method)}).Inc() - result := resultView{Problems: res} + result := resultView{Problems: res, IsOk: isOk} if err != nil { testsFailed.With(prometheus.Labels{"method": string(method)}).Inc() result.Error = err.Error()