aws

package
v0.42.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 11, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package aws provides EC2 capacity discovery for the truffle tool. It searches instance type availability, retrieves Spot pricing history, and queries On-Demand Capacity Reservations (ODCRs) and Capacity Blocks for ML workloads across one or more AWS regions concurrently.

Typical usage:

client, err := aws.NewClient(ctx)
results, err := client.SearchInstanceTypes(ctx, []string{"us-east-1"}, pattern, filterOpts)
prices, err := client.GetSpotPricing(ctx, results, aws.SpotOptions{ShowSavings: true})

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Capabilities added in v0.38.0

type Capabilities struct {
	InstanceType         string   `json:"instance_type"`
	Found                bool     `json:"found"`
	Architectures        []string `json:"architectures,omitempty"` // e.g. ["x86_64"], ["arm64"]
	ClusterPlacement     bool     `json:"cluster_placement"`       // supports the "cluster" placement strategy (MPI)
	EFA                  bool     `json:"efa"`                     // supports Elastic Fabric Adapter
	Hibernation          bool     `json:"hibernation"`             // supports On-Demand hibernation
	NestedVirtualization bool     `json:"nested_virtualization"`   // can run KVM/Hyper-V in-instance
	GPUs                 int32    `json:"gpus,omitempty"`
	BareMetal            bool     `json:"bare_metal"`
}

