Repository navigation
fix(gcp): stop emitting Cloud SQL and Memorystore CUDs from PerformanceRecommenders - #493
Conversation
…ceRecommenders The Cloud SQL and Memorystore clients listed the project-scoped google.cloudsql.instance.PerformanceRecommender and google.memorystore.redis.PerformanceRecommender, which give per-instance tuning advice, and relabeled every ACTIVE item as a 1yr CUD with savings taken from its cost projection (zero when absent). Cloud SQL and Memorystore CUDs are spend-based and are recommended only at Cloud Billing account scope, which this provider does not collect yet (see docs/design/gcp-spend-commitments.md). Mirror the Cloud Storage treatment (LeanerCloud#193, LeanerCloud#219): - Both clients' GetRecommendations return an error wrapping common.ErrCommitmentPurchaseNotSupported without calling the Recommender API. The recommender wrapper, page cap and converter that only served that path are removed; SetRecommenderClient and the RecommenderClient/RecommenderIterator types stay as deprecated source-compatibility shims. Pricing (GetOfferingDetails, ValidateOffering) is unchanged. - The region fan-out calls only the Compute Engine commitment recommender, and an explicit Cloud SQL or Memorystore request returns the not-supported error once, before any region lookup. - GetSupportedServices returns only ServiceCompute. Closes LeanerCloud#294 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reached
This review includes 14 billable files and costs up to $3.50. Or wait 59 minutes for your next included review. View limit details
Comment |
Independent adversarial review: CLEAN at
|
|
Merge driver status: draft; waiting on the author to mark it ready. The independent verdict is posted above. Once it is un-drafted, I will update the branch with |
Closes #294
Root cause
cloudsql.Client.GetRecommendationsandmemorystore.Client.GetRecommendationslisted the project-scopedgoogle.cloudsql.instance.PerformanceRecommenderandgoogle.memorystore.redis.PerformanceRecommender. Those give per-instance tuning advice (Cloud SQL's are query, index and settings tips), not commitments. Every ACTIVE item was still converted into aCommitmentCUDwith the default1yrterm andEstimatedSavingstaken from its cost projection, which came out as 0 when the projection was missing and negative when it was a cost increase. The region fan-out ran both on every collection (about 80 extra Recommender calls across ~40 regions). Cloud SQL and Memorystore CUDs are spend-based, and Google recommends them only at Cloud Billing account scope (google.cloudbilling.commitment.SpendBasedCommitmentRecommender), which this project-scoped provider does not collect yet (docs/design/gcp-spend-commitments.md).go#364 named this issue but did not fix it. Its body says "Not in this PR: G5/#294/#319 (recommender choice)". On
mainat 7383c3a, both clients still query the PerformanceRecommenders (see the fail-before output below).Fix
This takes the issue's first suggested option and follows the Cloud Storage precedent (#193, #219):
GetRecommendationson both clients returns an error wrappingcommon.ErrCommitmentPurchaseNotSupportedand makes no Recommender call. I removed the code that only served that path: the real recommender wrapper, the page cap from fix(gcp): paginate Cloud SQL/Memorystore SKUs and cap recommendations by page #364, andconvertGCPRecommendationwith itsextractGCP*,fill*PricingandtermYearsFromLabelhelpers.SetRecommenderClientand theRecommenderClient/RecommenderIteratortypes stay as deprecated no-op shims, as incloudstorage. Pricing (GetOfferingDetails,ValidateOffering,getSQLPricing/getRedisPricing) is unchanged.collectRegion) now calls only the Compute Engine commitment recommender. An explicit Cloud SQL or Memorystore request returns the client's not-supported error once, before any region lookup, using the same path as Cloud Storage (collectUnsupportedRecs). If the two services had stayed in the fan-out with an always-failing client, their error could becomelastErrand hide a real 403 in the all-failed aggregate (the fix(gcp): stop emitting Cloud Storage recommendations with a bucket name as the tier #193 problem).GetSupportedServicesnow returns onlyServiceCompute.GetServiceClientstill builds both clients for pricing and validation.Verification
All evidence is from unit tests with mocks and fixtures. Provider-level tests use a local httptest regions server and an in-process bufconn gRPC Recommender server; nothing calls Google Cloud. All test runs used
AWS_CONFIG_FILE=/dev/null AWS_SHARED_CREDENTIALS_FILE=/dev/nullbecause the default profile on the dev machine is invalid; the GCP tests don't read it.Regression tests (new or changed):
providers/gcp/performance_recommender_test.goTestGetAllRecommendations_NoPerformanceRecommenderCUDs: every PerformanceRecommender parent answers with an ACTIVE cost-saving recommendation. The test asserts that no recommendations come back and that only the two ComputeUsageCommitmentRecommenderparents are queried.TestGetRecommendations_ExplicitSQLAndCacheAreNotSupported: forrelational-dbandcache, assertsErrCommitmentPurchaseNotSupported, nil recs, zero Recommender calls and zero region lookups.TestCloudSQLClient_GetRecommendations_NotSupportedandTestMemorystoreClient_GetRecommendations_NotSupported: an injected recommender returns an ACTIVE recommendation. Each test asserts the sentinel error, nil recs, and thatListRecommendationsis never called.TestGCPProvider_GetSupportedServices: now asserts[]ServiceType{ServiceCompute}.Fail before (new tests on the unfixed code):
Pass after: all of the above pass.
Mutation probe: dropping
ServiceRelationalDB/ServiceCachefromisUnsupportedRecommendationServicemakesTestGetRecommendations_ExplicitSQLAndCacheAreNotSupportedfail for both subtests. In that state an explicit request falls through to an empty fan-out and returns(nil, nil).Commands, run at the pushed head:
This repo has no
internal/mocksguard package; that's a platform-repo check.Real-cloud gaps: nothing was run against a real project or billing account. The issue's open question, whether
google.memorystore.redis.PerformanceRecommenderexists at all, no longer matters because nothing queries it.Removed tests
These tests only covered the removed PerformanceRecommender path:
GetRecommendations_*with mock iteratorsManyItemsWithinPageCap,ExactlyAtCapSucceeds,PastCapFails,RequestsExplicitPageSizeConvertGCPRecommendation*term, nil-content and billing-failure testsTestListSKUs_CachedPerClientis kept.Two tests were reduced rather than removed:
*_ConvertGCPRecommendation_RecurringMonthlyCosttests are now*_GetOfferingDetails_RecurringMonthlyCost. They keep the catalog-currency monthly quote check throughGetOfferingDetailswith a hand-built rec. The scorer and reporter checks went with the converter.pricing_currency_test.gotests keep thegetSQLPricing/getRedisPricingcurrency assertions and drop thefill*Pricinghalf.Out of scope
SpendBasedCommitmentRecommenderpath (design doc steps 1-5, fix(gcp): ResourceType holds an instance name, then is used as a pricing tier #78): needs owner decisions and a captured payload.relational-db/cacheas GCP services will see them disappear fromGetSupportedServicesafter a pin bump. Per the extra context, platform#1035 already narrows the runtime service account to the Compute commitment recommender, so these calls were being denied there anyway.client.gofiles. They may need a trivial rebase but don't touch the removed code.Labels
Could a maintainer mirror the issue's triage labels onto this PR:
priority/p2,triaged,severity/high,urgency/this-quarter,impact/few,effort/m,type/bug.🤖 Generated with Claude Code