Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,10 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/reservations/armreservations v1.1.0
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.4.0
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.4.0
github.com/LeanerCloud/cloud-commitments-go/pkg v0.0.0-20261020053130-ff6225d5ff04
github.com/LeanerCloud/cloud-commitments-go/providers/aws v0.0.0-20261020071945-92722e673741
github.com/LeanerCloud/cloud-commitments-go/providers/azure v0.0.0-20261017134002-3def3f898617
github.com/LeanerCloud/cloud-commitments-go/providers/gcp v0.0.0-20261017134002-3def3f898617
github.com/LeanerCloud/cloud-commitments-go/pkg v0.0.0-20261026081621-80e9b8464d2a
github.com/LeanerCloud/cloud-commitments-go/providers/aws v0.0.0-20261026081621-80e9b8464d2a
github.com/LeanerCloud/cloud-commitments-go/providers/azure v0.0.0-20261026081621-80e9b8464d2a
github.com/LeanerCloud/cloud-commitments-go/providers/gcp v0.0.0-20261026081621-80e9b8464d2a
github.com/aws/aws-lambda-go v1.47.0
github.com/aws/aws-sdk-go-v2/service/kms v1.50.4
github.com/aws/aws-sdk-go-v2/service/lambda v1.89.0
Expand Down
16 changes: 8 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,14 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.54.0/go.mod h1:vB2GH9GAYYJTO3mEn8oYwzEdhlayZIdQz6zdzgUIRvA=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 h1:s0WlVbf9qpvkh1c/uDAPElam0WrL7fHRIidgZJ7UqZI=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc=
github.com/LeanerCloud/cloud-commitments-go/pkg v0.0.0-20261020053130-ff6225d5ff04 h1:D595qtoMszl7dkETbmVFzn+WPECQ7HuiKnsMlFI7bLA=
github.com/LeanerCloud/cloud-commitments-go/pkg v0.0.0-20261020053130-ff6225d5ff04/go.mod h1:SCDEgHG6evjPh0RsoXof+J3aMmGXNFMrwbJIle7rMpQ=
github.com/LeanerCloud/cloud-commitments-go/providers/aws v0.0.0-20261020071945-92722e673741 h1:AlfTl8EpfcRIWjU1FIx/XN+4ZgJjktjP/gPlRylPoF8=
github.com/LeanerCloud/cloud-commitments-go/providers/aws v0.0.0-20261020071945-92722e673741/go.mod h1:cx+GF1J6RKy0CTOs2qhy+DM9rwFbKf3g0JIhYwqWz9k=
github.com/LeanerCloud/cloud-commitments-go/providers/azure v0.0.0-20261017134002-3def3f898617 h1:K9wBX9ac1QwhkjW7BvDt0gl2Kt9fGdDytJyndoPRcBU=
github.com/LeanerCloud/cloud-commitments-go/providers/azure v0.0.0-20261017134002-3def3f898617/go.mod h1:iOwl8e9EKGb3VQ4u/YjiqVzglhD6/GX1ABC3tBkqu0A=
github.com/LeanerCloud/cloud-commitments-go/providers/gcp v0.0.0-20261017134002-3def3f898617 h1:VYVbQyoR+tIcPoXhkviclexKuU5H+A21hSXudB+kZag=
github.com/LeanerCloud/cloud-commitments-go/providers/gcp v0.0.0-20261017134002-3def3f898617/go.mod h1:03vjHt5wlHtZEFAFOhosA+paDSqacWnKg9cVa68QnJ0=
github.com/LeanerCloud/cloud-commitments-go/pkg v0.0.0-20261026081621-80e9b8464d2a h1:AdVEkJsrrE1i7a7J5pWh3fUZZ65VYacs8dq69EpMGWk=
github.com/LeanerCloud/cloud-commitments-go/pkg v0.0.0-20261026081621-80e9b8464d2a/go.mod h1:rEJErEsL40Np/ttf0RDoNNC2XQsN1GmWyFf34y0JLD8=
github.com/LeanerCloud/cloud-commitments-go/providers/aws v0.0.0-20261026081621-80e9b8464d2a h1:buZASfVGddhmva+kSO3QbwIw0USNo0zILx64TP0tN44=
github.com/LeanerCloud/cloud-commitments-go/providers/aws v0.0.0-20261026081621-80e9b8464d2a/go.mod h1:yVHEL5ceNS/CsDatzLH0+Qmwtoi7yY4tIHvqyvhdtig=
github.com/LeanerCloud/cloud-commitments-go/providers/azure v0.0.0-20261026081621-80e9b8464d2a h1:Ih+d9iCRAQErjoJHnlJlFB3zlgVZF1O7WFgwM/xB5PA=
github.com/LeanerCloud/cloud-commitments-go/providers/azure v0.0.0-20261026081621-80e9b8464d2a/go.mod h1:zA51HKXtBvHHMYd+owRDmn4p8ialZrLFzI9I052uUmo=
github.com/LeanerCloud/cloud-commitments-go/providers/gcp v0.0.0-20261026081621-80e9b8464d2a h1:nnyJsdoxgR+tqmMbh5L5/HtT6xn5p6Axz2OhphbCa+Y=
github.com/LeanerCloud/cloud-commitments-go/providers/gcp v0.0.0-20261026081621-80e9b8464d2a/go.mod h1:/HxBqXBb5v69+EHLsibHnekkEYRP8TvyCmT6d9QRxt0=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8=
Expand Down
2 changes: 1 addition & 1 deletion internal/api/combined_plan_purchase_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func (p *combinedProvider) GetServiceClient(_ context.Context, service common.Se

type combinedFactory struct{ provider *combinedProvider }

func (f combinedFactory) CreateAndValidateProvider(_ context.Context, name string, _ *provider.ProviderConfig) (provider.Provider, error) {
func (f combinedFactory) CreateAndValidateProvider(_ context.Context, name string, _ *provider.Config) (provider.Provider, error) {
if name != "azure" {
return nil, fmt.Errorf("fixture refuses unexpected provider %q", name)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func (p *pauseClaimProvider) GetServiceClient(context.Context, common.ServiceTyp

type pauseClaimFactory struct{ provider *pauseClaimProvider }

func (f pauseClaimFactory) CreateAndValidateProvider(context.Context, string, *provider.ProviderConfig) (provider.Provider, error) {
func (f pauseClaimFactory) CreateAndValidateProvider(context.Context, string, *provider.Config) (provider.Provider, error) {
return f.provider, nil
}

Expand Down
2 changes: 1 addition & 1 deletion internal/api/handler_purchases_retry_fanout_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ func (p *fanoutProvider) GetRecommendationsClient(_ context.Context) (provider.R

type fanoutProviderFactory struct{ prov *fanoutProvider }

func (f *fanoutProviderFactory) CreateAndValidateProvider(_ context.Context, _ string, _ *provider.ProviderConfig) (provider.Provider, error) {
func (f *fanoutProviderFactory) CreateAndValidateProvider(_ context.Context, _ string, _ *provider.Config) (provider.Provider, error) {
return f.prov, nil
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func (p *runNowProvider) GetServiceClient(context.Context, common.ServiceType, s

type runNowFactory struct{ provider *runNowProvider }

func (f runNowFactory) CreateAndValidateProvider(context.Context, string, *provider.ProviderConfig) (provider.Provider, error) {
func (f runNowFactory) CreateAndValidateProvider(context.Context, string, *provider.Config) (provider.Provider, error) {
return f.provider, nil
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ type globalFilterProvider struct {
provider.RecommendationsClient
}

func (p globalFilterProvider) CreateAndValidateProvider(_ context.Context, name string, cfg *provider.ProviderConfig) (provider.Provider, error) {
func (p globalFilterProvider) CreateAndValidateProvider(_ context.Context, name string, cfg *provider.Config) (provider.Provider, error) {
if name != "aws" || cfg != nil {
return nil, fmt.Errorf("unexpected provider request: %s", name)
}
Expand Down
2 changes: 1 addition & 1 deletion internal/api/recommendation_identity_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ type identityProviderFactory struct {
recs map[string][]common.Recommendation
}

func (f identityProviderFactory) CreateAndValidateProvider(ctx context.Context, name string, cfg *provider.ProviderConfig) (provider.Provider, error) {
func (f identityProviderFactory) CreateAndValidateProvider(ctx context.Context, name string, cfg *provider.Config) (provider.Provider, error) {
if name != "aws" || cfg == nil || cfg.AWSCredentialsProvider == nil {
return nil, fmt.Errorf("expected registered AWS fixture credentials")
}
Expand Down
12 changes: 8 additions & 4 deletions internal/providerfactory/bypass_guard_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ var bypassConstructors = map[string]map[string]bool{
}

// No non-test file under cmd/ or internal/ may call the concrete Azure/GCP
// provider constructors or set the deprecated ProviderConfig.Profile field.
// provider constructors or set the deprecated provider.Config Profile field.
func TestNoRegistryBypassInProductionCode(t *testing.T) {
root := filepath.Join("..", "..")
var violations []string
Expand All @@ -50,7 +50,7 @@ func TestNoRegistryBypassInProductionCode(t *testing.T) {
}
require.Greater(t, scanned, 100, "the walk must actually reach the production sources")
assert.Empty(t, violations,
"build credentialed Azure/GCP providers with providerfactory.NewAzure/NewGCP and use the typed ProviderConfig fields")
"build credentialed Azure/GCP providers with providerfactory.NewAzure/NewGCP and use the typed provider.Config fields")
}

// registryBypasses returns one entry per bypassing call or deprecated
Expand Down Expand Up @@ -80,7 +80,7 @@ func registryBypasses(t *testing.T, path string) []string {
out = append(out, fset.Position(node.Pos()).String()+": "+node.Sel.Name)
}
case *ast.CompositeLit:
if sel, ok := node.Type.(*ast.SelectorExpr); ok && sel.Sel.Name == "ProviderConfig" && selectorPkg(sel, imports) == providerPkg {
if sel, ok := node.Type.(*ast.SelectorExpr); ok && providerConfigTypes[sel.Sel.Name] && selectorPkg(sel, imports) == providerPkg {
out = append(out, profileKeys(fset, node)...)
}
}
Expand All @@ -89,6 +89,10 @@ func registryBypasses(t *testing.T, path string) []string {
return out
}

// providerConfigTypes are the names a provider.Config literal can be written
// with: Config, and its deprecated alias ProviderConfig (go#603).
var providerConfigTypes = map[string]bool{"Config": true, "ProviderConfig": true}

func selectorPkg(sel *ast.SelectorExpr, imports map[string]string) string {
id, ok := sel.X.(*ast.Ident)
if !ok {
Expand All @@ -105,7 +109,7 @@ func profileKeys(fset *token.FileSet, lit *ast.CompositeLit) []string {
continue
}
if id, ok := kv.Key.(*ast.Ident); ok && id.Name == "Profile" {
out = append(out, fset.Position(kv.Pos()).String()+": ProviderConfig.Profile")
out = append(out, fset.Position(kv.Pos()).String()+": provider.Config.Profile")
}
}
return out
Expand Down
6 changes: 3 additions & 3 deletions internal/providerfactory/providerfactory.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func NewGCP(projectID string, ts oauth2.TokenSource) (provider.Provider, error)
func newAzure(reg *provider.Registry, subscriptionID string, cred azcore.TokenCredential) (provider.Provider, error) {
// A nil cred converts to a nil `any`, which the Azure factory treats as
// "no credential supplied".
return build(reg, azureName, &provider.ProviderConfig{
return build(reg, azureName, &provider.Config{
Name: azureName,
AzureSubscriptionID: subscriptionID,
AzureTokenCredential: cred,
Expand All @@ -73,14 +73,14 @@ func newGCP(reg *provider.Registry, projectID string, ts oauth2.TokenSource) (pr
if ts == nil {
return nil, ErrMissingGCPTokenSource
}
return build(reg, gcpName, &provider.ProviderConfig{
return build(reg, gcpName, &provider.Config{
Name: gcpName,
GCPProjectID: projectID,
GCPTokenSource: ts,
})
}

func build(reg *provider.Registry, name string, cfg *provider.ProviderConfig) (provider.Provider, error) {
func build(reg *provider.Registry, name string, cfg *provider.Config) (provider.Provider, error) {
prov, err := reg.GetProviderWithConfig(name, cfg)
if err != nil {
return nil, fmt.Errorf("providerfactory: build %s provider: %w", name, err)
Expand Down
8 changes: 4 additions & 4 deletions internal/providerfactory/providerfactory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ func (f *fakeTokenSource) Token() (*oauth2.Token, error) {

// recordingRegistry returns a private registry whose name factory records
// the config it receives and returns want.
func recordingRegistry(t *testing.T, name string, want provider.Provider, wantErr error) (*provider.Registry, *[]*provider.ProviderConfig) {
func recordingRegistry(t *testing.T, name string, want provider.Provider, wantErr error) (*provider.Registry, *[]*provider.Config) {
t.Helper()
reg := provider.NewRegistry()
var got []*provider.ProviderConfig
require.NoError(t, reg.Register(name, func(cfg *provider.ProviderConfig) (provider.Provider, error) {
var got []*provider.Config
require.NoError(t, reg.Register(name, func(cfg *provider.Config) (provider.Provider, error) {
got = append(got, cfg)
return want, wantErr
}))
Expand Down Expand Up @@ -147,7 +147,7 @@ func TestBuild_PropagatesFactoryErrorsAndNilProviders(t *testing.T) {
func TestNewAzure_MatchesLegacyConstruction(t *testing.T) {
cred := &fakeAzureCred{id: "legacy"}

legacy, err := azureprovider.NewAzureProvider(&provider.ProviderConfig{Profile: testSubscriptionID}) //nolint:staticcheck // SA1019: this is the legacy baseline being compared against
legacy, err := azureprovider.NewAzureProvider(&provider.Config{Profile: testSubscriptionID}) //nolint:staticcheck // SA1019: this is the legacy baseline being compared against
require.NoError(t, err)
legacy.SetCredential(cred)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func purchaseThroughPinnedAzureClient(t *testing.T, exec *config.PurchaseExecuti
prov.On("GetServiceClient", mock.Anything, common.ServiceSavingsPlansAll, mock.Anything).Return(provider.ServiceClient(client), nil)

m := &Manager{config: store, email: sender, providerFactory: factory}
_, _, errs, err := m.processPurchaseRecommendations(ctx, exec, &config.PurchasePlan{Name: "p"}, "acct", (*provider.ProviderConfig)(nil), "")
_, _, errs, err := m.processPurchaseRecommendations(ctx, exec, &config.PurchasePlan{Name: "p"}, "acct", (*provider.Config)(nil), "")
require.NoError(t, err)
require.Empty(t, errs)
for i, rec := range exec.Recommendations {
Expand Down
26 changes: 13 additions & 13 deletions internal/purchase/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ func (m *Manager) executeSingleAccount(ctx context.Context, exec *config.Purchas
// (issue #97; see fan_out_shape.go). Every error it returns is before
// submission. Split out of executeSingleAccount to keep that function under
// the gocyclo budget.
func (m *Manager) prepareSingleAccountSubmission(ctx context.Context, exec *config.PurchaseExecution) (*provider.ProviderConfig, purchaseTarget, error) {
func (m *Manager) prepareSingleAccountSubmission(ctx context.Context, exec *config.PurchaseExecution) (*provider.Config, purchaseTarget, error) {
if err := requireRecsMatchRowAccount(exec); err != nil {
return nil, purchaseTarget{}, beforeSubmission(err)
}
Expand Down Expand Up @@ -445,7 +445,7 @@ func applyAccountOutcome(acctExec *config.PurchaseExecution, purchaseErrors []st
// resolved (lookup failed, the account does not exist, or credentials could
// not be derived); the caller must NOT fall back to ambient credentials on
// error, as that would purchase/stamp against the wrong account (#646).
func (m *Manager) resolveSingleAccountProvider(ctx context.Context, exec *config.PurchaseExecution) (*provider.ProviderConfig, purchaseTarget, error) {
func (m *Manager) resolveSingleAccountProvider(ctx context.Context, exec *config.PurchaseExecution) (*provider.Config, purchaseTarget, error) {
// Skip credential resolution when nothing is selected. Approval-only
// flows may carry an account ID on the recs solely for the contact-email
// gate; attempting resolution there would fail on accounts with no
Expand Down Expand Up @@ -499,14 +499,14 @@ func (e *partialPurchaseError) Error() string {
return "some purchases failed (partial success): " + strings.Join(e.errors, "; ")
}

// resolveAccountProvider returns a *ProviderConfig with a pre-authenticated provider
// resolveAccountProvider returns a *provider.Config with a pre-authenticated provider
// for the given account. Returns an error if credential resolution fails -- callers
// must NOT fall back to ambient credentials on error.
func (m *Manager) resolveAccountProvider(ctx context.Context, account config.CloudAccount) (*provider.ProviderConfig, error) {
func (m *Manager) resolveAccountProvider(ctx context.Context, account config.CloudAccount) (*provider.Config, error) {
t0 := time.Now()
logging.Infof("purchase[resolveAccountProvider]: resolving credentials for provider=%s account=%s",
account.Provider, account.ID)
var cfg *provider.ProviderConfig
var cfg *provider.Config
var err error
switch account.Provider {
case "aws":
Expand All @@ -528,7 +528,7 @@ func (m *Manager) resolveAccountProvider(ctx context.Context, account config.Clo
return cfg, nil
}

func (m *Manager) resolveAWSProvider(ctx context.Context, account config.CloudAccount) (*provider.ProviderConfig, error) {
func (m *Manager) resolveAWSProvider(ctx context.Context, account config.CloudAccount) (*provider.Config, error) {
t0 := time.Now()
logging.Infof("purchase[resolveAWSProvider]: resolving AWS credentials for account=%s authMode=%s",
account.ID, account.AWSAuthMode)
Expand All @@ -544,10 +544,10 @@ func (m *Manager) resolveAWSProvider(ctx context.Context, account config.CloudAc
}
logging.Infof("purchase[resolveAWSProvider]: AWS credentials resolved for account=%s in %s",
account.ID, time.Since(t0))
return &provider.ProviderConfig{Name: "aws", AWSCredentialsProvider: awsCreds}, nil
return &provider.Config{Name: "aws", AWSCredentialsProvider: awsCreds}, nil
}

func (m *Manager) resolveAzureProvider(ctx context.Context, account config.CloudAccount) (*provider.ProviderConfig, error) {
func (m *Manager) resolveAzureProvider(ctx context.Context, account config.CloudAccount) (*provider.Config, error) {
t0 := time.Now()
logging.Infof("purchase[resolveAzureProvider]: resolving Azure credentials for account=%s authMode=%s",
account.ID, account.AzureAuthMode)
Expand All @@ -571,10 +571,10 @@ func (m *Manager) resolveAzureProvider(ctx context.Context, account config.Cloud
}
logging.Infof("purchase[resolveAzureProvider]: Azure credentials resolved for account=%s in %s",
account.ID, time.Since(t0))
return &provider.ProviderConfig{ProviderOverride: azProv}, nil
return &provider.Config{ProviderOverride: azProv}, nil
}

func (m *Manager) resolveGCPProvider(ctx context.Context, account config.CloudAccount) (*provider.ProviderConfig, error) {
func (m *Manager) resolveGCPProvider(ctx context.Context, account config.CloudAccount) (*provider.Config, error) {
t0 := time.Now()
logging.Infof("purchase[resolveGCPProvider]: resolving GCP credentials for account=%s authMode=%s",
account.ID, account.GCPAuthMode)
Expand Down Expand Up @@ -604,7 +604,7 @@ func (m *Manager) resolveGCPProvider(ctx context.Context, account config.CloudAc
}
logging.Infof("purchase[resolveGCPProvider]: GCP credentials resolved for account=%s in %s",
account.ID, time.Since(t0))
return &provider.ProviderConfig{ProviderOverride: gcpProv}, nil
return &provider.Config{ProviderOverride: gcpProv}, nil
}

// getMaxAccountParallelism is a thin alias over the shared
Expand All @@ -624,7 +624,7 @@ type recPurchaseOutcome struct {
index int
}

func (m *Manager) processPurchaseRecommendations(ctx context.Context, exec *config.PurchaseExecution, plan *config.PurchasePlan, accountID string, provCfg *provider.ProviderConfig, awsPartition string) (totalSavings, totalUpfront float64, purchaseErrors []string, procErr error) {
func (m *Manager) processPurchaseRecommendations(ctx context.Context, exec *config.PurchaseExecution, plan *config.PurchasePlan, accountID string, provCfg *provider.Config, awsPartition string) (totalSavings, totalUpfront float64, purchaseErrors []string, procErr error) {
// ExecutionID is carried into PurchaseOptions so executeSinglePurchase
// can tag every per-rec log line with the owning exec UUID. Without
// this, CloudWatch filtering by exec ID returns zero hits and a stuck
Expand Down Expand Up @@ -1111,7 +1111,7 @@ func logRecCtxErr(executionID, recTuple string, elapsed time.Duration, recCtxErr
// provCfg carries optional per-account credentials; pass nil to use ambient credentials.
// opts carries execution-level metadata (the source surface) that providers stamp
// onto the commitment they create.
func (m *Manager) executeSinglePurchase(ctx context.Context, rec config.RecommendationRecord, provCfg *provider.ProviderConfig, opts common.PurchaseOptions) (common.PurchaseResult, error) {
func (m *Manager) executeSinglePurchase(ctx context.Context, rec config.RecommendationRecord, provCfg *provider.Config, opts common.PurchaseOptions) (common.PurchaseResult, error) {
// Per-purchase Info logs tagged with the owning execution ID so a
// CloudWatch filter on the execution UUID surfaces every step of the
// purchase attempt -- provider construction, service-client lookup,
Expand Down
Loading
Loading