Skip to content
Merged
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
2 changes: 2 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ linters:
- third_party$
- builtin$
- examples$
- node_modules
issues:
max-issues-per-linter: 0
max-same-issues: 0
Expand All @@ -108,3 +109,4 @@ formatters:
- third_party$
- builtin$
- examples$
- node_modules
4 changes: 2 additions & 2 deletions cmd/cleanup-lambda/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import (
"github.com/aws/aws-lambda-go/lambda"
)

// CleanupEvent represents the input to the cleanup function
// CleanupEvent represents the input to the cleanup function.
type CleanupEvent struct {
DryRun bool `json:"dryRun,omitempty"`
}

// CleanupResult represents the cleanup operation results
// CleanupResult represents the cleanup operation results.
type CleanupResult struct {
SessionsDeleted int64 `json:"sessionsDeleted"`
ExecutionsDeleted int64 `json:"executionsDeleted"`
Expand Down
22 changes: 11 additions & 11 deletions cmd/configure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/stretchr/testify/require"
)

// MockSecretsStore is a mock implementation of SecretsStore for testing
// MockSecretsStore is a mock implementation of SecretsStore for testing.
type MockSecretsStore struct {
listSecretsFunc func(ctx context.Context, filter string) ([]string, error)
updateSecretFunc func(ctx context.Context, secretID string, secretValue string) error
Expand Down Expand Up @@ -40,7 +40,7 @@ func (m *MockSecretsStore) UpdateSecret(ctx context.Context, secretID string, se
return nil
}

// TestAzureCredentials_Struct tests the AzureCredentials struct
// TestAzureCredentials_Struct tests the AzureCredentials struct.
func TestAzureCredentials_Struct(t *testing.T) {
creds := AzureCredentials{
TenantID: "tenant-123",
Expand All @@ -55,7 +55,7 @@ func TestAzureCredentials_Struct(t *testing.T) {
assert.Equal(t, "sub-abc", creds.SubscriptionID)
}

// TestAzureConfigOptions_Defaults tests AzureConfigOptions defaults
// TestAzureConfigOptions_Defaults tests AzureConfigOptions defaults.
func TestAzureConfigOptions_Defaults(t *testing.T) {
opts := AzureConfigOptions{}

Expand All @@ -68,7 +68,7 @@ func TestAzureConfigOptions_Defaults(t *testing.T) {
assert.False(t, opts.Interactive)
}

// TestAzureConfigOptions_WithValues tests AzureConfigOptions with values
// TestAzureConfigOptions_WithValues tests AzureConfigOptions with values.
func TestAzureConfigOptions_WithValues(t *testing.T) {
opts := AzureConfigOptions{
StackName: "my-cudly",
Expand All @@ -89,7 +89,7 @@ func TestAzureConfigOptions_WithValues(t *testing.T) {
assert.True(t, opts.Interactive)
}

// TestGCPCredentials_Struct tests the GCPCredentials struct
// TestGCPCredentials_Struct tests the GCPCredentials struct.
func TestGCPCredentials_Struct(t *testing.T) {
creds := GCPCredentials{
Type: "service_account",
Expand All @@ -108,7 +108,7 @@ func TestGCPCredentials_Struct(t *testing.T) {
assert.Equal(t, "12345678901234567890", creds.ClientID)
}

// TestGCPConfigOptions_Defaults tests GCPConfigOptions defaults
// TestGCPConfigOptions_Defaults tests GCPConfigOptions defaults.
func TestGCPConfigOptions_Defaults(t *testing.T) {
opts := GCPConfigOptions{}

Expand All @@ -119,7 +119,7 @@ func TestGCPConfigOptions_Defaults(t *testing.T) {
assert.False(t, opts.Interactive)
}

// TestGCPConfigOptions_WithValues tests GCPConfigOptions with values
// TestGCPConfigOptions_WithValues tests GCPConfigOptions with values.
func TestGCPConfigOptions_WithValues(t *testing.T) {
opts := GCPConfigOptions{
StackName: "my-cudly",
Expand All @@ -136,7 +136,7 @@ func TestGCPConfigOptions_WithValues(t *testing.T) {
assert.True(t, opts.Interactive)
}

// Tests for validateAzureUUID function
// Tests for validateAzureUUID function.
func TestValidateAzureUUID(t *testing.T) {
tests := []struct {
name string
Expand Down Expand Up @@ -256,7 +256,7 @@ func TestValidateAzureUUID(t *testing.T) {
}
}

// Tests for validateGCPProjectID function
// Tests for validateGCPProjectID function.
func TestValidateGCPProjectID(t *testing.T) {
tests := []struct {
name string
Expand Down Expand Up @@ -383,7 +383,7 @@ func TestValidateGCPProjectID(t *testing.T) {
}
}

// Tests for storeAzureCredentials function
// Tests for storeAzureCredentials function.
func TestStoreAzureCredentials(t *testing.T) {
tests := []struct {
name string
Expand Down Expand Up @@ -549,7 +549,7 @@ func TestStoreAzureCredentials(t *testing.T) {
}
}

// Tests for storeGCPCredentials function
// Tests for storeGCPCredentials function.
func TestStoreGCPCredentials(t *testing.T) {
// private_key validation is presence-only; the key content is not parsed or
// validated as a real PEM block by storeGCPCredentials.
Expand Down
50 changes: 25 additions & 25 deletions cmd/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,36 +18,36 @@ import (
"golang.org/x/term"
)

// Constants for purchase processing
// Constants for purchase processing.
const (
// DefaultDuplicateCheckLookbackHours is the default lookback period for checking recent purchases
// DefaultDuplicateCheckLookbackHours is the default lookback period for checking recent purchases.
DefaultDuplicateCheckLookbackHours = 24

// PurchaseDelaySeconds is the delay between consecutive purchases to avoid rate limiting
// PurchaseDelaySeconds is the delay between consecutive purchases to avoid rate limiting.
PurchaseDelaySeconds = 2
)

// AppLogger is a simple logger for application output
// AppLogger is a simple logger for application output.
var AppLogger = log.New(os.Stdout, "", 0)

// OrganizationsAPI interface for describing accounts
// OrganizationsAPI interface for describing accounts.
type OrganizationsAPI interface {
DescribeAccount(ctx context.Context, params *organizations.DescribeAccountInput, optFns ...func(*organizations.Options)) (*organizations.DescribeAccountOutput, error)
}

// AccountAliasGetter is an interface for getting account aliases
// AccountAliasGetter is an interface for getting account aliases.
type AccountAliasGetter interface {
GetAccountAlias(ctx context.Context, accountID string) string
}

// AccountAliasCache caches account ID to alias mappings
// AccountAliasCache caches account ID to alias mappings.
type AccountAliasCache struct {
mu sync.RWMutex
cache map[string]string
orgClient OrganizationsAPI
}

// NewAccountAliasCache creates a new account alias cache
// NewAccountAliasCache creates a new account alias cache.
func NewAccountAliasCache(cfg aws.Config) *AccountAliasCache {
return &AccountAliasCache{
cache: make(map[string]string),
Expand All @@ -56,15 +56,15 @@ func NewAccountAliasCache(cfg aws.Config) *AccountAliasCache {
}

// NewAccountAliasCacheWithClient creates a new account alias cache with a custom client
// This is useful for testing with mocked clients
// This is useful for testing with mocked clients.
func NewAccountAliasCacheWithClient(orgClient OrganizationsAPI) *AccountAliasCache {
return &AccountAliasCache{
cache: make(map[string]string),
orgClient: orgClient,
}
}

// GetAccountAlias returns the account alias for an account ID
// GetAccountAlias returns the account alias for an account ID.
func (c *AccountAliasCache) GetAccountAlias(ctx context.Context, accountID string) string {
if accountID == "" {
return ""
Expand Down Expand Up @@ -104,7 +104,7 @@ func (c *AccountAliasCache) GetAccountAlias(ctx context.Context, accountID strin
return accountID
}

// CalculateTotalInstances calculates the total instance count across recommendations
// CalculateTotalInstances calculates the total instance count across recommendations.
func CalculateTotalInstances(recs []common.Recommendation) int {
total := 0
for _, rec := range recs {
Expand Down Expand Up @@ -223,7 +223,7 @@ func ApplyCoverage(recs []common.Recommendation, coverage float64) []common.Reco
//
// Pools where CE reports 100% existing coverage but AWS still recommends
// new RIs (typical when existing RIs are near expiry) are dropped here —
// the existing coverage is honoured strictly. Use --rebuy-window-days to
// the existing coverage is honored strictly. Use --rebuy-window-days to
// surface those replacements before the cliff.
//
// SPs:
Expand Down Expand Up @@ -424,7 +424,7 @@ func applyTargetCoverageSP(rec common.Recommendation, targetPct float64) (common
// RecommendedUtilization is consulted only as a no-signal guard above (a
// zero value means we can't sanity-check the result); the scaling itself
// uses targetPct directly rather than a recUtil/target ratio so the flag's
// intent is honoured even when AWS already projects above target.
// intent is honored even when AWS already projects above target.
//
// If Details isn't a *SavingsPlanDetails (defensive — should always be
// for SP recs), log a warning and pass through UNCHANGED — including
Expand Down Expand Up @@ -467,7 +467,7 @@ func applySizing(recs []common.Recommendation, cfg Config, coverage float64) []c
return ApplyCoverage(recs, coverage)
}

// ApplyCountOverride overrides the count for all recommendations
// ApplyCountOverride overrides the count for all recommendations.
func ApplyCountOverride(recs []common.Recommendation, overrideCount int32) []common.Recommendation {
if overrideCount <= 0 {
return recs
Expand All @@ -480,7 +480,7 @@ func ApplyCountOverride(recs []common.Recommendation, overrideCount int32) []com
return result
}

// ApplyInstanceLimit limits the total number of instances
// ApplyInstanceLimit limits the total number of instances.
func ApplyInstanceLimit(recs []common.Recommendation, maxInstances int32) []common.Recommendation {
if maxInstances <= 0 {
return recs
Expand Down Expand Up @@ -540,7 +540,7 @@ func CheckAuditLogWritable(path string) error {
return f.Close()
}

// DuplicateChecker checks for existing commitments to avoid duplicates
// DuplicateChecker checks for existing commitments to avoid duplicates.
type DuplicateChecker struct {
LookbackHours int // How many hours to look back for recent purchases
}
Expand Down Expand Up @@ -586,7 +586,7 @@ func (d *DuplicateChecker) AdjustRecommendationsForExisting(ctx context.Context,
return passed, filtered, nil
}

// filterRecentCommitments filters commitments to only recent purchases within the lookback window
// filterRecentCommitments filters commitments to only recent purchases within the lookback window.
func (d *DuplicateChecker) filterRecentCommitments(existing []common.Commitment) []common.Commitment {
cutoffTime := time.Now().Add(-time.Duration(d.LookbackHours) * time.Hour)
recentExisting := make([]common.Commitment, 0)
Expand All @@ -600,12 +600,12 @@ func (d *DuplicateChecker) filterRecentCommitments(existing []common.Commitment)
return recentExisting
}

// isRecentActiveCommitment checks if a commitment is active and purchased after the cutoff time
// isRecentActiveCommitment checks if a commitment is active and purchased after the cutoff time.
func isRecentActiveCommitment(c common.Commitment, cutoffTime time.Time) bool {
return (c.State == "active" || c.State == "payment-pending") && c.StartDate.After(cutoffTime)
}

// buildExistingCommitmentsMap builds a map of commitments by resource type, region, and engine
// buildExistingCommitmentsMap builds a map of commitments by resource type, region, and engine.
func buildExistingCommitmentsMap(commitments []common.Commitment) map[string]int {
existingMap := make(map[string]int)

Expand Down Expand Up @@ -638,7 +638,7 @@ func adjustRecommendationsAgainstExisting(recs []common.Recommendation, existing
return passed, filtered
}

// adjustSingleRecommendation adjusts a single recommendation based on existing commitments
// adjustSingleRecommendation adjusts a single recommendation based on existing commitments.
func adjustSingleRecommendation(rec common.Recommendation, existingMap map[string]int) common.Recommendation {
engine := getEngineFromRecommendation(rec)
key := fmt.Sprintf("%s|%s|%s", rec.ResourceType, rec.Region, engine)
Expand All @@ -664,7 +664,7 @@ func adjustSingleRecommendation(rec common.Recommendation, existingMap map[strin
return adjusted
}

// getEngineFromRecommendation extracts the engine from recommendation details
// getEngineFromRecommendation extracts the engine from recommendation details.
func getEngineFromRecommendation(rec common.Recommendation) string {
if rec.Details == nil {
return ""
Expand All @@ -687,7 +687,7 @@ func getEngineFromRecommendation(rec common.Recommendation) string {

// engineNameMap maps database engine names to a consistent normalized format.
// AWS RIs use: "aurora-postgresql", "aurora-mysql", "mysql", "postgres"
// Cost Explorer uses: "Aurora PostgreSQL", "Aurora MySQL", "MySQL", "PostgreSQL"
// Cost Explorer uses: "Aurora PostgreSQL", "Aurora MySQL", "MySQL", "PostgreSQL".
var engineNameMap = map[string]string{
// Cost Explorer format -> normalized
"Aurora PostgreSQL": "aurora-postgresql",
Expand All @@ -714,7 +714,7 @@ var engineNameMap = map[string]string{
"sqlserver-web": "sqlserver",
}

// normalizeEngineName normalizes database engine names to a consistent format
// normalizeEngineName normalizes database engine names to a consistent format.
func normalizeEngineName(engine string) string {
if normalized, ok := engineNameMap[engine]; ok {
return normalized
Expand All @@ -723,12 +723,12 @@ func normalizeEngineName(engine string) string {
return strings.ToLower(engine)
}

// AdjustRecommendationsForExistingRIs is an alias for AdjustRecommendationsForExisting
// AdjustRecommendationsForExistingRIs is an alias for AdjustRecommendationsForExisting.
func (d *DuplicateChecker) AdjustRecommendationsForExistingRIs(ctx context.Context, recs []common.Recommendation, client provider.ServiceClient) ([]common.Recommendation, []common.Recommendation, error) {
return d.AdjustRecommendationsForExisting(ctx, recs, client)
}

// GetRecommendationDescription returns a human-readable description
// GetRecommendationDescription returns a human-readable description.
func GetRecommendationDescription(rec common.Recommendation) string {
desc := fmt.Sprintf("%s %s", rec.Service, rec.ResourceType)
if rec.Details != nil {
Expand Down
4 changes: 2 additions & 2 deletions cmd/lambda/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
"github.com/aws/aws-lambda-go/lambda"
)

// Version is set at build time
// Version is set at build time.
var Version = "dev"

var (
Expand Down Expand Up @@ -56,7 +56,7 @@ func initApp(ctx context.Context) (*server.Application, error) {
}

// Handler is the main Lambda handler function
// This delegates to Application.HandleLambdaEvent which handles all event types
// This delegates to Application.HandleLambdaEvent which handles all event types.
func Handler(ctx context.Context, rawEvent json.RawMessage) (interface{}, error) {
// Initialize app on first request (lazy initialization)
application, err := initApp(ctx)
Expand Down
2 changes: 1 addition & 1 deletion cmd/lambda/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/stretchr/testify/require"
)

// createTestApp creates a minimal Application for testing with no DB dependency
// createTestApp creates a minimal Application for testing with no DB dependency.
func createTestApp() *server.Application {
apiHandler := api.NewHandler(api.HandlerConfig{})
return &server.Application{
Expand Down
12 changes: 6 additions & 6 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ import (

const (
// MaxReasonableInstances is the maximum number of instances that can be processed
// This is a safety limit to prevent accidental large purchases
// This is a safety limit to prevent accidental large purchases.
MaxReasonableInstances = 10000
)

// Config holds all configuration for the RI helper tool
// Config holds all configuration for the RI helper tool.
type Config struct {
Providers []string
Regions []string
Expand Down Expand Up @@ -173,7 +173,7 @@ func init() {
"Default 0 = no filter.")
}

// Package-level Config that cobra flags bind to
// Package-level Config that cobra flags bind to.
var toolCfg = Config{}

// validateFlags is now defined in validators.go
Expand Down Expand Up @@ -239,7 +239,7 @@ func parseServices(serviceNames []string) []common.ServiceType {
return result
}

// getAllServices returns all supported services
// getAllServices returns all supported services.
func getAllServices() []common.ServiceType {
return []common.ServiceType{
common.ServiceRDS,
Expand All @@ -255,7 +255,7 @@ func getAllServices() []common.ServiceType {
}
}

// createServiceClient creates the appropriate service client for a service
// createServiceClient creates the appropriate service client for a service.
func createServiceClient(service common.ServiceType, cfg aws.Config) provider.ServiceClient {
switch service {
case common.ServiceRDS:
Expand Down Expand Up @@ -366,7 +366,7 @@ func generatePurchaseID(rec common.Recommendation, region string, _ int, isDryRu
prefix, service, region, instanceType, rec.Count, coveragePct, timestamp, uuidSuffix)
}

// sanitizeAccountName converts account name to a filesystem/ID-safe format
// sanitizeAccountName converts account name to a filesystem/ID-safe format.
func sanitizeAccountName(accountName string) string {
if accountName == "" {
return ""
Expand Down
Loading
Loading