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
14 changes: 13 additions & 1 deletion cmd/multi_service_engine_versions.go
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,9 @@ func extractNumericPrefix(s string) string {
// lookup: known is false when the major version cannot be extracted or the
// engine:majorVersion key is missing from versionInfo. Callers on money paths
// must not treat known=false as "not in extended support" (issue #1313).
// An extended-support entry with no start date is an anomalous payload: it is
// skipped with a warning rather than read as "already started", and if no
// other entry proves extended support is active, known is false (issue #1315).
func isInExtendedSupport(engine, fullVersion string, versionInfo map[string]MajorEngineVersionInfo) (extended, known bool) {
majorVersion := extractMajorVersion(engine, fullVersion)
if majorVersion == "" {
Expand All @@ -439,10 +442,19 @@ func isInExtendedSupport(engine, fullVersion string, versionInfo map[string]Majo

// Check if current date falls within extended support period
now := time.Now()
missingStart := false
for _, lifecycle := range info.SupportedEngineLifecycles {
if lifecycle.LifecycleSupportName != string(rdstypes.LifecycleSupportNameOpenSourceRdsExtendedSupport) {
continue
}
// A zero start date would pass the start gate below and claim the
// window is open with no evidence; skip it loudly (issue #1315).
if lifecycle.LifecycleSupportStartDate.IsZero() {
missingStart = true
log.Printf("⚠️ Extended-support lifecycle for %s %s has no start date: ignoring the entry, extended-support window unknown",
normalizedEngine, majorVersion)
continue
}
// Not in extended support before its start date
if now.Before(lifecycle.LifecycleSupportStartDate) {
continue
Expand All @@ -454,7 +466,7 @@ func isInExtendedSupport(engine, fullVersion string, versionInfo map[string]Majo
}
}

return false, true
return false, !missingStart
}

// adjustRecommendationForExcludedVersions reduces the instance count in a recommendation
Expand Down
132 changes: 132 additions & 0 deletions cmd/multi_service_engine_versions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,91 @@ func TestIsInExtendedSupport(t *testing.T) {
expected: true,
expectedKnown: true,
},
{
// Issue #1315: both dates absent must not read as "in extended support".
name: "Zero start and zero end date - unknown, not silently true",
engine: "mysql",
version: "5.7.44",
versionInfo: map[string]MajorEngineVersionInfo{
"mysql:5.7": {
Engine: "mysql",
MajorEngineVersion: "5.7",
SupportedEngineLifecycles: []EngineLifecycleInfo{
{
LifecycleSupportName: string(rdstypes.LifecycleSupportNameOpenSourceRdsExtendedSupport),
},
},
},
},
expected: false,
expectedKnown: false,
},
{
// Issue #1315: a missing start date is skipped even with a future end date.
name: "Zero start date with future end date - unknown, not silently true",
engine: "mysql",
version: "5.7.44",
versionInfo: map[string]MajorEngineVersionInfo{
"mysql:5.7": {
Engine: "mysql",
MajorEngineVersion: "5.7",
SupportedEngineLifecycles: []EngineLifecycleInfo{
{
LifecycleSupportName: string(rdstypes.LifecycleSupportNameOpenSourceRdsExtendedSupport),
LifecycleSupportEndDate: futureDate,
},
},
},
},
expected: false,
expectedKnown: false,
},
{
// A well-formed active entry still proves extended support even
// when another extended entry is missing its start date.
name: "Zero start entry alongside a valid active entry",
engine: "mysql",
version: "5.7.44",
versionInfo: map[string]MajorEngineVersionInfo{
"mysql:5.7": {
Engine: "mysql",
MajorEngineVersion: "5.7",
SupportedEngineLifecycles: []EngineLifecycleInfo{
{
LifecycleSupportName: string(rdstypes.LifecycleSupportNameOpenSourceRdsExtendedSupport),
LifecycleSupportEndDate: futureDate,
},
{
LifecycleSupportName: string(rdstypes.LifecycleSupportNameOpenSourceRdsExtendedSupport),
LifecycleSupportStartDate: pastDate,
LifecycleSupportEndDate: futureDate,
},
},
},
},
expected: true,
expectedKnown: true,
},
{
// A zero start date on a non-extended entry is irrelevant.
name: "Zero start date on standard support entry is ignored",
engine: "mysql",
version: "8.0.35",
versionInfo: map[string]MajorEngineVersionInfo{
"mysql:8.0": {
Engine: "mysql",
MajorEngineVersion: "8.0",
SupportedEngineLifecycles: []EngineLifecycleInfo{
{
LifecycleSupportName: string(rdstypes.LifecycleSupportNameOpenSourceRdsStandardSupport),
LifecycleSupportEndDate: futureDate,
},
},
},
},
expected: false,
expectedKnown: true,
},
{
name: "Engine name normalization with spaces",
engine: "Aurora MySQL",
Expand Down Expand Up @@ -776,6 +861,53 @@ func TestIsInExtendedSupport(t *testing.T) {
}
}

// TestIsInExtendedSupport_ZeroStartDateWarns covers issue #1315: an
// extended-support entry with no start date is logged with the engine and
// major version, and the instance stays in the recommendation count.
func TestIsInExtendedSupport_ZeroStartDateWarns(t *testing.T) {
versionInfo := map[string]MajorEngineVersionInfo{
"mysql:5.7": {
Engine: "mysql",
MajorEngineVersion: "5.7",
SupportedEngineLifecycles: []EngineLifecycleInfo{
{
LifecycleSupportName: string(rdstypes.LifecycleSupportNameOpenSourceRdsExtendedSupport),
LifecycleSupportEndDate: time.Now().AddDate(1, 0, 0),
},
},
},
}
recommendation := common.Recommendation{
Service: common.ServiceRDS,
Region: "us-east-1",
ResourceType: "db.r5.large",
Count: 2,
Details: &common.DatabaseDetails{Engine: "MySQL"},
}
instanceVersions := map[string][]InstanceEngineVersion{
"db.r5.large": {
{Engine: "mysql", EngineVersion: "5.7.44", InstanceClass: "db.r5.large", Region: "us-east-1"},
},
}

var logBuf bytes.Buffer
origOutput := log.Writer()
origFlags := log.Flags()
log.SetOutput(&logBuf)
log.SetFlags(0)
defer func() {
log.SetOutput(origOutput)
log.SetFlags(origFlags)
}()

result := adjustRecommendationForExcludedVersions(recommendation, instanceVersions, versionInfo)

assert.Equal(t, 2, result.Count, "missing start date must not exclude the instance")
logged := logBuf.String()
assert.Contains(t, logged, "mysql 5.7 has no start date", "warning must name the engine and major version")
assert.Contains(t, logged, "No lifecycle data for mysql 5.7.44", "caller must surface the unknown status")
}

// TestQueryRunningInstanceEngineVersions_ProfileSelection asserts the
// validation-profile precedence deterministically: the profiles name entries
// absent from the (redirected, empty) shared config, so config loading fails
Expand Down
Loading