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 }