diff --git a/providers/aws/services/rds/client.go b/providers/aws/services/rds/client.go index 037053cd..813bda31 100644 --- a/providers/aws/services/rds/client.go +++ b/providers/aws/services/rds/client.go @@ -488,12 +488,28 @@ func (c *Client) lookupEngineName(engine string) (string, error) { if err != nil { return "", err } - if strings.HasPrefix(name, "oracle") || strings.HasPrefix(name, "sqlserver") || strings.HasPrefix(name, "sql-server") { + if isLicensedEngine(name) { return "", fmt.Errorf("engine %q: license model is not known; refusing to guess", engine) } return name, nil } +// licensedEnginePrefixes are the lower-cased engine spellings whose offerings +// carry a license model. "sql server" (with a space) is the Cost Explorer +// spelling, which normalizeEngineName passes through as-is (issue #302). +var licensedEnginePrefixes = []string{"oracle", "sqlserver", "sql-server", "sql server"} + +// isLicensedEngine reports whether a normalized engine name is Oracle or SQL +// Server in any spelling. +func isLicensedEngine(name string) bool { + for _, prefix := range licensedEnginePrefixes { + if strings.HasPrefix(name, prefix) { + return true + } + } + return false +} + // offeringDuration returns the term as the API's duration string and as seconds // for the exact-match check. func (c *Client) offeringDuration(term string) (duration string, seconds int64, err error) { diff --git a/providers/aws/services/rds/client_test.go b/providers/aws/services/rds/client_test.go index e9aab1a7..b2245eba 100644 --- a/providers/aws/services/rds/client_test.go +++ b/providers/aws/services/rds/client_test.go @@ -1316,9 +1316,14 @@ func TestFindOfferingID_NoMatchReportsPagesFetched(t *testing.T) { // TestFindOfferingID_LicensedEnginesRefusedBeforeAPICall: Oracle and SQL Server // offerings are listed as "oracle-se2(li)" / "oracle-se2(byol)", so the license -// model must be known; the lookup refuses without calling the API. +// model must be known; the lookup refuses without calling the API. "SQL Server" +// is the Cost Explorer spelling (with a space) and must be refused the same way +// rather than fail later as "no offerings found" (issue #302). func TestFindOfferingID_LicensedEnginesRefusedBeforeAPICall(t *testing.T) { - for _, engine := range []string{"oracle-se2", "oracle-ee", "sqlserver-se", "sqlserver-web", "sql-server-ex"} { + for _, engine := range []string{ + "oracle-se2", "oracle-ee", "sqlserver-se", "sqlserver-web", "sql-server-ex", + "SQL Server", "sql server", "SQL Server Enterprise", + } { t.Run(engine, func(t *testing.T) { mockRDS := &MockRDSClient{} t.Cleanup(func() { mockRDS.AssertExpectations(t) })