Capabilities is a feature-support snapshot for a single instance type, from one DescribeInstanceTypes call. truffle is the instance-type capability authority for the spore.host tools; other tools (e.g. spawn's pre-flight launch validation) consume this instead of re-querying EC2 themselves.

type CapacityBlockOfferingOptions added in v0.40.0

type CapacityBlockOfferingOptions struct {
	InstanceType          string // required
	InstanceCount         int32  // required by us; defaults to 1
	CapacityDurationHours int32  // required by AWS
	StartAfter            string // ISO-8601; earliest block start → StartDateRange
	EndBy                 string // ISO-8601; latest block end → EndDateRange
	Verbose               bool
}

CapacityBlockOfferingOptions are the query parameters for discovering purchasable Capacity Block offerings. CapacityDurationHours and InstanceType are required by the AWS DescribeCapacityBlockOfferings API; InstanceCount defaults to 1.

type CapacityBlockOfferingResult added in v0.40.0

type CapacityBlockOfferingResult struct {
	OfferingID       string `json:"offering_id" yaml:"offering_id"`
	InstanceType     string `json:"instance_type" yaml:"instance_type"`
	InstanceCount    int32  `json:"instance_count" yaml:"instance_count"`
	AvailabilityZone string `json:"availability_zone" yaml:"availability_zone"`
	Region           string `json:"region" yaml:"region"`
	StartDate        string `json:"start_date" yaml:"start_date"`
	EndDate          string `json:"end_date" yaml:"end_date"`
	DurationHours    int32  `json:"duration_hours" yaml:"duration_hours"`
	UpfrontFee       string `json:"upfront_fee" yaml:"upfront_fee"` // total up-front price (string per AWS)
	CurrencyCode     string `json:"currency_code" yaml:"currency_code"`
	Tenancy          string `json:"tenancy,omitempty" yaml:"tenancy,omitempty"`
}

CapacityBlockOfferingResult represents a PURCHASABLE Capacity Block offering (the answer to "what can I reserve?"), as returned by DescribeCapacityBlock Offerings — distinct from CapacityBlockResult, which represents an EXISTING reservation you already own. The OfferingID is what spawn purchases (spawn#217).

type CapacityBlockOptions

type CapacityBlockOptions struct {
	InstanceTypes []string
	MinDuration   int32  // Minimum duration in hours
	MaxDuration   int32  // Maximum duration in hours
	StartAfter    string // ISO format datetime
	StartBefore   string // ISO format datetime
	OnlyActive    bool
	Verbose       bool
}

CapacityBlockOptions contains Capacity Block search options

type CapacityBlockResult

type CapacityBlockResult struct {
	CapacityBlockID       string   `json:"capacity_block_id" yaml:"capacity_block_id"`
	InstanceType          string   `json:"instance_type" yaml:"instance_type"`
	InstanceCount         int32    `json:"instance_count" yaml:"instance_count"`
	AvailabilityZone      string   `json:"availability_zone" yaml:"availability_zone"`
	StartDate             string   `json:"start_date" yaml:"start_date"`
	EndDate               string   `json:"end_date" yaml:"end_date"`
	DurationHours         int32    `json:"duration_hours" yaml:"duration_hours"`
	State                 string   `json:"state" yaml:"state"` // scheduled, active, completed, cancelled
	ReservationFee        float64  `json:"reservation_fee" yaml:"reservation_fee"`
	UltraClusterPlacement bool     `json:"ultra_cluster_placement" yaml:"ultra_cluster_placement"`
	Tags                  []string `json:"tags,omitempty" yaml:"tags,omitempty"`
}

CapacityBlockResult represents a Capacity Block for ML

type CapacityReservationOptions

type CapacityReservationOptions struct {
	InstanceTypes  []string
	OnlyAvailable  bool  // Only show reservations with available capacity
	OnlyActive     bool  // Only show active reservations
	IncludeExpired bool  // Include expired reservations
	MinCapacity    int32 // Minimum available capacity
	Verbose        bool
}

CapacityReservationOptions contains ODCR search options

type CapacityReservationResult

type CapacityReservationResult struct {
	ReservationID     string   `json:"reservation_id" yaml:"reservation_id"`
	InstanceType      string   `json:"instance_type" yaml:"instance_type"`
	Region            string   `json:"region" yaml:"region"`
	AvailabilityZone  string   `json:"availability_zone" yaml:"availability_zone"`
	TotalCapacity     int32    `json:"total_capacity" yaml:"total_capacity"`
	AvailableCapacity int32    `json:"available_capacity" yaml:"available_capacity"`
	UsedCapacity      int32    `json:"used_capacity" yaml:"used_capacity"`
	State             string   `json:"state" yaml:"state"`
	Tenancy           string   `json:"tenancy" yaml:"tenancy"`
	EBSOptimized      bool     `json:"ebs_optimized" yaml:"ebs_optimized"`
	EndDate           string   `json:"end_date,omitempty" yaml:"end_date,omitempty"`
	Platform          string   `json:"platform" yaml:"platform"`
	Tags              []string `json:"tags,omitempty" yaml:"tags,omitempty"`
}

CapacityReservationResult represents an ODCR (On-Demand Capacity Reservation)

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client wraps AWS SDK clients

func NewClient

func NewClient(ctx context.Context) (*Client, error)

NewClient creates a new AWS client using the default credential chain.

func NewClientFromConfig

func NewClientFromConfig(cfg aws.Config) *Client

NewClientFromConfig creates a new AWS client with an injected aws.Config. Use this in tests to point the client at a Substrate emulator.

func (*Client) GetAllRegions

func (c *Client) GetAllRegions(ctx context.Context) ([]string, error)

GetAllRegions is deprecated. Use GetEnabledRegions instead. This method is kept for backward compatibility.

func (*Client) GetCapabilities added in v0.38.0

func (c *Client) GetCapabilities(ctx context.Context, instanceType, region string) (*Capabilities, error)

GetCapabilities returns feature support for a single instance type in the given region (region may be empty for the client default). Backed by one DescribeInstanceTypes call; the API is the source of truth (no hardcoded family lists).

func (*Client) GetCapacityBlockOfferings added in v0.40.0

func (c *Client) GetCapacityBlockOfferings(ctx context.Context, regions []string, opts CapacityBlockOfferingOptions) ([]CapacityBlockOfferingResult, error)

GetCapacityBlockOfferings discovers PURCHASABLE Capacity Block offerings across regions via DescribeCapacityBlockOfferings (the "what can I reserve?" query) — distinct from GetCapacityBlocks, which lists blocks you already own. Read-only. The returned OfferingID feeds spawn's purchase command (spawn#217). Price (UpfrontFee + CurrencyCode) comes directly from each offering — no separate pricing lookup needed.

func (*Client) GetCapacityBlocks

func (c *Client) GetCapacityBlocks(ctx context.Context, regions []string, opts CapacityBlockOptions) ([]CapacityBlockResult, error)

GetCapacityBlocks retrieves Capacity Blocks for ML

func (*Client) GetCapacityReservations

func (c *Client) GetCapacityReservations(ctx context.Context, regions []string, opts CapacityReservationOptions) ([]CapacityReservationResult, error)

GetCapacityReservations retrieves On-Demand Capacity Reservations (ODCRs)

func (*Client) GetEnabledRegions

func (c *Client) GetEnabledRegions(ctx context.Context) ([]string, error)

GetEnabledRegions returns AWS regions enabled for this account. This respects Service Control Policies (SCPs) that may restrict regions. Regions blocked by organizational SCPs will not appear in the returned list.

func (*Client) GetInstanceTypes

func (c *Client) GetInstanceTypes(ctx context.Context, region string) ([]string, error)

GetInstanceTypes returns all instance types in a region

func (*Client) GetSpotPricing

func (c *Client) GetSpotPricing(ctx context.Context, instances []InstanceTypeResult, opts SpotOptions) ([]SpotPriceResult, error)

GetSpotPricing retrieves current Spot pricing for instance types

func (*Client) HourlyRate added in v0.36.2

func (c *Client) HourlyRate(ctx context.Context, instanceType, region, model string) (float64, error)

HourlyRate returns the current $/hr for one instance type in one region under the given purchase model. It is a library-friendly convenience for embedders that want a single number rather than reducing a []SpotPriceResult by hand.

model is case-insensitive:

  • "on-demand" / "ondemand" / "" → the On-Demand rate.
  • "spot" → the minimum current Spot price across AZs in the region (Spot varies by AZ; the minimum is the best obtainable rate). Returns an error if no Spot price is currently published for the type.

"reserved" is not a point-in-time rate (it depends on term, payment option, and offering class) and is rejected; use the On-Demand rate as the baseline and apply your own reserved discount.

func (*Client) OnDemandPrice added in v0.36.2

func (c *Client) OnDemandPrice(ctx context.Context, instanceType, region string) (float64, error)

OnDemandPrice returns the current On-Demand $/hr for one instance type in one region (Linux, shared tenancy). It is a thin accessor over the client's OnDemandPricer; see Client.HourlyRate for a purchase-model-aware helper.

func (*Client) SageMakerPrice added in v0.42.0

func (c *Client) SageMakerPrice(ctx context.Context, instanceType, region string) (float64, error)

SageMakerPrice returns the current On-Demand $/hr for one ml.* instance type in one region. It is a thin accessor over the client's SageMakerPricer.

func (*Client) SearchInstanceTypes

func (c *Client) SearchInstanceTypes(ctx context.Context, regions []string, matcher *regexp.Regexp, opts FilterOptions) ([]InstanceTypeResult, error)

SearchInstanceTypes searches for instance types matching the pattern across regions

func (*Client) SearchSageMakerInstanceTypes added in v0.42.0

func (c *Client) SearchSageMakerInstanceTypes(ctx context.Context, regions []string, matcher *regexp.Regexp, opts FilterOptions) ([]InstanceTypeResult, error)

SearchSageMakerInstanceTypes searches for SageMaker ml.* instance types matching the pattern across regions. It mirrors Client.SearchInstanceTypes: per-region concurrency and the #63 error-aggregation contract (a total failure must not masquerade as an empty result).

Unlike EC2, SageMaker has no DescribeInstanceTypes API, so the offered set comes from Service Quotas. Specs (vCPU/memory/GPU/arch) are derived from the underlying EC2 instance type (ml.g5.2xlarge → g5.2xlarge), which runs on the same hardware. Results carry Service="sagemaker" and SpawnSupported=false (spawn launches EC2, not SageMaker); OnDemandPrice is left 0 — SageMaker pricing is a separate concern (issue #80).

func (*Client) SetOnDemandPricer added in v0.36.2

func (c *Client) SetOnDemandPricer(p OnDemandPricer)

SetOnDemandPricer overrides the On-Demand price source used by this client. Pass nil to reset to the default AWS Price List pricer. This is primarily for embedders and tests that want deterministic prices or an offline source.

func (*Client) SetSageMakerPricer added in v0.42.0

func (c *Client) SetSageMakerPricer(p SageMakerPricer)

SetSageMakerPricer overrides the SageMaker price source used by this client. Pass nil to reset to the default AWS Price List pricer. Primarily for embedders and tests that want deterministic prices or an offline source.

func (*Client) SetSageMakerTypeLister added in v0.42.0

func (c *Client) SetSageMakerTypeLister(l SageMakerTypeLister)

SetSageMakerTypeLister overrides the source of offered ml.* types used by this client. Pass nil to reset to the default Service Quotas lister. This is primarily for embedders and tests that want a deterministic offering set.

type FilterOptions

type FilterOptions struct {
	IncludeAZs       bool    // If true, populate InstanceTypeResult.AvailableAZs (one extra API call per type)
	Architecture     string  // Filter to "x86_64" or "arm64"; empty matches both
	MinVCPUs         int     // Minimum vCPU count; 0 disables this filter
	MinMemory        float64 // Minimum memory in GiB; 0 disables this filter
	MinPhysicalCores int     // Minimum physical core count; 0 disables this filter
	ExactVCPUs       bool    // If true, match exact vCPU count instead of minimum
	ExactMemory      bool    // If true, match exact memory instead of minimum
	ExactCores       bool    // If true, match exact physical core count instead of minimum
	InstanceFamily   string  // Restrict to a family prefix, e.g. "m6i"; empty matches all
	NestedVirt       bool    // If true, only types supporting nested virtualization (KVM/Hyper-V in-instance)
	Verbose          bool    // If true, log per-region progress to stderr
}

FilterOptions controls which instance types are returned by Client.SearchInstanceTypes.

type Finder added in v0.36.8

type Finder interface {
	// GetEnabledRegions returns regions enabled for the caller's account.
	GetEnabledRegions(ctx context.Context) ([]string, error)

	// GetAllRegions returns all AWS regions (enabled or not).
	GetAllRegions(ctx context.Context) ([]string, error)

	// GetInstanceTypes returns all instance type names available in a region.
	GetInstanceTypes(ctx context.Context, region string) ([]string, error)

	// SearchInstanceTypes finds instance types matching a pattern across regions.
	SearchInstanceTypes(ctx context.Context, regions []string, matcher *regexp.Regexp, opts FilterOptions) ([]InstanceTypeResult, error)

	// GetSpotPricing retrieves current Spot pricing for instance types.
	GetSpotPricing(ctx context.Context, instances []InstanceTypeResult, opts SpotOptions) ([]SpotPriceResult, error)

	// GetCapacityReservations retrieves ODCRs across regions.
	GetCapacityReservations(ctx context.Context, regions []string, opts CapacityReservationOptions) ([]CapacityReservationResult, error)

	// GetCapacityBlocks retrieves Capacity Blocks for ML across regions.
	GetCapacityBlocks(ctx context.Context, regions []string, opts CapacityBlockOptions) ([]CapacityBlockResult, error)

	// GetCapacityBlockOfferings discovers purchasable Capacity Block offerings across regions.
	GetCapacityBlockOfferings(ctx context.Context, regions []string, opts CapacityBlockOfferingOptions) ([]CapacityBlockOfferingResult, error)

	// OnDemandPrice returns the on-demand $/hr for an instance type in a region.
	OnDemandPrice(ctx context.Context, instanceType, region string) (float64, error)

	// HourlyRate returns $/hr under a given purchase model ("on-demand" or "spot").
	HourlyRate(ctx context.Context, instanceType, region, model string) (float64, error)
}

Finder is the read-only query interface for EC2 instance discovery. The concrete Client satisfies this interface. Downstream consumers should accept Finder in their function signatures to enable unit testing with [awsmock.Finder] or any custom implementation.

type InstanceTypeResult

type InstanceTypeResult struct {
	InstanceType    string   `json:"instance_type" yaml:"instance_type"`                                     // EC2 instance type, e.g. "m6i.2xlarge"
	Region          string   `json:"region" yaml:"region"`                                                   // AWS region where this type is available
	AvailableAZs    []string `json:"availability_zones,omitempty" yaml:"availability_zones,omitempty"`       // AZs with capacity; populated when FilterOptions.IncludeAZs is true
	VCPUs           int32    `json:"vcpus,omitempty" yaml:"vcpus,omitempty"`                                 // Default vCPU count
	PhysicalCores   int32    `json:"physical_cores,omitempty" yaml:"physical_cores,omitempty"`               // Physical CPU cores (vCPUs / threads-per-core)
	ThreadsPerCore  int32    `json:"threads_per_core,omitempty" yaml:"threads_per_core,omitempty"`           // Threads per physical core (1 for Graviton, 2 for most x86)
	MemoryMiB       int64    `json:"memory_mib,omitempty" yaml:"memory_mib,omitempty"`                       // Memory in MiB
	Architecture    string   `json:"architecture,omitempty" yaml:"architecture,omitempty"`                   // CPU architecture: "x86_64" or "arm64"
	InstanceFamily  string   `json:"instance_family,omitempty" yaml:"instance_family,omitempty"`             // Family prefix, e.g. "m6i"
	GPUs            int32    `json:"gpus,omitempty" yaml:"gpus,omitempty"`                                   // Number of GPUs; 0 for non-GPU instances
	GPUMemoryMiB    int64    `json:"gpu_memory_mib,omitempty" yaml:"gpu_memory_mib,omitempty"`               // Total GPU memory in MiB across all GPUs
	GPUModel        string   `json:"gpu_model,omitempty" yaml:"gpu_model,omitempty"`                         // GPU model name, e.g. "A100"
	GPUManufacturer string   `json:"gpu_manufacturer,omitempty" yaml:"gpu_manufacturer,omitempty"`           // GPU vendor, e.g. "nvidia"
	OnDemandPrice   float64  `json:"on_demand_price,omitempty" yaml:"on_demand_price,omitempty"`             // On-demand $/hr; 0 if not yet fetched
	SpawnSupported  bool     `json:"spawn_supported,omitempty" yaml:"spawn_supported,omitempty"`             // True if spawn can launch instances in this region
	NestedVirt      bool     `json:"nested_virtualization,omitempty" yaml:"nested_virtualization,omitempty"` // True if the type supports nested virtualization (KVM/Hyper-V in-instance)
	Service         string   `json:"service,omitempty" yaml:"service,omitempty"`                             // Offering namespace: "" / "ec2" (default) or "sagemaker" for ml.* types

	// SageMaker-only fields (populated when Service == "sagemaker"):
	ManagedSpotEligible bool     `json:"managed_spot_eligible,omitempty" yaml:"managed_spot_eligible,omitempty"` // Type can be used with managed spot training (has a "spot training job usage" quota). Managed spot is a billed-time discount (up to 90%), not a spot market — there is no per-type spot price.
	TrainingJobQuota    *float64 `json:"training_job_quota,omitempty" yaml:"training_job_quota,omitempty"`       // Account limit for "training job usage" of this type; nil when the region exposes no such quota. 0 means an increase must be requested before launching.
}

InstanceTypeResult represents an instance type's availability and specifications in a given region, as returned by Client.SearchInstanceTypes.

type OnDemandPricer added in v0.36.2

type OnDemandPricer interface {
	// OnDemandPrice returns the On-Demand $/hr for instanceType in region.
	// It returns (0, error) when no price could be determined.
	OnDemandPrice(ctx context.Context, instanceType, region string) (float64, error)
}

OnDemandPricer resolves the On-Demand hourly rate ($/hr) for a Linux instance type in a region. Implementations should be safe for concurrent use.

truffle uses this to populate SpotPriceResult.OnDemandPrice and SpotPriceResult.SavingsPercent (when SpotOptions.ShowSavings is set) and to back the Client.HourlyRate convenience. The default implementation (NewAWSOnDemandPricer) queries the AWS Price List API and caches results; callers embedding truffle as a library can inject their own via Client.SetOnDemandPricer (e.g. a fixture in tests).

func NewAWSOnDemandPricer added in v0.36.2

func NewAWSOnDemandPricer(cfg aws.Config) OnDemandPricer

NewAWSOnDemandPricer returns an OnDemandPricer backed solely by the AWS Price List API (no static fallback). Most callers want the client default; this is exported for embedders that want to control fallback behavior.

type SageMakerPricer added in v0.42.0

type SageMakerPricer interface {
	// SageMakerPrice returns the On-Demand $/hr for an ml.* instanceType in
	// region. It returns (0, error) when no price could be determined.
	SageMakerPrice(ctx context.Context, instanceType, region string) (float64, error)
}

SageMakerPricer resolves the On-Demand hourly rate ($/hr) for a SageMaker ml.* instance type in a region. SageMaker is priced under a distinct offer (AmazonSageMaker) with a management premium over the equivalent EC2 rate, so it cannot reuse the EC2 pricer. Implementations should be safe for concurrent use.

The default implementation queries the AWS Price List API and caches results; embedders and tests can inject their own via Client.SetSageMakerPricer.

func NewAWSSageMakerPricer added in v0.42.0

func NewAWSSageMakerPricer(cfg aws.Config) SageMakerPricer

NewAWSSageMakerPricer returns a SageMakerPricer backed by the AWS Price List API. Exported for embedders that want to control pricing directly.

type SageMakerTypeLister added in v0.42.0

type SageMakerTypeLister interface {
	// OfferedTypes returns the ml.*-prefixed types offered in region, with quota detail.
	OfferedTypes(ctx context.Context, region string) ([]quotas.SageMakerTypeQuota, error)
}

SageMakerTypeLister returns the SageMaker ml.* instance types offered in a region, with their per-type quota detail (training-job limit, managed-spot eligibility). There is no SageMaker equivalent of EC2 DescribeInstanceTypes, so the authoritative source is Service Quotas (which lists a quota per ml.* type). Implementations should be safe for concurrent use.

The default implementation queries Service Quotas via pkg/quotas; embedders and tests can inject their own with Client.SetSageMakerTypeLister.

type SpotOptions

type SpotOptions struct {
	MaxPrice      float64 // Exclude results above this $/hr threshold; 0 disables
	ShowSavings   bool    // Populate SpotPriceResult.SavingsPercent by comparing with on-demand price
	LookbackHours int     // Hours of price history to query; 0 uses the AWS default (typically 1 hour)
	OnlyActive    bool    // Exclude price history entries with no current offering
	Verbose       bool    // If true, log per-region progress to stderr
}

SpotOptions controls the behavior of Client.GetSpotPricing.

type SpotPriceResult

type SpotPriceResult struct {
	InstanceType     string  `json:"instance_type" yaml:"instance_type"`                         // EC2 instance type
	Region           string  `json:"region" yaml:"region"`                                       // AWS region
	AvailabilityZone string  `json:"availability_zone" yaml:"availability_zone"`                 // AZ where this price applies
	SpotPrice        float64 `json:"spot_price" yaml:"spot_price"`                               // Current Spot price in $/hr
	OnDemandPrice    float64 `json:"on_demand_price,omitempty" yaml:"on_demand_price,omitempty"` // On-demand $/hr for savings calculation; 0 if unavailable
	SavingsPercent   float64 `json:"savings_percent,omitempty" yaml:"savings_percent,omitempty"` // Discount vs on-demand: 100*(1-spot/ondemand); set when SpotOptions.ShowSavings is true
	Timestamp        string  `json:"timestamp" yaml:"timestamp"`                                 // RFC3339 timestamp of the price observation
	ProductType      string  `json:"product_type,omitempty" yaml:"product_type,omitempty"`       // OS description, e.g. "Linux/UNIX"
}

SpotPriceResult represents a Spot instance price observation for one AZ, as returned by Client.GetSpotPricing.

Directories

Path Synopsis
Package awsmock provides a configurable mock implementation of aws.Finder for unit testing downstream consumers of truffle's instance discovery API.
Package awsmock provides a configurable mock implementation of aws.Finder for unit testing downstream consumers of truffle's instance discovery API.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL