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
32 changes: 26 additions & 6 deletions pkg/common/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,20 +242,40 @@ type Region struct {
DisplayName string `json:"display_name"`
}

// ComputeDetails represents compute-specific details (EC2, VM, Compute Engine)
// ComputeDetails represents compute-specific details (EC2, VM, Compute Engine).
//
// VCPU + MemoryGB are populated by per-provider catalogue lookups when
// available (Azure: armcompute.ResourceSKU.Capabilities; AWS:
// ec2:DescribeInstanceTypes; GCP: machine-type catalogue). They are
// optional — converters that don't yet wire a catalogue leave them at the
// zero value, and the JSON tag uses omitempty so unknown values don't
// pollute the API payload.
type ComputeDetails struct {
InstanceType string `json:"instance_type"`
Platform string `json:"platform"` // linux, windows
Tenancy string `json:"tenancy"` // default, dedicated, host
Scope string `json:"scope"` // regional, zonal
InstanceType string `json:"instance_type"`
Platform string `json:"platform"` // linux, windows
Tenancy string `json:"tenancy"` // default, dedicated, host
Scope string `json:"scope"` // regional, zonal
VCPU int `json:"vcpu,omitempty"` // 0 = unknown
MemoryGB float64 `json:"memory_gb,omitempty"` // 0 = unknown
}

func (d ComputeDetails) GetServiceType() ServiceType {
return ServiceCompute
}

// GetDetailDescription returns a short human description of the compute
// recommendation. The base form is "<platform>/<tenancy>"; when both VCPU
// and MemoryGB are populated (>0) the size is appended as
// " (<vcpu> vCPU / <memory> GB)" to give the UI a one-line summary
// without forcing the caller to inspect the struct.
func (d ComputeDetails) GetDetailDescription() string {
return d.Platform + "/" + d.Tenancy
base := d.Platform + "/" + d.Tenancy
if d.VCPU > 0 && d.MemoryGB > 0 {
// %g trims trailing zeros (16 GB, not 16.000000 GB) but keeps
// fractional sizes (e.g. 0.5 GB for the smallest Azure SKUs).
return fmt.Sprintf("%s (%d vCPU / %g GB)", base, d.VCPU, d.MemoryGB)
}
return base
}

// DatabaseDetails represents database-specific details (RDS, Azure SQL, Cloud SQL)
Expand Down
45 changes: 45 additions & 0 deletions pkg/common/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,51 @@ func TestComputeDetails_GetDetailDescription(t *testing.T) {
},
expected: "windows/dedicated",
},
{
// vCPU alone is insufficient — both fields must be populated for
// the size suffix to appear, otherwise we'd surface "16 vCPU /
// 0 GB" which is misleading.
name: "VCPU populated but MemoryGB zero — base description only",
details: ComputeDetails{
Platform: "linux",
Tenancy: "default",
VCPU: 16,
},
expected: "linux/default",
},
{
// Symmetric guard for the MemoryGB-only case.
name: "MemoryGB populated but VCPU zero — base description only",
details: ComputeDetails{
Platform: "linux",
Tenancy: "default",
MemoryGB: 32,
},
expected: "linux/default",
},
{
// Whole-number GB renders without trailing zeros (16 GB,
// not 16.000000 GB).
name: "Both fields populated — integer memory",
details: ComputeDetails{
Platform: "linux",
Tenancy: "default",
VCPU: 4,
MemoryGB: 16,
},
expected: "linux/default (4 vCPU / 16 GB)",
},
{
// Fractional GB (Azure has 0.5 GB SKUs) renders verbatim.
name: "Both fields populated — fractional memory",
details: ComputeDetails{
Platform: "linux",
Tenancy: "default",
VCPU: 1,
MemoryGB: 0.5,
},
expected: "linux/default (1 vCPU / 0.5 GB)",
},
}

for _, tt := range tests {
Expand Down