62 lines
1.7 KiB
Go
62 lines
1.7 KiB
Go
package gcp
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"slices"
|
|
|
|
"google.golang.org/api/googleapi"
|
|
|
|
"gitea.home.hrajfrisbee.cz/kacerr/egress-proxies-operator/internal/provider"
|
|
)
|
|
|
|
// classify maps a GCP API error onto the provider taxonomy:
|
|
// 404 → NotFound; 429 and quota-flavored 403s → QuotaExceeded;
|
|
// 400/401/other 403s → Permanent; 408/5xx and anything unrecognized
|
|
// (network errors, context cancellation) → Transient, because retrying is
|
|
// always safer than latching Failed on an error nobody taught this
|
|
// function to recognize.
|
|
func classify(err error) error {
|
|
var gerr *googleapi.Error
|
|
if !errors.As(err, &gerr) {
|
|
return provider.ErrTransient
|
|
}
|
|
switch {
|
|
case gerr.Code == http.StatusNotFound:
|
|
return provider.ErrNotFound
|
|
case gerr.Code == http.StatusTooManyRequests:
|
|
return provider.ErrQuotaExceeded
|
|
case gerr.Code == http.StatusForbidden && hasReason(gerr, "quotaExceeded", "rateLimitExceeded"):
|
|
return provider.ErrQuotaExceeded
|
|
case gerr.Code == http.StatusBadRequest,
|
|
gerr.Code == http.StatusUnauthorized,
|
|
gerr.Code == http.StatusForbidden:
|
|
return provider.ErrPermanent
|
|
default:
|
|
return provider.ErrTransient
|
|
}
|
|
}
|
|
|
|
func (p *Provider) wrapErr(op, id string, err error) error {
|
|
return provider.Wrap(classify(err), op, p.name, id, err)
|
|
}
|
|
|
|
func hasReason(gerr *googleapi.Error, reasons ...string) bool {
|
|
for _, item := range gerr.Errors {
|
|
if slices.Contains(reasons, item.Reason) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func isAlreadyExists(err error) bool {
|
|
var gerr *googleapi.Error
|
|
return errors.As(err, &gerr) && gerr.Code == http.StatusConflict
|
|
}
|
|
|
|
func isNotFound(err error) bool {
|
|
var gerr *googleapi.Error
|
|
return errors.As(err, &gerr) && gerr.Code == http.StatusNotFound
|
|
}
|