diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e843aaa..73ac2ad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,14 +1,11 @@ name: CI on: - pull_request: push: branches: - main - -env: - NODE_VERSION: "22" - GO_VERSION: "1.24" + - "release/*" + pull_request: jobs: test: @@ -17,28 +14,48 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Setup Node.js - uses: actions/setup-node@v4 + - name: Set up Go + uses: actions/setup-go@v5 with: - node-version: ${{ env.NODE_VERSION }} - cache: npm - cache-dependency-path: web/package-lock.json + go-version-file: go.mod + cache: true - - name: Install frontend deps - run: npm ci - working-directory: web + - name: Go test + run: go test ./... - - name: Build frontend - run: npm run build - working-directory: web + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 - - name: Setup Go + - name: Set up Go uses: actions/setup-go@v5 with: - go-version: ${{ env.GO_VERSION }} + go-version-file: go.mod + cache: true - - name: Go test - run: | - export GOMODCACHE="$GITHUB_WORKSPACE/.gocache" - export GOCACHE="$GITHUB_WORKSPACE/.gocache/go" - go test ./... + - name: Run golangci-lint + uses: golangci/golangci-lint-action@v9 + with: + version: latest + args: --config .golangci.yml + install-mode: goinstall + + gosec: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Install gosec + run: go install github.com/securego/gosec/v2/cmd/gosec@v2.22.1 + + - name: Run gosec + run: $(go env GOPATH)/bin/gosec -exclude-dir=internal/proto -exclude-dir=.gocache ./... diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 870cd43..435ad12 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,12 +1,11 @@ name: Build and Publish Docker Image on: - push: - branches: - - main - tags: - - "v*" - workflow_dispatch: + workflow_call: + inputs: + tag: + required: true + type: string env: IMAGE_NAME: jesuspaz/clustercost-dashboard @@ -30,6 +29,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + with: + ref: ${{ inputs.tag }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -46,8 +47,8 @@ jobs: with: images: ${{ env.IMAGE_NAME }} tags: | - type=ref,event=tag - type=raw,value=latest,enable={{is_default_branch}} + type=raw,value=${{ inputs.tag }} + type=raw,value=latest type=sha flavor: | suffix=-${{ matrix.arch }} @@ -71,6 +72,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + with: + ref: ${{ inputs.tag }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -87,9 +90,8 @@ jobs: with: images: ${{ env.IMAGE_NAME }} tags: | - type=ref,event=tag - type=raw,value=latest,enable={{is_default_branch}} - type=sha + type=raw,value=${{ inputs.tag }} + type=raw,value=latest - name: Create multi-arch manifests run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..bebf4c8 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,93 @@ +name: Manual Release + +on: + workflow_dispatch: + inputs: + bump: + description: "Version bump type" + required: true + type: choice + options: + - patch + - minor + - major + - custom + custom_version: + description: "Custom semver tag (e.g., v0.2.0). Required when bump=custom." + required: false + +jobs: + release: + runs-on: ubuntu-latest + permissions: + contents: write + outputs: + version: ${{ steps.version.outputs.version }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Compute release version + id: version + shell: bash + run: | + set -euo pipefail + bump="${{ inputs.bump }}" + custom="${{ inputs.custom_version }}" + + if [[ "$bump" == "custom" ]]; then + if [[ -z "$custom" ]]; then + echo "custom_version is required when bump=custom" >&2 + exit 1 + fi + if [[ ! "$custom" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "custom_version must be semver like v0.2.0" >&2 + exit 1 + fi + version="$custom" + else + git fetch --tags --force + latest=$(git tag -l "v[0-9]*.[0-9]*.[0-9]*" | sort -V | tail -n 1) + if [[ -z "$latest" ]]; then + latest="v0.0.0" + fi + base="${latest#v}" + IFS='.' read -r major minor patch <<< "$base" + case "$bump" in + patch) patch=$((patch + 1)) ;; + minor) minor=$((minor + 1)); patch=0 ;; + major) major=$((major + 1)); minor=0; patch=0 ;; + esac + version="v${major}.${minor}.${patch}" + fi + + echo "version=${version}" >> "$GITHUB_OUTPUT" + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Run Go tests + env: + GOCACHE: ${{ github.workspace }}/.gocache + run: go test ./... + + - name: Create GitHub release + uses: softprops/action-gh-release@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ steps.version.outputs.version }} + name: ClusterCost Dashboard ${{ steps.version.outputs.version }} + generate_release_notes: true + + docker: + needs: release + uses: ./.github/workflows/docker.yml + with: + tag: ${{ needs.release.outputs.version }} + secrets: inherit diff --git a/.gitignore b/.gitignore index 7c018ab..f639991 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,8 @@ internal/static/dist/* .DS_Store .vscode/ .idea/ + +/dashboard +.env + +data/clustercost.db \ No newline at end of file diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..2669cef --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,22 @@ +version: "2" +run: + tests: false +linters: + enable: + - misspell + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ +issues: + max-issues-per-linter: 0 + max-same-issues: 0 +formatters: + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/Dockerfile b/Dockerfile index 759e5d4..1b84fb7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,11 +23,14 @@ COPY web/tailwind.config.cjs web/postcss.config.cjs web/vite.config.ts web/tscon COPY web/src ./web/src COPY --from=frontend /app/web/dist ./web/dist RUN mkdir -p internal/static && rm -rf internal/static/dist && cp -r web/dist internal/static/dist +COPY scripts ./scripts +# RUN go run scripts/generate_pricing.go RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o /dashboard ./cmd/dashboard FROM --platform=$TARGETPLATFORM gcr.io/distroless/base-debian12:nonroot WORKDIR /app COPY --from=backend /dashboard /app/dashboard ENV LISTEN_ADDR=:9090 -EXPOSE 9090 +ENV GRPC_ADDR=:9091 +EXPOSE 9090 9091 ENTRYPOINT ["/app/dashboard"] diff --git a/Makefile b/Makefile index 7033661..15ee998 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,21 @@ -.PHONY: backend frontend build docker test clean dev-backend dev-frontend dev-bundle +.PHONY: backend frontend build docker test lint sec clean dev-backend dev-frontend dev-bundle generate-pricing + +generate-pricing: + go run scripts/generate_pricing.go BACKEND_ENV ?= LISTEN_ADDR=:9010 AGENT_URLS ?= BIN_DIR ?= $(PWD)/bin BINARY ?= $(BIN_DIR)/clustercost +PROTOC ?= protoc + +proto: + PATH="$(shell go env GOPATH)/bin:$$PATH" $(PROTOC) -I internal/proto \ + --go_out=paths=source_relative:internal/proto \ + --go-grpc_out=paths=source_relative:internal/proto \ + internal/proto/agent/v1/agent.proto + dev-backend: $(BACKEND_ENV) AGENT_URLS=$(AGENT_URLS) go run ./cmd/dashboard @@ -29,7 +40,16 @@ docker: test: GOMODCACHE=$(PWD)/.gocache GOCACHE=$(PWD)/.gocache/go go test ./... +lint: + golangci-lint run + +sec: + gosec -exclude-dir=internal/proto -exclude-dir=.gocache ./... + clean: rm -rf .gocache web/node_modules web/dist $(BIN_DIR) rm -rf internal/static/dist/* touch internal/static/dist/.gitkeep + +upload-latest: + docker buildx build --platform linux/amd64,linux/arm64 -t jesuspaz/clustercost-dashboard:latest --push --build-arg VERSION=$(VERSION) . diff --git a/cmd/dashboard/main.go b/cmd/dashboard/main.go index a1db34d..25d6e59 100644 --- a/cmd/dashboard/main.go +++ b/cmd/dashboard/main.go @@ -2,19 +2,22 @@ package main import ( "context" - "fmt" - "log" + "flag" "net/http" "os/signal" "strings" "syscall" "time" - "github.com/clustercost/clustercost-dashboard/internal/agents" "github.com/clustercost/clustercost-dashboard/internal/api" + "github.com/clustercost/clustercost-dashboard/internal/auth" "github.com/clustercost/clustercost-dashboard/internal/config" + "github.com/clustercost/clustercost-dashboard/internal/db" + "github.com/clustercost/clustercost-dashboard/internal/finops" + ccgrpc "github.com/clustercost/clustercost-dashboard/internal/grpc" "github.com/clustercost/clustercost-dashboard/internal/logging" "github.com/clustercost/clustercost-dashboard/internal/store" + "github.com/clustercost/clustercost-dashboard/internal/vm" ) func main() { @@ -25,37 +28,66 @@ func main() { logger.Fatalf("load config: %v", err) } - s := store.New(cfg.Agents, cfg.RecommendedAgentVersion) - client := agents.NewClient(10 * time.Second) + logLevel := flag.String("log-level", "", "Set the logging level (info, debug)") + flag.Parse() + + if *logLevel != "" { + cfg.LogLevel = strings.ToLower(*logLevel) + } + logger.Printf("Configured Log Level: %s", cfg.LogLevel) ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer stop() - go func() { - ticker := time.NewTicker(cfg.PollInterval) - defer ticker.Stop() - logger.Printf("starting poller with interval %s", cfg.PollInterval) - for { - if err := pollAgents(ctx, client, s, cfg, logger); err != nil { - logger.Printf("poll error: %v", err) - } - select { - case <-ctx.Done(): - return - case <-ticker.C: - } - } - }() + vmClient, err := vm.NewClient(cfg) + if err != nil { + logger.Fatalf("victoria metrics query setup error: %v", err) + } + + sqlite, err := db.New(cfg.StoragePath) + if err != nil { + logger.Fatalf("sqlite setup error: %v", err) + } + defer func() { _ = sqlite.Close() }() + + // Initialize In-Memory Store + st := store.New(cfg.Agents, cfg.RecommendedAgentVersion) + + // Initialize FinOps Engine + finopsEngine := finops.NewEngine(vmClient, st.PricingCatalog()) + + auth.SetSecret(cfg.JWTSecret) srv := &http.Server{ - Addr: cfg.ListenAddr, - Handler: api.NewRouter(s), + Addr: cfg.ListenAddr, + Handler: api.NewRouter(vmClient, sqlite, st, finopsEngine), + ReadHeaderTimeout: 5 * time.Second, + } + + vmIngestor, err := vm.NewIngestor(cfg, logger) + if err != nil { + logger.Fatalf("victoria metrics setup error: %v", err) + } + if vmIngestor != nil { + defer vmIngestor.Stop() + logger.Printf("victoria metrics ingest enabled") } + // Pass store to gRPC server so it can receive reports + grpcSrv := ccgrpc.NewServer(cfg, vmIngestor, st) + go func() { + logger.Printf("gRPC receiver initialized") + logger.Printf("gRPC listening on %s", cfg.GrpcAddr) + if err := grpcSrv.ListenAndServe(cfg.GrpcAddr); err != nil { + logger.Fatalf("grpc server error: %v", err) + } + }() + go func() { <-ctx.Done() shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() + grpcSrv.Stop() _ = srv.Shutdown(shutdownCtx) }() @@ -64,52 +96,3 @@ func main() { logger.Fatalf("server error: %v", err) } } - -func pollAgents(ctx context.Context, client *agents.Client, s *store.Store, cfg config.Config, logger *log.Logger) error { - for _, agent := range cfg.Agents { - snapshot := scrapeAgent(ctx, client, agent) - if snapshot.LastError != "" { - logger.Printf("agent %s error: %s", agent.Name, snapshot.LastError) - } - s.Update(agent.Name, snapshot) - } - return nil -} - -func scrapeAgent(ctx context.Context, client *agents.Client, cfg config.AgentConfig) store.AgentSnapshot { - agentCtx, cancel := context.WithTimeout(ctx, 20*time.Second) - defer cancel() - - snapshot := store.AgentSnapshot{LastScrape: time.Now()} - var errs []string - - if health, err := client.FetchHealth(agentCtx, cfg.BaseURL); err != nil { - errs = append(errs, fmt.Sprintf("health: %v", err)) - } else { - snapshot.Health = &health - } - - if namespaces, err := client.FetchNamespaces(agentCtx, cfg.BaseURL); err != nil { - errs = append(errs, fmt.Sprintf("namespaces: %v", err)) - } else { - snapshot.Namespaces = &namespaces - } - - if nodes, err := client.FetchNodes(agentCtx, cfg.BaseURL); err != nil { - errs = append(errs, fmt.Sprintf("nodes: %v", err)) - } else { - snapshot.Nodes = &nodes - } - - if resources, err := client.FetchResources(agentCtx, cfg.BaseURL); err != nil { - errs = append(errs, fmt.Sprintf("resources: %v", err)) - } else { - snapshot.Resources = &resources - } - - if len(errs) > 0 { - snapshot.LastError = strings.Join(errs, "; ") - } - - return snapshot -} diff --git a/cmd/mockagent/main.go b/cmd/mockagent/main.go index 4759ae8..5d70cda 100644 --- a/cmd/mockagent/main.go +++ b/cmd/mockagent/main.go @@ -5,6 +5,7 @@ import ( "flag" "log" "net/http" + "time" ) type summaryResponse struct { @@ -76,25 +77,25 @@ func main() { writeJSON(w, []map[string]any{ { "namespace": "payments", - "team": "backend", - "env": "prod", - "hourlyCost": 4.2, - "cpuRequestedCores": 3.5, - "cpuUsedCores": 2.8, - "memoryRequestedGiB": 8, - "memoryUsedGiB": 6.4, - "podCount": 23, + "team": "backend", + "env": "prod", + "hourlyCost": 4.2, + "cpuRequestedCores": 3.5, + "cpuUsedCores": 2.8, + "memoryRequestedGiB": 8, + "memoryUsedGiB": 6.4, + "podCount": 23, }, { "namespace": "api", - "team": "platform", - "env": "prod", - "hourlyCost": 3.5, - "cpuRequestedCores": 2.7, - "cpuUsedCores": 2.2, - "memoryRequestedGiB": 6, - "memoryUsedGiB": 4.8, - "podCount": 18, + "team": "platform", + "env": "prod", + "hourlyCost": 3.5, + "cpuRequestedCores": 2.7, + "cpuUsedCores": 2.2, + "memoryRequestedGiB": 6, + "memoryUsedGiB": 4.8, + "podCount": 18, }, }) }) @@ -152,7 +153,12 @@ func main() { }) log.Printf("mock agent listening on %s", *listen) - log.Fatal(http.ListenAndServe(*listen, mux)) + srv := &http.Server{ + Addr: *listen, + Handler: mux, + ReadHeaderTimeout: 5 * time.Second, + } + log.Fatal(srv.ListenAndServe()) } func writeJSON(w http.ResponseWriter, payload any) { diff --git a/dashboard b/dashboard deleted file mode 100755 index 8e02658..0000000 Binary files a/dashboard and /dev/null differ diff --git a/docs/TECHDEBT.md b/docs/TECHDEBT.md new file mode 100644 index 0000000..a2fbc10 --- /dev/null +++ b/docs/TECHDEBT.md @@ -0,0 +1,17 @@ +# Technical Debt & Roadmap + +## High Priority +- [ ] **High Cardinality Optimization**: Add a feature flag or logic to disable high-cardinality connection labels (e.g., specific src/dst IPs, ephemeral ports) or aggregate them (e.g., `external-traffic`) before ingestion into VictoriaMetrics to prevent index explosion. +- [ ] **Metric Type Definition**: Confirm definitively whether connection byte/cost metrics are cumulative **counters** or per-interval **deltas/gauges**. + - If Counters: Queries must use `increase()`. + - If Gauges: Queries must use `sum_over_time()` or `avg_over_time()`. + - *Action*: Standardize on Counters for consistency with Prometheus best practices. + +## medium Priority +- [ ] **Historical Topology API**: Implement a `query_range`-based endpoint for topology data. + - Current: Single-point `increase(@ end)` (Snapshot). + - Desired: Dynamic windowing for "Network usage over the last 7 days". + +## Future Considerations +- [ ] **Retention Policies**: Configure distinct retention periods for high-precision metrics (15s interval) vs. aggregated historical data. +- [ ] **Refactor Store Locking**: Evaluate moving from heavy `RWMutex` usage in `store.go` to a more concurrent pattern if contention increases with 100+ agents. diff --git a/docs/VIEWS.md b/docs/VIEWS.md new file mode 100644 index 0000000..c251854 --- /dev/null +++ b/docs/VIEWS.md @@ -0,0 +1,105 @@ +# Dashboard Views & UX Strategy + +## 1. Cost Allocation View ("The Financial Truth") +**Goal**: Provide clear visibility into who is spending what, resolving the "Shared Bill" conflict. + +### 🧠 The Pain Point +The #1 frustration in Kubernetes isn't technical—it's political. *“Who is responsible for this bill?”* +Organizations run multi-tenant clusters. When the cloud bill arrives, it's a massive, unassigned sum. FinOps teams need to accurately chargeback costs to specific teams (e.g., "Frontend" vs. "Data Science"). Without this clarity, the product provides no value to management. + +### 🚶 The User Journey +1. **Initial State**: The user sees a large aggregate number: **"projected Monthly Spend: $5,200"**. +2. **The Question**: Immediately asks, *"Why is it so high?"*. +3. **Discovery**: Scrolls down to see a breakdown by **Namespace** or **Label**. +4. **Insight**: Identifies that the `ai-training` namespace consumes **60%** of the budget. +5. **Action**: Clicks for details and shares a permalink report with that team. + +### 🎨 UX & Visuals +* **Main Visual**: **Sunburst Chart** or **Treemap**. These effectively visualize hierarchy (Cluster → Namespace → Workload). +* **Interaction**: Hovering over a slice dims the rest and highlights specific costs with a floating tooltip. +* **Differentiator**: **"Unit of Economics" Selector**. Allow users to toggle between: + * Currency ($) + * Carbon Footprint (CO₂e) + * % of Budget +* **Key Features**: + * **Label Mapping**: Group costs by custom business labels (e.g., `owner: jesus`, `team: platform`). + * **Idle Cost Allocation**: Option to distribute "Idle/Unused" cluster costs proportionally across tenants. + +--- + +## 2. Optimization View ("The Right-Sizing Engine") +**Goal**: Build confidence to reduce resource request limits without fearing stability issues. + +### 🧠 The Pain Point +**Fear**. Engineers set high requests (e.g., 4 CPU) to prevent crashes, even if the app uses only 0.2 CPU. They are terrified of OOMKilled errors. The tool must sell **confidence**, not just data. + +### 🚶 The User Journey +1. **Entry**: User clicks the **"Savings"** tab. +2. **Overview**: Sees a table sorted by **"Wasted Spend"**. +3. **Detail**: Sees their main deployment highlighted in red. +4. **Analysis**: Expands the row to see a line chart: + * **Grey Line**: Configured Limit (High). + * **Green Line**: Actual P99 Usage (Low). +5. **Recommendation**: System advises: *"You can safely reduce CPU to 0.5 with Low Risk."* +6. **Action**: Copies the suggested YAML snippet or clicks "Apply" (if GitOps integrated). + +### 🎨 UX & Visuals +* **Main Visual**: **Bullet Charts** (Overlapping progress bars). + * **Grey Background**: Request (Cost). + * **Green Bar**: Usage P99 (Real Needs). + * **Empty Space**: Waste. +* **Risk Semaphores**: Every recommendation must be tagged: + * 🟢 **Safe**: < 50% usage peaks over 30 days. + * 🟡 **Moderate**: Occasional spikes detected. +* **Action**: A slide-out **Drawer** showing the Diff (Before vs. After). + +--- + +## 3. Network Radar View ("The Invisible Cost") +**Goal**: Visualize detailed network flows and their associated costs (Egress vs. Cross-AZ). + +### 🧠 The Pain Point +This is where **eBPF** shines. Network transfer costs are notoriously opaque. AWS charges for: +1. **Internet Egress**. +2. **Cross-AZ Traffic**. (Common misconfiguration: Pod A in Zone 1 talking to Pod B in Zone 2). + +### 🚶 The User Journey +1. **Entry**: User selects **"Network Costs"**. +2. **Visualization**: Sees the topology map. +3. **Filter**: Toggles **"Show Money Flows"**. +4. **Insight**: The map dims; expensive links (Internet/Cross-AZ) glow **Neon Orange**. +5. **Discovery**: Clicks a thick line routing to "Internet" and discovers a log-shipper sending TBs to an external IP. + +### 🎨 UX & Visuals +* **Main Visual**: **Force-Directed Graph** (Topology). +* **Hierarchy**: + * **Cloud (Top)**: Nodes grouped by external provider (S3, Google API, Auth0). + * **Cluster (Bottom)**: Internal services. +* **Edges**: + * **Thickness**: Cost ($). + * **Color**: Traffic Type (🔴 Internet, 🟡 Cross-AZ, ⚪ Local). +* **Unique Feature**: **"NAT Hairpinning" Detection**. Flag traffic that exits and re-enters the cluster as a critical waste. + +--- + +## 4. Infrastructure Health View ("The Node Tetris") +**Goal**: Optimize cluster density and bin-packing. + +### 🧠 The Pain Point +**Bin Packing**. Paying for a whole Box (Node) to ship one Book (Pod). Users want to know if they can turn off nodes to save money but struggle with the "Tetris" of reorganizing pods. + +### 🚶 The User Journey +1. **Entry**: User navigates to **"Infrastructure"**. +2. **Observation**: Sees 10 nodes; 3 look visually empty. +3. **Suggestion**: System alerts: **"Consolidation Possible"**. +4. **Simulation**: *"Move pods from Node 9 & 10 to others to terminate 2 nodes and save $400/mo."* + +### 🎨 UX & Visuals +* **Main Visual**: **Waffle Charts** or **Rectangular Map** per node. + * **Big Rectangle**: Node. + * **Small Blocks**: Pods. +* **Color Coding**: + * ⬜ **White Space**: Real free capacity. + * 🌫 **Grey Blocks**: Reserved but unused capacity (Slack). + * 🟦 **Colored Blocks**: Actual Application Usage. +* **KPI**: **Cluster Density Score**. *"Your cluster is 45% dense. Goal: 75%."* diff --git a/go.mod b/go.mod index 57e30df..8c1562f 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,45 @@ module github.com/clustercost/clustercost-dashboard -go 1.21 +go 1.24.0 require ( github.com/go-chi/chi/v5 v5.2.3 github.com/go-chi/cors v1.2.1 gopkg.in/yaml.v3 v3.0.1 ) + +require ( + github.com/aws/aws-sdk-go-v2 v1.41.1 // indirect + github.com/aws/aws-sdk-go-v2/config v1.32.7 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.19.7 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 // indirect + github.com/aws/aws-sdk-go-v2/service/pricing v1.40.11 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 // indirect + github.com/aws/smithy-go v1.24.0 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/golang-jwt/jwt/v5 v5.3.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/ncruces/go-strftime v0.1.9 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + golang.org/x/crypto v0.46.0 // indirect + golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect + golang.org/x/net v0.47.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/text v0.32.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda // indirect + google.golang.org/grpc v1.78.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect + modernc.org/libc v1.66.10 // indirect + modernc.org/mathutil v1.7.1 // indirect + modernc.org/memory v1.11.0 // indirect + modernc.org/sqlite v1.43.0 // indirect +) diff --git a/go.sum b/go.sum index c2cdfc0..19e2723 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,79 @@ +github.com/aws/aws-sdk-go-v2 v1.41.1 h1:ABlyEARCDLN034NhxlRUSZr4l71mh+T5KAeGh6cerhU= +github.com/aws/aws-sdk-go-v2 v1.41.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0= +github.com/aws/aws-sdk-go-v2/config v1.32.7 h1:vxUyWGUwmkQ2g19n7JY/9YL8MfAIl7bTesIUykECXmY= +github.com/aws/aws-sdk-go-v2/config v1.32.7/go.mod h1:2/Qm5vKUU/r7Y+zUk/Ptt2MDAEKAfUtKc1+3U1Mo3oY= +github.com/aws/aws-sdk-go-v2/credentials v1.19.7 h1:tHK47VqqtJxOymRrNtUXN5SP/zUTvZKeLx4tH6PGQc8= +github.com/aws/aws-sdk-go-v2/credentials v1.19.7/go.mod h1:qOZk8sPDrxhf+4Wf4oT2urYJrYt3RejHSzgAquYeppw= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 h1:I0GyV8wiYrP8XpA70g1HBcQO1JlQxCMTW9npl5UbDHY= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17/go.mod h1:tyw7BOl5bBe/oqvoIeECFJjMdzXoa/dfVz3QQ5lgHGA= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 h1:xOLELNKGp2vsiteLsvLPwxC+mYmO6OZ8PYgiuPJzF8U= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17/go.mod h1:5M5CI3D12dNOtH3/mk6minaRwI2/37ifCURZISxA/IQ= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 h1:WWLqlh79iO48yLkj1v3ISRNiv+3KdQoZ6JWyfcsyQik= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17/go.mod h1:EhG22vHRrvF8oXSTYStZhJc1aUgKtnJe+aOiFEV90cM= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 h1:RuNSMoozM8oXlgLG/n6WLaFGoea7/CddrCfIiSA+xdY= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17/go.mod h1:F2xxQ9TZz5gDWsclCtPQscGpP0VUOc8RqgFM3vDENmU= +github.com/aws/aws-sdk-go-v2/service/pricing v1.40.11 h1:FBTRfFPRVua0y0izPAmUHOh2fAYtuz1ZkN/LUILN5Aw= +github.com/aws/aws-sdk-go-v2/service/pricing v1.40.11/go.mod h1:XFV2Em3Hn/2xirmmjy0JNg0AB3dpdNLGzwsnJkJycKs= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 h1:VrhDvQib/i0lxvr3zqlUwLwJP4fpmpyD9wYG1vfSu+Y= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.5/go.mod h1:k029+U8SY30/3/ras4G/Fnv/b88N4mAfliNn08Dem4M= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 h1:v6EiMvhEYBoHABfbGB4alOYmCIrcgyPPiBE1wZAEbqk= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.9/go.mod h1:yifAsgBxgJWn3ggx70A3urX2AN49Y5sJTD1UQFlfqBw= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 h1:gd84Omyu9JLriJVCbGApcLzVR3XtmC4ZDPcAI6Ftvds= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13/go.mod h1:sTGThjphYE4Ohw8vJiRStAcu3rbjtXRsdNB0TvZ5wwo= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 h1:5fFjR/ToSOzB2OQ/XqWpZBmNvmP/pJ1jOWYlFDJTjRQ= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.6/go.mod h1:qgFDZQSD/Kys7nJnVqYlWKnh0SSdMjAi0uSwON4wgYQ= +github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk= +github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE= github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= +github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= +github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= +github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o= +golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda h1:i/Q+bfisr7gq6feoJnS/DlpdwEL4ihp41fvRiM3Ork0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= +google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +modernc.org/libc v1.66.10 h1:yZkb3YeLx4oynyR+iUsXsybsX4Ubx7MQlSYEw4yj59A= +modernc.org/libc v1.66.10/go.mod h1:8vGSEwvoUoltr4dlywvHqjtAqHBaw0j1jI7iFBTAr2I= +modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= +modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= +modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= +modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= +modernc.org/sqlite v1.43.0 h1:8YqiFx3G1VhHTXO2Q00bl1Wz9KhS9Q5okwfp9Y97VnA= +modernc.org/sqlite v1.43.0/go.mod h1:+VkC6v3pLOAE0A0uVucQEcbVW0I5nHCeDaBf+DpsQT8= diff --git a/internal/agents/client.go b/internal/agents/client.go index 8471ea5..f4f0dbb 100644 --- a/internal/agents/client.go +++ b/internal/agents/client.go @@ -71,7 +71,7 @@ func (c *Client) get(ctx context.Context, baseURL, endpoint string, target any) if err != nil { return fmt.Errorf("call agent: %w", err) } - defer res.Body.Close() + defer func() { _ = res.Body.Close() }() if res.StatusCode < 200 || res.StatusCode >= 300 { return fmt.Errorf("agent responded with status %d", res.StatusCode) diff --git a/internal/api/handlers_agent_status.go b/internal/api/handlers_agent_status.go index 3ae3c78..1422fb7 100644 --- a/internal/api/handlers_agent_status.go +++ b/internal/api/handlers_agent_status.go @@ -3,14 +3,15 @@ package api import ( "net/http" - "github.com/clustercost/clustercost-dashboard/internal/store" + "github.com/clustercost/clustercost-dashboard/internal/vm" ) // AgentStatus returns the aggregated agent connection status. func (h *Handler) AgentStatus(w http.ResponseWriter, r *http.Request) { - status, err := h.store.AgentStatus() + ctx := vm.WithClusterID(r.Context(), clusterIDFromRequest(r)) + status, err := h.vm.AgentStatus(ctx) if err != nil { - if err == store.ErrNoData { + if err == vm.ErrNoData { writeError(w, http.StatusServiceUnavailable, "agent data not yet available") return } diff --git a/internal/api/handlers_agents.go b/internal/api/handlers_agents.go index 7523ac2..adb0580 100644 --- a/internal/api/handlers_agents.go +++ b/internal/api/handlers_agents.go @@ -1,8 +1,22 @@ package api -import "net/http" +import ( + "net/http" + + "github.com/clustercost/clustercost-dashboard/internal/vm" +) // Agents returns configured agents and their last known status. func (h *Handler) Agents(w http.ResponseWriter, r *http.Request) { - writeJSON(w, http.StatusOK, h.store.Agents()) + ctx := vm.WithClusterID(r.Context(), clusterIDFromRequest(r)) + agents, err := h.vm.Agents(ctx) + if err != nil { + if err == vm.ErrNoData { + writeError(w, http.StatusServiceUnavailable, "agent data not yet available") + return + } + writeError(w, http.StatusInternalServerError, err.Error()) + return + } + writeJSON(w, http.StatusOK, agents) } diff --git a/internal/api/handlers_auth.go b/internal/api/handlers_auth.go new file mode 100644 index 0000000..f04fe99 --- /dev/null +++ b/internal/api/handlers_auth.go @@ -0,0 +1,36 @@ +package api + +import ( + "encoding/json" + "net/http" + + "github.com/clustercost/clustercost-dashboard/internal/auth" +) + +type loginRequest struct { + Username string `json:"username"` + Password string `json:"password"` +} + +type loginResponse struct { + Token string `json:"token"` +} + +// Login handles user authentication and returns a JWT. +func (h *Handler) Login(w http.ResponseWriter, r *http.Request) { + var req loginRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + writeError(w, http.StatusBadRequest, "invalid request body") + return + } + + token, err := auth.Login(h.db, req.Username, req.Password) + if err != nil { + // Log error internally if needed, but return generic error to user + // In a real app, distinguish between internal error and invalid creds safely + writeError(w, http.StatusUnauthorized, "invalid credentials") + return + } + + writeJSON(w, http.StatusOK, loginResponse{Token: token}) +} diff --git a/internal/api/handlers_finops.go b/internal/api/handlers_finops.go new file mode 100644 index 0000000..50f1dec --- /dev/null +++ b/internal/api/handlers_finops.go @@ -0,0 +1,38 @@ +package api + +import ( + "net/http" + "sort" + + "github.com/clustercost/clustercost-dashboard/internal/finops" +) + +// EfficiencyReport generates the FinOps efficiency analysis. +func (h *Handler) EfficiencyReport(w http.ResponseWriter, r *http.Request) { + pods := h.store.GetAllPods() + + var reports []finops.EfficiencyReport + ctx := r.Context() + + for _, pc := range pods { + report, err := h.finops.CalculatePodEfficiency(ctx, pc.Pod, pc.ClusterID, pc.Region, pc.AZ, pc.InstanceType) + if err != nil { + // Log error but continue? Or skip? + // For now continue and maybe return partial results? + continue + } + if report != nil { + reports = append(reports, *report) + } + } + + // Sort by Potential Savings Descending (highest waste first) + sort.Slice(reports, func(i, j int) bool { + return reports[i].PotentialSavingsMo > reports[j].PotentialSavingsMo + }) + + writeJSON(w, http.StatusOK, map[string]interface{}{ + "items": reports, + "count": len(reports), + }) +} diff --git a/internal/api/handlers_health.go b/internal/api/handlers_health.go index 3f5f9b1..4891df4 100644 --- a/internal/api/handlers_health.go +++ b/internal/api/handlers_health.go @@ -4,25 +4,25 @@ import ( "net/http" "time" - "github.com/clustercost/clustercost-dashboard/internal/store" + "github.com/clustercost/clustercost-dashboard/internal/vm" ) // Health returns a simple readiness payload. func (h *Handler) Health(w http.ResponseWriter, r *http.Request) { - meta, err := h.store.ClusterMetadata() + ctx := vm.WithClusterID(r.Context(), clusterIDFromRequest(r)) + meta, err := h.vm.ClusterMetadata(ctx) timestamp := meta.Timestamp status := "ok" switch err { case nil: - agents := h.store.Agents() - for _, agent := range agents { - if agent.Status != "healthy" { - status = "degraded" - break - } + agentStatus, statusErr := h.vm.AgentStatus(ctx) + if statusErr != nil { + status = "degraded" + } else if agentStatus.Status != "connected" { + status = "degraded" } - case store.ErrNoData: + case vm.ErrNoData: status = "initializing" if timestamp.IsZero() { timestamp = time.Now().UTC() diff --git a/internal/api/handlers_health_test.go b/internal/api/handlers_health_test.go index a3a9697..f5cf9b9 100644 --- a/internal/api/handlers_health_test.go +++ b/internal/api/handlers_health_test.go @@ -1,40 +1,67 @@ package api import ( + "context" "encoding/json" "net/http" "net/http/httptest" "testing" "time" - "github.com/clustercost/clustercost-dashboard/internal/agents" - "github.com/clustercost/clustercost-dashboard/internal/config" "github.com/clustercost/clustercost-dashboard/internal/store" + "github.com/clustercost/clustercost-dashboard/internal/vm" ) -func newTestHandler() *Handler { - cfgs := []config.AgentConfig{ - {Name: "agent", BaseURL: "http://example.com", Type: "k8s"}, - } - s := store.New(cfgs, "v1.0.0") - return &Handler{store: s} +type fakeMetricsProvider struct { + meta store.ClusterMetadata + status store.AgentStatusPayload +} + +func (f *fakeMetricsProvider) Overview(context.Context, int) (store.OverviewPayload, error) { + return store.OverviewPayload{}, vm.ErrNoData +} +func (f *fakeMetricsProvider) NamespaceList(context.Context, store.NamespaceFilter) (store.NamespaceListResponse, error) { + return store.NamespaceListResponse{}, vm.ErrNoData +} +func (f *fakeMetricsProvider) NamespaceDetail(context.Context, string) (store.NamespaceSummary, error) { + return store.NamespaceSummary{}, vm.ErrNoData +} +func (f *fakeMetricsProvider) NodeList(context.Context, store.NodeFilter) (store.NodeListResponse, error) { + return store.NodeListResponse{}, vm.ErrNoData +} +func (f *fakeMetricsProvider) NodeDetail(context.Context, string) (store.NodeSummary, error) { + return store.NodeSummary{}, vm.ErrNoData +} +func (f *fakeMetricsProvider) Resources(context.Context) (store.ResourcesPayload, error) { + return store.ResourcesPayload{}, vm.ErrNoData +} +func (f *fakeMetricsProvider) AgentStatus(context.Context) (store.AgentStatusPayload, error) { + return f.status, nil +} +func (f *fakeMetricsProvider) Agents(context.Context) ([]store.AgentInfo, error) { + return nil, vm.ErrNoData +} +func (f *fakeMetricsProvider) ClusterMetadata(context.Context) (store.ClusterMetadata, error) { + return f.meta, nil +} +func (f *fakeMetricsProvider) NetworkTopology(context.Context, store.NetworkTopologyOptions) ([]store.NetworkEdge, error) { + return nil, vm.ErrNoData +} + +func newTestHandler(meta store.ClusterMetadata, status store.AgentStatusPayload) *Handler { + return &Handler{vm: &fakeMetricsProvider{meta: meta, status: status}} } func TestHealthHandlerReturnsClusterMetadata(t *testing.T) { - h := newTestHandler() now := time.Now().UTC() - h.store.Update("agent", store.AgentSnapshot{ - LastScrape: now, - Health: &agents.HealthResponse{ - Status: "healthy", - ClusterID: "cluster-123", - ClusterName: "Test Cluster", - ClusterType: "k8s", - Region: "us-east-2", - Version: "dev", - Timestamp: now, - }, - }) + h := newTestHandler(store.ClusterMetadata{ + ID: "cluster-123", + Name: "Test Cluster", + Type: "k8s", + Region: "us-east-2", + Version: "dev", + Timestamp: now, + }, store.AgentStatusPayload{Status: "connected"}) req := httptest.NewRequest(http.MethodGet, "/api/health", nil) rec := httptest.NewRecorder() diff --git a/internal/api/handlers_namespaces.go b/internal/api/handlers_namespaces.go index 6ffd8b4..3ada99b 100644 --- a/internal/api/handlers_namespaces.go +++ b/internal/api/handlers_namespaces.go @@ -6,6 +6,7 @@ import ( "github.com/go-chi/chi/v5" "github.com/clustercost/clustercost-dashboard/internal/store" + "github.com/clustercost/clustercost-dashboard/internal/vm" ) const ( @@ -16,6 +17,7 @@ const ( // Namespaces exposes namespace level cost metrics with filtering and pagination. func (h *Handler) Namespaces(w http.ResponseWriter, r *http.Request) { q := r.URL.Query() + ctx := vm.WithClusterID(r.Context(), clusterIDFromRequest(r)) filter := store.NamespaceFilter{ Environment: q.Get("environment"), @@ -24,9 +26,9 @@ func (h *Handler) Namespaces(w http.ResponseWriter, r *http.Request) { Offset: parseOffset(q.Get("offset")), } - resp, err := h.store.NamespaceList(filter) + resp, err := h.vm.NamespaceList(ctx, filter) if err != nil { - if err == store.ErrNoData { + if err == vm.ErrNoData { writeError(w, http.StatusServiceUnavailable, "data not yet available") return } @@ -45,9 +47,10 @@ func (h *Handler) NamespaceDetail(w http.ResponseWriter, r *http.Request) { return } - ns, err := h.store.NamespaceDetail(name) + ctx := vm.WithClusterID(r.Context(), clusterIDFromRequest(r)) + ns, err := h.vm.NamespaceDetail(ctx, name) if err != nil { - if err == store.ErrNoData { + if err == vm.ErrNoData { writeError(w, http.StatusNotFound, "namespace not found") return } diff --git a/internal/api/handlers_network.go b/internal/api/handlers_network.go new file mode 100644 index 0000000..3a43b88 --- /dev/null +++ b/internal/api/handlers_network.go @@ -0,0 +1,87 @@ +package api + +import ( + "errors" + "net/http" + "time" + + "github.com/clustercost/clustercost-dashboard/internal/store" + "github.com/clustercost/clustercost-dashboard/internal/vm" +) + +type NetworkTopologyResponse struct { + ClusterID string `json:"clusterId"` + Namespace string `json:"namespace,omitempty"` + Start time.Time `json:"start"` + End time.Time `json:"end"` + Edges []store.NetworkEdge `json:"edges"` + TotalEdges int `json:"totalEdges"` + RequestedLimit int `json:"requestedLimit"` + Timestamp time.Time `json:"timestamp"` +} + +func (h *Handler) NetworkTopology(w http.ResponseWriter, r *http.Request) { + clusterID := clusterIDFromRequest(r) + namespaces := parseNamespaceList(r.URL.Query()["namespace"]) + limit := parseLimit(r.URL.Query().Get("limit"), 2000, 10000) + minCostUSD := parseFloat(r.URL.Query().Get("minCost"), 0) + minBytes := parseInt64(r.URL.Query().Get("minBytes"), 0) + minConnections := parseInt64(r.URL.Query().Get("minConnections"), 0) + + start, end, err := parseTimeRange(r, 1*time.Hour) + if err != nil { + writeError(w, http.StatusBadRequest, "invalid time range") + return + } + if start.IsZero() || end.IsZero() { + writeError(w, http.StatusBadRequest, "time range required") + return + } + + edges, err := h.vm.NetworkTopology(r.Context(), store.NetworkTopologyOptions{ + ClusterID: clusterID, + Namespaces: namespaces, + Start: start, + End: end, + Limit: limit, + MinCostUSD: minCostUSD, + MinBytes: minBytes, + MinConnections: minConnections, + }) + if err != nil { + if errors.Is(err, vm.ErrNoData) { + namespace := "" + if len(namespaces) == 1 { + namespace = namespaces[0] + } + writeJSON(w, http.StatusOK, NetworkTopologyResponse{ + ClusterID: clusterID, + Namespace: namespace, + Start: start, + End: end, + Edges: []store.NetworkEdge{}, + TotalEdges: 0, + RequestedLimit: limit, + Timestamp: time.Now().UTC(), + }) + return + } + writeError(w, http.StatusInternalServerError, "failed to query network topology") + return + } + + namespace := "" + if len(namespaces) == 1 { + namespace = namespaces[0] + } + writeJSON(w, http.StatusOK, NetworkTopologyResponse{ + ClusterID: clusterID, + Namespace: namespace, + Start: start, + End: end, + Edges: edges, + TotalEdges: len(edges), + RequestedLimit: limit, + Timestamp: time.Now().UTC(), + }) +} diff --git a/internal/api/handlers_nodes.go b/internal/api/handlers_nodes.go index 69dfa14..fcb30ef 100644 --- a/internal/api/handlers_nodes.go +++ b/internal/api/handlers_nodes.go @@ -6,6 +6,7 @@ import ( "github.com/go-chi/chi/v5" "github.com/clustercost/clustercost-dashboard/internal/store" + "github.com/clustercost/clustercost-dashboard/internal/vm" ) const ( @@ -16,15 +17,16 @@ const ( // Nodes returns node utilization information. func (h *Handler) Nodes(w http.ResponseWriter, r *http.Request) { q := r.URL.Query() + ctx := vm.WithClusterID(r.Context(), clusterIDFromRequest(r)) filter := store.NodeFilter{ Search: q.Get("search"), Limit: parseLimit(q.Get("limit"), defaultNodeLimit, maxNodeLimit), Offset: parseOffset(q.Get("offset")), } - resp, err := h.store.NodeList(filter) + resp, err := h.vm.NodeList(ctx, filter) if err != nil { - if err == store.ErrNoData { + if err == vm.ErrNoData { writeError(w, http.StatusServiceUnavailable, "data not yet available") return } @@ -43,9 +45,10 @@ func (h *Handler) NodeDetail(w http.ResponseWriter, r *http.Request) { return } - node, err := h.store.NodeDetail(name) + ctx := vm.WithClusterID(r.Context(), clusterIDFromRequest(r)) + node, err := h.vm.NodeDetail(ctx, name) if err != nil { - if err == store.ErrNoData { + if err == vm.ErrNoData { writeError(w, http.StatusNotFound, "node not found") return } diff --git a/internal/api/handlers_overview.go b/internal/api/handlers_overview.go index 768e192..247a819 100644 --- a/internal/api/handlers_overview.go +++ b/internal/api/handlers_overview.go @@ -3,16 +3,17 @@ package api import ( "net/http" - "github.com/clustercost/clustercost-dashboard/internal/store" + "github.com/clustercost/clustercost-dashboard/internal/vm" ) // Overview serves the aggregated overview payload. func (h *Handler) Overview(w http.ResponseWriter, r *http.Request) { limit := parseLimit(r.URL.Query().Get("limitTopNamespaces"), 5, 20) - overview, err := h.store.Overview(limit) + ctx := vm.WithClusterID(r.Context(), clusterIDFromRequest(r)) + overview, err := h.vm.Overview(ctx, limit) if err != nil { - if err == store.ErrNoData { + if err == vm.ErrNoData { writeError(w, http.StatusServiceUnavailable, "data not yet available") return } diff --git a/internal/api/handlers_resources.go b/internal/api/handlers_resources.go index 53a0f4a..5bef26b 100644 --- a/internal/api/handlers_resources.go +++ b/internal/api/handlers_resources.go @@ -3,14 +3,15 @@ package api import ( "net/http" - "github.com/clustercost/clustercost-dashboard/internal/store" + "github.com/clustercost/clustercost-dashboard/internal/vm" ) // Resources exposes cluster-wide efficiency metrics. func (h *Handler) Resources(w http.ResponseWriter, r *http.Request) { - resp, err := h.store.Resources() + ctx := vm.WithClusterID(r.Context(), clusterIDFromRequest(r)) + resp, err := h.vm.Resources(ctx) if err != nil { - if err == store.ErrNoData { + if err == vm.ErrNoData { writeError(w, http.StatusServiceUnavailable, "data not yet available") return } diff --git a/internal/api/request_params.go b/internal/api/request_params.go index 9c84e2a..147b9d4 100644 --- a/internal/api/request_params.go +++ b/internal/api/request_params.go @@ -1,6 +1,11 @@ package api -import "strconv" +import ( + "net/http" + "strconv" + "strings" + "time" +) func parseLimit(raw string, fallback, max int) int { limit := fallback @@ -25,3 +30,105 @@ func parseOffset(raw string) int { } return parsed } + +func parseFloat(raw string, fallback float64) float64 { + if raw == "" { + return fallback + } + parsed, err := strconv.ParseFloat(raw, 64) + if err != nil || parsed < 0 { + return fallback + } + return parsed +} + +func parseInt64(raw string, fallback int64) int64 { + if raw == "" { + return fallback + } + parsed, err := strconv.ParseInt(raw, 10, 64) + if err != nil || parsed < 0 { + return fallback + } + return parsed +} + +func parseNamespaceList(raw []string) []string { + if len(raw) == 0 { + return nil + } + seen := make(map[string]struct{}, len(raw)) + list := make([]string, 0, len(raw)) + for _, entry := range raw { + if entry == "" { + continue + } + for _, value := range strings.Split(entry, ",") { + trimmed := strings.TrimSpace(value) + if trimmed == "" { + continue + } + if _, ok := seen[trimmed]; ok { + continue + } + seen[trimmed] = struct{}{} + list = append(list, trimmed) + } + } + return list +} + +func clusterIDFromRequest(r *http.Request) string { + if r == nil { + return "" + } + return r.URL.Query().Get("clusterId") +} + +func parseTimeRange(r *http.Request, fallback time.Duration) (time.Time, time.Time, error) { + if r == nil { + return time.Time{}, time.Time{}, nil + } + q := r.URL.Query() + + if lookback := q.Get("lookback"); lookback != "" { + d, err := time.ParseDuration(lookback) + if err != nil { + return time.Time{}, time.Time{}, err + } + end := time.Now().UTC() + return end.Add(-d), end, nil + } + + start, err := parseTimestamp(q.Get("start")) + if err != nil { + return time.Time{}, time.Time{}, err + } + end, err := parseTimestamp(q.Get("end")) + if err != nil { + return time.Time{}, time.Time{}, err + } + + if start.IsZero() || end.IsZero() { + if fallback <= 0 { + return time.Time{}, time.Time{}, nil + } + now := time.Now().UTC() + return now.Add(-fallback), now, nil + } + return start, end, nil +} + +func parseTimestamp(raw string) (time.Time, error) { + if raw == "" { + return time.Time{}, nil + } + if parsed, err := strconv.ParseInt(raw, 10, 64); err == nil { + return time.Unix(parsed, 0).UTC(), nil + } + parsed, err := time.Parse(time.RFC3339, raw) + if err != nil { + return time.Time{}, err + } + return parsed.UTC(), nil +} diff --git a/internal/api/router.go b/internal/api/router.go index a29de32..28d403a 100644 --- a/internal/api/router.go +++ b/internal/api/router.go @@ -1,6 +1,7 @@ package api import ( + "context" "encoding/json" "net/http" @@ -8,18 +9,43 @@ import ( "github.com/go-chi/chi/v5/middleware" "github.com/go-chi/cors" + "github.com/clustercost/clustercost-dashboard/internal/auth" + "github.com/clustercost/clustercost-dashboard/internal/db" + "github.com/clustercost/clustercost-dashboard/internal/finops" "github.com/clustercost/clustercost-dashboard/internal/static" "github.com/clustercost/clustercost-dashboard/internal/store" ) -// Handler wires HTTP requests to the in-memory store. +// MetricsProvider defines the data backend used by API handlers. +type MetricsProvider interface { + Overview(ctx context.Context, limit int) (store.OverviewPayload, error) + NamespaceList(ctx context.Context, filter store.NamespaceFilter) (store.NamespaceListResponse, error) + NamespaceDetail(ctx context.Context, name string) (store.NamespaceSummary, error) + NodeList(ctx context.Context, filter store.NodeFilter) (store.NodeListResponse, error) + NodeDetail(ctx context.Context, name string) (store.NodeSummary, error) + Resources(ctx context.Context) (store.ResourcesPayload, error) + AgentStatus(ctx context.Context) (store.AgentStatusPayload, error) + Agents(ctx context.Context) ([]store.AgentInfo, error) + ClusterMetadata(ctx context.Context) (store.ClusterMetadata, error) + NetworkTopology(ctx context.Context, opts store.NetworkTopologyOptions) ([]store.NetworkEdge, error) +} + +// Handler wires HTTP requests to the VictoriaMetrics client. type Handler struct { - store *store.Store + vm MetricsProvider + db *db.Store + store *store.Store + finops *finops.Engine } // NewRouter builds the HTTP router serving both JSON APIs and static assets. -func NewRouter(s *store.Store) http.Handler { - h := &Handler{store: s} +func NewRouter(vmClient MetricsProvider, db *db.Store, st *store.Store, finopsEngine *finops.Engine) http.Handler { + h := &Handler{ + vm: vmClient, + db: db, + store: st, + finops: finopsEngine, + } r := chi.NewRouter() r.Use(middleware.RequestID) @@ -27,24 +53,39 @@ func NewRouter(s *store.Store) http.Handler { r.Use(middleware.Recoverer) r.Use(cors.Handler(cors.Options{ AllowedOrigins: []string{"*"}, - AllowedMethods: []string{http.MethodGet, http.MethodOptions}, + AllowedMethods: []string{http.MethodGet, http.MethodPost, http.MethodOptions}, // Added POST for Login AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-Requested-With"}, AllowCredentials: false, MaxAge: 300, })) r.Route("/api", func(api chi.Router) { + // Public routes api.Get("/health", h.Health) - api.Route("/cost", func(cost chi.Router) { - cost.Get("/overview", h.Overview) - cost.Get("/namespaces", h.Namespaces) - cost.Get("/namespaces/{name}", h.NamespaceDetail) - cost.Get("/nodes", h.Nodes) - cost.Get("/nodes/{name}", h.NodeDetail) - cost.Get("/resources", h.Resources) + api.Post("/login", h.Login) + + // Protected routes + api.Group(func(protected chi.Router) { + protected.Use(auth.Middleware) + protected.Route("/cost", func(cost chi.Router) { + cost.Get("/overview", h.Overview) + cost.Get("/namespaces", h.Namespaces) + cost.Get("/namespaces/{name}", h.NamespaceDetail) + cost.Get("/nodes", h.Nodes) + cost.Get("/nodes/{name}", h.NodeDetail) + cost.Get("/resources", h.Resources) + }) + protected.Get("/agent", h.AgentStatus) + protected.Get("/agents", h.Agents) + + protected.Route("/finops", func(finops chi.Router) { + finops.Get("/efficiency", h.EfficiencyReport) + }) + + protected.Route("/network", func(network chi.Router) { + network.Get("/topology", h.NetworkTopology) + }) }) - api.Get("/agent", h.AgentStatus) - api.Get("/agents", h.Agents) }) r.Handle("/*", static.Handler()) diff --git a/internal/auth/auth.go b/internal/auth/auth.go new file mode 100644 index 0000000..0d3aa07 --- /dev/null +++ b/internal/auth/auth.go @@ -0,0 +1,78 @@ +package auth + +import ( + "context" + "fmt" + "net/http" + "strings" + "time" + + "github.com/golang-jwt/jwt/v5" + "golang.org/x/crypto/bcrypt" + + "github.com/clustercost/clustercost-dashboard/internal/db" +) + +var jwtSecret = []byte("default-secret-change-me") + +func SetSecret(secret string) { + if secret != "" { + jwtSecret = []byte(secret) + } +} + +type Claims struct { + Username string `json:"username"` + jwt.RegisteredClaims +} + +func Login(db *db.Store, username, password string) (string, error) { + hash, err := db.GetUserPasswordHash(username) + if err != nil { + return "", err + } + if hash == "" { + return "", fmt.Errorf("invalid credentials") + } + + if err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)); err != nil { + return "", fmt.Errorf("invalid credentials") + } + + claims := &Claims{ + Username: username, + RegisteredClaims: jwt.RegisteredClaims{ + ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), + }, + } + + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + return token.SignedString(jwtSecret) +} + +func Middleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + authHeader := r.Header.Get("Authorization") + if authHeader == "" { + http.Error(w, "authorization header required", http.StatusUnauthorized) + return + } + + tokenString := strings.TrimPrefix(authHeader, "Bearer ") + claims := &Claims{} + + token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) { + return jwtSecret, nil + }) + + if err != nil || !token.Valid { + http.Error(w, "invalid token", http.StatusUnauthorized) + return + } + + type contextKey string + const userKey contextKey = "user" + ctx := context.WithValue(r.Context(), userKey, claims.Username) + next.ServeHTTP(w, r.WithContext(ctx)) + }) +} diff --git a/internal/config/config.go b/internal/config/config.go index da1cfe6..7fb616a 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1,10 +1,10 @@ package config import ( - "errors" "fmt" - "io/ioutil" "os" + "path/filepath" + "strconv" "strings" "time" @@ -16,22 +16,53 @@ type AgentConfig struct { Name string `yaml:"name"` BaseURL string `yaml:"baseUrl"` Type string `yaml:"type"` + Token string `yaml:"token"` + Region string `yaml:"clusterRegion"` } // Config contains runtime settings for the dashboard backend. type Config struct { - ListenAddr string `yaml:"listenAddr"` - PollInterval time.Duration `yaml:"pollInterval"` - Agents []AgentConfig `yaml:"agents"` - RecommendedAgentVersion string `yaml:"recommendedAgentVersion"` + ListenAddr string `yaml:"listenAddr"` + GrpcAddr string `yaml:"grpcAddr"` + DefaultAgentToken string `yaml:"defaultAgentToken"` + PollInterval time.Duration `yaml:"pollInterval"` + DisableHTTPPolling bool `yaml:"disableHttpPolling"` + Agents []AgentConfig `yaml:"agents"` + RecommendedAgentVersion string `yaml:"recommendedAgentVersion"` + VictoriaMetricsURL string `yaml:"victoriaMetricsUrl"` + VictoriaMetricsIngestPath string `yaml:"victoriaMetricsIngestPath"` + VictoriaMetricsToken string `yaml:"victoriaMetricsToken"` + VictoriaMetricsUsername string `yaml:"victoriaMetricsUsername"` + VictoriaMetricsPassword string `yaml:"victoriaMetricsPassword"` + VictoriaMetricsTimeout time.Duration `yaml:"victoriaMetricsTimeout"` + VictoriaMetricsBatchBytes int `yaml:"victoriaMetricsBatchBytes"` + VictoriaMetricsFlushInterval time.Duration `yaml:"victoriaMetricsFlushInterval"` + VictoriaMetricsWorkers int `yaml:"victoriaMetricsWorkers"` + VictoriaMetricsQueueSize int `yaml:"victoriaMetricsQueueSize"` + VictoriaMetricsGzip bool `yaml:"victoriaMetricsGzip"` + VictoriaMetricsLookback time.Duration `yaml:"victoriaMetricsLookback"` + StoragePath string `yaml:"storagePath"` + JWTSecret string `yaml:"jwtSecret"` + LogLevel string `yaml:"logLevel"` } // Default returns the default configuration used when no other information is provided. func Default() Config { return Config{ - ListenAddr: ":9090", - PollInterval: 30 * time.Second, - Agents: []AgentConfig{}, + ListenAddr: ":9090", + GrpcAddr: ":9091", + PollInterval: 30 * time.Second, + Agents: []AgentConfig{}, + VictoriaMetricsIngestPath: "/api/v1/import/prometheus", + VictoriaMetricsTimeout: 5 * time.Second, + VictoriaMetricsBatchBytes: 2 << 20, + VictoriaMetricsFlushInterval: 2 * time.Second, + VictoriaMetricsWorkers: 0, + VictoriaMetricsQueueSize: 10000, + VictoriaMetricsGzip: true, + VictoriaMetricsLookback: 24 * time.Hour, + StoragePath: "data/clustercost.db", + JWTSecret: "clustercost-secret", } } @@ -43,12 +74,31 @@ func Load() (Config, error) { cfg.ListenAddr = listen } + if grpcAddr := os.Getenv("GRPC_ADDR"); grpcAddr != "" { + cfg.GrpcAddr = grpcAddr + } + + if defaultToken := os.Getenv("DEFAULT_AGENT_TOKEN"); defaultToken != "" { + cfg.DefaultAgentToken = defaultToken + } + if interval := os.Getenv("POLL_INTERVAL"); interval != "" { d, err := time.ParseDuration(interval) if err != nil { return Config{}, fmt.Errorf("invalid POLL_INTERVAL: %w", err) } cfg.PollInterval = d + if d == 0 { + cfg.DisableHTTPPolling = true + } + } + + if disable := os.Getenv("DISABLE_HTTP_POLLING"); disable != "" { + parsed, err := strconv.ParseBool(disable) + if err != nil { + return Config{}, fmt.Errorf("invalid DISABLE_HTTP_POLLING: %w", err) + } + cfg.DisableHTTPPolling = parsed } if file := os.Getenv("CONFIG_FILE"); file != "" { @@ -79,15 +129,102 @@ func Load() (Config, error) { cfg.RecommendedAgentVersion = expected } - if len(cfg.Agents) == 0 { - return Config{}, errors.New("no agents configured - set CONFIG_FILE or AGENT_URLS") + if vmURL := os.Getenv("VICTORIA_METRICS_URL"); vmURL != "" { + cfg.VictoriaMetricsURL = vmURL + } + + if ingestPath := os.Getenv("VICTORIA_METRICS_INGEST_PATH"); ingestPath != "" { + cfg.VictoriaMetricsIngestPath = ingestPath + } + + if token := os.Getenv("VICTORIA_METRICS_TOKEN"); token != "" { + cfg.VictoriaMetricsToken = token + } + + if user := os.Getenv("VICTORIA_METRICS_USERNAME"); user != "" { + cfg.VictoriaMetricsUsername = user + } + + if pass := os.Getenv("VICTORIA_METRICS_PASSWORD"); pass != "" { + cfg.VictoriaMetricsPassword = pass + } + + if timeout := os.Getenv("VICTORIA_METRICS_TIMEOUT"); timeout != "" { + d, err := time.ParseDuration(timeout) + if err != nil { + return Config{}, fmt.Errorf("invalid VICTORIA_METRICS_TIMEOUT: %w", err) + } + cfg.VictoriaMetricsTimeout = d + } + + if raw := os.Getenv("VICTORIA_METRICS_BATCH_BYTES"); raw != "" { + parsed, err := strconv.Atoi(raw) + if err != nil { + return Config{}, fmt.Errorf("invalid VICTORIA_METRICS_BATCH_BYTES: %w", err) + } + cfg.VictoriaMetricsBatchBytes = parsed + } + + if raw := os.Getenv("VICTORIA_METRICS_FLUSH_INTERVAL"); raw != "" { + d, err := time.ParseDuration(raw) + if err != nil { + return Config{}, fmt.Errorf("invalid VICTORIA_METRICS_FLUSH_INTERVAL: %w", err) + } + cfg.VictoriaMetricsFlushInterval = d + } + + if raw := os.Getenv("VICTORIA_METRICS_WORKERS"); raw != "" { + parsed, err := strconv.Atoi(raw) + if err != nil { + return Config{}, fmt.Errorf("invalid VICTORIA_METRICS_WORKERS: %w", err) + } + cfg.VictoriaMetricsWorkers = parsed + } + + if raw := os.Getenv("VICTORIA_METRICS_QUEUE_SIZE"); raw != "" { + parsed, err := strconv.Atoi(raw) + if err != nil { + return Config{}, fmt.Errorf("invalid VICTORIA_METRICS_QUEUE_SIZE: %w", err) + } + cfg.VictoriaMetricsQueueSize = parsed + } + + if raw := os.Getenv("VICTORIA_METRICS_GZIP"); raw != "" { + parsed, err := strconv.ParseBool(raw) + if err != nil { + return Config{}, fmt.Errorf("invalid VICTORIA_METRICS_GZIP: %w", err) + } + cfg.VictoriaMetricsGzip = parsed + } + + if raw := os.Getenv("VICTORIA_METRICS_LOOKBACK"); raw != "" { + d, err := time.ParseDuration(raw) + if err != nil { + return Config{}, fmt.Errorf("invalid VICTORIA_METRICS_LOOKBACK: %w", err) + } + cfg.VictoriaMetricsLookback = d + } + + if storage := os.Getenv("STORAGE_PATH"); storage != "" { + cfg.StoragePath = storage + } + + if secret := os.Getenv("JWT_SECRET"); secret != "" { + cfg.JWTSecret = secret + } + + if logLevel := os.Getenv("LOG_LEVEL"); logLevel != "" { + cfg.LogLevel = strings.ToLower(logLevel) + } + if cfg.LogLevel == "" { + cfg.LogLevel = "info" } return cfg, nil } func fromFile(path string) (Config, error) { - b, err := ioutil.ReadFile(path) + b, err := os.ReadFile(filepath.Clean(path)) // #nosec G304 -- loading config from user-supplied path is intended if err != nil { return Config{}, fmt.Errorf("read config file: %w", err) } @@ -100,7 +237,7 @@ func fromFile(path string) (Config, error) { if cfg.ListenAddr == "" { cfg.ListenAddr = ":9090" } - if cfg.PollInterval == 0 { + if cfg.PollInterval == 0 && !cfg.DisableHTTPPolling { cfg.PollInterval = 30 * time.Second } @@ -111,9 +248,18 @@ func merge(dst *Config, src Config) { if src.ListenAddr != "" { dst.ListenAddr = src.ListenAddr } + if src.GrpcAddr != "" { + dst.GrpcAddr = src.GrpcAddr + } + if src.DefaultAgentToken != "" { + dst.DefaultAgentToken = src.DefaultAgentToken + } if src.PollInterval != 0 { dst.PollInterval = src.PollInterval } + if src.DisableHTTPPolling { + dst.DisableHTTPPolling = true + } if len(src.Agents) > 0 { dst.Agents = src.Agents @@ -121,4 +267,48 @@ func merge(dst *Config, src Config) { if src.RecommendedAgentVersion != "" { dst.RecommendedAgentVersion = src.RecommendedAgentVersion } + + if src.VictoriaMetricsURL != "" { + dst.VictoriaMetricsURL = src.VictoriaMetricsURL + } + if src.VictoriaMetricsIngestPath != "" { + dst.VictoriaMetricsIngestPath = src.VictoriaMetricsIngestPath + } + if src.VictoriaMetricsToken != "" { + dst.VictoriaMetricsToken = src.VictoriaMetricsToken + } + if src.VictoriaMetricsUsername != "" { + dst.VictoriaMetricsUsername = src.VictoriaMetricsUsername + } + if src.VictoriaMetricsPassword != "" { + dst.VictoriaMetricsPassword = src.VictoriaMetricsPassword + } + if src.VictoriaMetricsTimeout != 0 { + dst.VictoriaMetricsTimeout = src.VictoriaMetricsTimeout + } + if src.VictoriaMetricsBatchBytes != 0 { + dst.VictoriaMetricsBatchBytes = src.VictoriaMetricsBatchBytes + } + if src.VictoriaMetricsFlushInterval != 0 { + dst.VictoriaMetricsFlushInterval = src.VictoriaMetricsFlushInterval + } + if src.VictoriaMetricsWorkers != 0 { + dst.VictoriaMetricsWorkers = src.VictoriaMetricsWorkers + } + if src.VictoriaMetricsQueueSize != 0 { + dst.VictoriaMetricsQueueSize = src.VictoriaMetricsQueueSize + } + if src.VictoriaMetricsGzip { + dst.VictoriaMetricsGzip = true + } + // ... (in merge function) + if src.VictoriaMetricsLookback != 0 { + dst.VictoriaMetricsLookback = src.VictoriaMetricsLookback + } + if src.StoragePath != "" { + dst.StoragePath = src.StoragePath + } + if src.JWTSecret != "" { + dst.JWTSecret = src.JWTSecret + } } diff --git a/internal/db/db.go b/internal/db/db.go new file mode 100644 index 0000000..e408706 --- /dev/null +++ b/internal/db/db.go @@ -0,0 +1,99 @@ +package db + +import ( + "database/sql" + "fmt" + "log" + "os" + "path/filepath" + + "golang.org/x/crypto/bcrypt" + _ "modernc.org/sqlite" // Register SQLite driver +) + +type Store struct { + db *sql.DB +} + +func New(storagePath string) (*Store, error) { + if err := os.MkdirAll(filepath.Dir(storagePath), 0750); err != nil { + return nil, fmt.Errorf("create db directory: %w", err) + } + + db, err := sql.Open("sqlite", storagePath) + if err != nil { + return nil, fmt.Errorf("open sqlite db: %w", err) + } + + if err := db.Ping(); err != nil { + return nil, fmt.Errorf("ping db: %w", err) + } + + s := &Store{db: db} + if err := s.migrate(); err != nil { + return nil, fmt.Errorf("migrate db: %w", err) + } + + // Seed default admin if user table is empty + if err := s.SeedAdmin(); err != nil { + log.Printf("[DB] Warning: failed to seed admin: %v", err) + } + + return s, nil +} + +func (s *Store) migrate() error { + query := ` + CREATE TABLE IF NOT EXISTS users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username TEXT NOT NULL UNIQUE, + password_hash TEXT NOT NULL, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP + ); + ` + _, err := s.db.Exec(query) + return err +} + +func (s *Store) SeedAdmin() error { + var count int + err := s.db.QueryRow("SELECT COUNT(*) FROM users").Scan(&count) + if err != nil { + return err + } + if count > 0 { + return nil + } + + username := "admin" + // Default password: "password" + // In production, force user to change this or pass via ENV + password := "password" + if envPass := os.Getenv("ADMIN_PASSWORD"); envPass != "" { + password = envPass + } + + hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + if err != nil { + return err + } + + _, err = s.db.Exec("INSERT INTO users (username, password_hash) VALUES (?, ?)", username, string(hash)) + if err == nil { + log.Printf("[DB] Created initial admin user: '%s' with password from env (or default 'password')", username) + } + return err +} + +func (s *Store) GetUserPasswordHash(username string) (string, error) { + var hash string + err := s.db.QueryRow("SELECT password_hash FROM users WHERE username = ?", username).Scan(&hash) + if err == sql.ErrNoRows { + return "", nil // User not found + } + return hash, err +} + +func (s *Store) Close() error { + return s.db.Close() +} diff --git a/internal/finops/engine.go b/internal/finops/engine.go new file mode 100644 index 0000000..43d1060 --- /dev/null +++ b/internal/finops/engine.go @@ -0,0 +1,114 @@ +package finops + +import ( + "context" + "math" + + agentv1 "github.com/clustercost/clustercost-dashboard/internal/proto/agent/v1" + "github.com/clustercost/clustercost-dashboard/internal/store" + "github.com/clustercost/clustercost-dashboard/internal/vm" +) + +// EfficiencyReport represents the financial analysis of a workload. +type EfficiencyReport struct { + Namespace string `json:"namespace"` + Service string `json:"service"` + RequestedCostMo float64 `json:"requested_cost_mo"` + ActualUsageCostMo float64 `json:"actual_usage_cost_mo"` + PotentialSavingsMo float64 `json:"potential_savings_mo"` + ConfidenceScore float64 `json:"confidence_score"` + EfficiencyScore float64 `json:"efficiency_score"` // 0-100 +} + +// Engine calculates efficiency scores. +type Engine struct { + vmClient *vm.Client + pricing *store.PricingCatalog +} + +// NewEngine creates a new FinOps engine. +func NewEngine(vmClient *vm.Client, pricing *store.PricingCatalog) *Engine { + return &Engine{ + vmClient: vmClient, + pricing: pricing, + } +} + +// CalculatePodEfficiency computes the efficiency report for a single pod. +func (e *Engine) CalculatePodEfficiency(ctx context.Context, pod *agentv1.PodMetric, clusterID, nodeRegion, nodeAZ, instanceType string) (*EfficiencyReport, error) { + // 1. Get Pricing Dimensions + if instanceType == "" { + instanceType = "m5.large" // Fallback + } + + // Get unit prices + cpuPricePerCore, ramPricePerGB := e.pricing.GetNodeResourcePrices(ctx, nodeRegion, instanceType, 2, 8*1024*1024*1024) + + // 2. Calculate Requested Cost (The "Price Tag") + // CPU + reqCPUCores := float64(pod.Cpu.RequestMillicores) / 1000.0 + reqCPUHourly := reqCPUCores * cpuPricePerCore + + // Memory + reqRAMGB := float64(pod.Memory.RequestBytes) / (1024 * 1024 * 1024) + reqRAMHourly := reqRAMGB * ramPricePerGB + + totalReqHourly := reqCPUHourly + reqRAMHourly + totalReqMonthly := totalReqHourly * 730 // 730 hours in a month + + // 3. Get Actual Usage (P95 from VictoriaMetrics) + p95CPU, p95RAMBytes, err := e.vmClient.GetPodP95Usage(ctx, clusterID, pod.Namespace, pod.PodName) + if err != nil { + // If VM is down or no data, we can't calculate usage. + // Return partial report or error. + return nil, err + } + + p95RAMGB := float64(p95RAMBytes) / (1024 * 1024 * 1024) + + // 4. Calculate Usage Cost (The "Reality") + usageCPUHourly := p95CPU * cpuPricePerCore + usageRAMHourly := p95RAMGB * ramPricePerGB + totalUsageHourly := usageCPUHourly + usageRAMHourly + totalUsageMonthly := totalUsageHourly * 730 + + // 5. Calculate Waste & Savings + // Safety Buffer: Recommended = P95 * 1.2 + safeCPU := p95CPU * 1.2 + safeRAM := p95RAMGB * 1.2 + + // Potential Savings = Cost(Requested) - Cost(Safe) + // If Requested < Safe, Savings is 0 (underprovisioned). + savingsHourly := 0.0 + + costSafeCPU := safeCPU * cpuPricePerCore + costSafeRAM := safeRAM * ramPricePerGB + totalSafeHourly := costSafeCPU + costSafeRAM + + if totalReqHourly > totalSafeHourly { + savingsHourly = totalReqHourly - totalSafeHourly + } + + potentialSavingsMo := savingsHourly * 730 + + // 6. Efficiency Score + // Score = (Safe / Requested) * 100 + // If Unset/Zero requests, efficiency is undefined (or 0). + efficiencyScore := 0.0 + if totalReqHourly > 0 { + efficiencyScore = (totalSafeHourly / totalReqHourly) * 100 + if efficiencyScore > 100 { + efficiencyScore = 100 // Cap at 100% (underprovisioned is "efficient" in terms of waste, but risky) + } + } + + return &EfficiencyReport{ + Namespace: pod.Namespace, + Service: pod.PodName, // Or workload name if available + RequestedCostMo: totalReqMonthly, + ActualUsageCostMo: totalUsageMonthly, + PotentialSavingsMo: potentialSavingsMo, + ConfidenceScore: 0.95, // Hardcoded for MVP as per VM availability + EfficiencyScore: math.Round(efficiencyScore*100) / 100, + }, nil +} diff --git a/internal/grpc/collector.go b/internal/grpc/collector.go new file mode 100644 index 0000000..da757ad --- /dev/null +++ b/internal/grpc/collector.go @@ -0,0 +1,98 @@ +package grpc + +import ( + "context" + "fmt" + "log" + + agentv1 "github.com/clustercost/clustercost-dashboard/internal/proto/agent/v1" + "github.com/clustercost/clustercost-dashboard/internal/store" +) + +type Collector struct { + agentv1.UnimplementedCollectorServer + ingestor ReportIngestor + store *store.Store + logLevel string +} + +type ReportIngestor interface { + EnqueueMetrics(agentName string, req *agentv1.MetricsReportRequest) bool + EnqueueNetwork(agentName string, req *agentv1.NetworkReportRequest) bool +} + +func NewCollector(ingestor ReportIngestor, st *store.Store, logLevel string) *Collector { + return &Collector{ + ingestor: ingestor, + store: st, + logLevel: logLevel, + } +} + +func (c *Collector) ReportMetrics(ctx context.Context, req *agentv1.MetricsReportRequest) (*agentv1.ReportResponse, error) { + if c.logLevel == "debug" { + log.Printf("[DEBUG-GRPC] Received Metrics Report from agent %s. Pods: %d, Nodes: %d", req.AgentId, len(req.Pods), len(req.Nodes)) + } + + if err := c.processMetricsReport(req); err != nil { + log.Printf("Failed to process metrics report from agent %s: %v", req.AgentId, err) + return &agentv1.ReportResponse{ + Accepted: false, + ErrorMessage: err.Error(), + }, nil + } + return &agentv1.ReportResponse{Accepted: true}, nil +} + +func (c *Collector) ReportNetwork(ctx context.Context, req *agentv1.NetworkReportRequest) (*agentv1.ReportResponse, error) { + if c.logLevel == "debug" { + log.Printf("[DEBUG-GRPC] Received Network Report from agent %s. Endpoints: %d, Connections: %d", req.AgentId, len(req.Endpoints), len(req.CompactConnections)) + } + + if err := c.processNetworkReport(req); err != nil { + log.Printf("Failed to process network report from agent %s: %v", req.AgentId, err) + return &agentv1.ReportResponse{ + Accepted: false, + ErrorMessage: err.Error(), + }, nil + } + return &agentv1.ReportResponse{Accepted: true}, nil +} + +func (c *Collector) processMetricsReport(req *agentv1.MetricsReportRequest) error { + agentName := req.AgentId + if agentName == "" { + return fmt.Errorf("missing agent_id") + } + + if c.ingestor != nil { + if ok := c.ingestor.EnqueueMetrics(agentName, req); !ok { + return fmt.Errorf("ingest queue full") + } + } + + if c.store != nil { + c.store.UpdateMetrics(agentName, req) + } + + return nil +} + +func (c *Collector) processNetworkReport(req *agentv1.NetworkReportRequest) error { + agentName := req.AgentId + if agentName == "" { + return fmt.Errorf("missing agent_id") + } + + if c.ingestor != nil { + if ok := c.ingestor.EnqueueNetwork(agentName, req); !ok { + return fmt.Errorf("ingest queue full") + } + } + + if c.store != nil { + c.store.UpdateNetwork(agentName, req) + } + + return nil +} diff --git a/internal/grpc/interceptor.go b/internal/grpc/interceptor.go new file mode 100644 index 0000000..79c3782 --- /dev/null +++ b/internal/grpc/interceptor.go @@ -0,0 +1,92 @@ +package grpc + +import ( + "context" + "log" + "strings" + + "github.com/clustercost/clustercost-dashboard/internal/config" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// AuthInterceptor validates the authorization token in the context metadata. +type AuthInterceptor struct { + validTokens map[string]string // map[token]agentName + defaultToken string + logLevel string +} + +// NewAuthInterceptor creates a new interceptor with the valid tokens from config. +func NewAuthInterceptor(agents []config.AgentConfig, defaultToken, logLevel string) *AuthInterceptor { + validTokens := make(map[string]string) + for _, agent := range agents { + if agent.Token != "" { + validTokens[agent.Token] = agent.Name + } + } + return &AuthInterceptor{ + validTokens: validTokens, + defaultToken: defaultToken, + logLevel: logLevel, + } +} + +// Unary returns a UnaryServerInterceptor that validates the token. +func (i *AuthInterceptor) Unary() grpc.UnaryServerInterceptor { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + if i.logLevel == "debug" { + log.Printf("[gRPC] Received request: %s", info.FullMethod) + } + + if len(i.validTokens) == 0 && i.defaultToken == "" { + if i.logLevel == "debug" { + log.Println("[gRPC] No tokens configured, allowing unauthenticated request") + } + // If no tokens are configured, allow unauthenticated access. + return handler(ctx, req) + } + + md, ok := metadata.FromIncomingContext(ctx) + if !ok { + log.Println("[gRPC] Auth failed: no metadata") + return nil, status.Error(codes.Unauthenticated, "metadata is not provided") + } + + values := md["authorization"] + if len(values) == 0 { + log.Println("[gRPC] Auth failed: no authorization header") + return nil, status.Error(codes.Unauthenticated, "authorization token is not provided") + } + + accessToken := strings.TrimPrefix(values[0], "Bearer ") + + // Check default token first + if i.defaultToken != "" && accessToken == i.defaultToken { + if i.logLevel == "debug" { + log.Println("[gRPC] Authenticated with default token") + } + // If default token is used, we might not know the agent name yet. + // It will be extracted from the request body in the handler. + return handler(ctx, req) + } + + // Check specific agent tokens + agentName, ok := i.validTokens[accessToken] + if ok { + if i.logLevel == "debug" { + log.Printf("[gRPC] Authenticated agent: %s", agentName) + } + // Inject agent name into context + type contextKey string + const agentNameKey contextKey = "agent_name" + newCtx := context.WithValue(ctx, agentNameKey, agentName) + return handler(newCtx, req) + } + + log.Printf("[gRPC] Auth failed: invalid token") + return nil, status.Error(codes.Unauthenticated, "invalid token") + } +} diff --git a/internal/grpc/server.go b/internal/grpc/server.go new file mode 100644 index 0000000..c9b4fbd --- /dev/null +++ b/internal/grpc/server.go @@ -0,0 +1,54 @@ +package grpc + +import ( + "fmt" + "log" + "net" + + "github.com/clustercost/clustercost-dashboard/internal/config" + agentv1 "github.com/clustercost/clustercost-dashboard/internal/proto/agent/v1" + "github.com/clustercost/clustercost-dashboard/internal/store" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" +) + +type Server struct { + grpcServer *grpc.Server +} + +func NewServer(cfg config.Config, ingestor ReportIngestor, st *store.Store) *Server { + auth := NewAuthInterceptor(cfg.Agents, cfg.DefaultAgentToken, cfg.LogLevel) + + opts := []grpc.ServerOption{ + grpc.UnaryInterceptor(auth.Unary()), + } + + gsrv := grpc.NewServer(opts...) + + collector := NewCollector(ingestor, st, cfg.LogLevel) + agentv1.RegisterCollectorServer(gsrv, collector) + + // Register reflection service on gRPC server (useful for grpcurl). + reflection.Register(gsrv) + + return &Server{ + grpcServer: gsrv, + } +} + +func (s *Server) ListenAndServe(addr string) error { + lis, err := net.Listen("tcp", addr) + if err != nil { + return fmt.Errorf("failed to listen: %v", err) + } + log.Printf("[gRPC] Server listening on %s", addr) + return s.Serve(lis) +} + +func (s *Server) Serve(lis net.Listener) error { + return s.grpcServer.Serve(lis) +} + +func (s *Server) Stop() { + s.grpcServer.GracefulStop() +} diff --git a/internal/grpc/server_test.go b/internal/grpc/server_test.go new file mode 100644 index 0000000..942cd19 --- /dev/null +++ b/internal/grpc/server_test.go @@ -0,0 +1,91 @@ +package grpc + +import ( + "context" + "net" + "testing" + + "github.com/clustercost/clustercost-dashboard/internal/config" + agentv1 "github.com/clustercost/clustercost-dashboard/internal/proto/agent/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/test/bufconn" +) + +// ... (setup code remains similar) + +func TestReportMetrics_Unary(t *testing.T) { + // Rename to TestReportMetrics_Unary + lis := bufconn.Listen(1024 * 1024) + // Mock ingestor + ingestor := &fakeIngestor{} + // Use config.Config + cfg := config.Config{ + DefaultAgentToken: "secret", + } + s := NewServer(cfg, ingestor, nil) + // NewServer registers collector internally. + + go func() { + if err := s.Serve(lis); err != nil { + t.Logf("Server exited: %v", err) + } + }() + defer s.Stop() + + ctx := context.Background() + conn, err := grpc.DialContext(ctx, "bufnet", + grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) { + return lis.Dial() + }), + grpc.WithTransportCredentials(insecure.NewCredentials()), + ) + if err != nil { + t.Fatalf("Failed to dial bufnet: %v", err) + } + defer conn.Close() + + client := agentv1.NewCollectorClient(conn) + + // Helper to add auth token + authCtx := func(token string) context.Context { + return metadata.NewOutgoingContext(ctx, metadata.Pairs("authorization", "Bearer "+token)) + } + + t.Run("Valid Metrics Report", func(t *testing.T) { + req := &agentv1.MetricsReportRequest{ + AgentId: "agent-1", + ClusterId: "cluster-1", + AvailabilityZone: "us-east-1", + Pods: []*agentv1.PodMetric{ + { + Namespace: "default", + PodName: "pod-1", + Cpu: &agentv1.CpuMetrics{UsageMillicores: 250}, + }, + }, + } + + resp, err := client.ReportMetrics(authCtx("secret"), req) + if err != nil { + t.Fatalf("ReportMetrics failed: %v", err) + } + if !resp.Accepted { + t.Errorf("Expected accepted=true, got false") + } + }) + + // Add other test cases... +} + +// fakeIngestor implementation... +type fakeIngestor struct{} + +func (f *fakeIngestor) EnqueueMetrics(agentName string, req *agentv1.MetricsReportRequest) bool { + return true +} + +func (f *fakeIngestor) EnqueueNetwork(agentName string, req *agentv1.NetworkReportRequest) bool { + return true +} diff --git a/internal/pricing/aws.go b/internal/pricing/aws.go new file mode 100644 index 0000000..5417c31 --- /dev/null +++ b/internal/pricing/aws.go @@ -0,0 +1,159 @@ +package pricing + +import ( + "context" + "encoding/json" + "fmt" + "strconv" + "sync" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/pricing" + "github.com/aws/aws-sdk-go-v2/service/pricing/types" +) + +// Provider defines the interface for fetching node pricing. +type Provider interface { + GetNodePrice(ctx context.Context, region, instanceType string) (float64, error) +} + +// AWSClient implements Provider using AWS Pricing API. +type AWSClient struct { + client *pricing.Client + cache sync.Map // map[string]float64 key=region|instanceType +} + +// NewAWSClient initializes the AWS Pricing client. +// Note: AWS Pricing API is only available in us-east-1 and ap-south-1. +// We must use us-east-1 endpoint to query for all regions. +func NewAWSClient(ctx context.Context) (*AWSClient, error) { + cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion("us-east-1")) + if err != nil { + return nil, fmt.Errorf("unable to load SDK config: %v", err) + } + + return &AWSClient{ + client: pricing.NewFromConfig(cfg), + }, nil +} + +func (c *AWSClient) GetNodePrice(ctx context.Context, region, instanceType string) (float64, error) { + key := fmt.Sprintf("%s|%s", region, instanceType) + if val, ok := c.cache.Load(key); ok { + return val.(float64), nil + } + + // Fetch from AWS + price, err := c.fetchPrice(ctx, region, instanceType) + if err != nil { + return 0, err + } + + c.cache.Store(key, price) + return price, nil +} + +// fetchPrice queries AWS Pricing API. +// Note: "Region" in Pricing API is "Location" attribute (e.g. "US East (N. Virginia)"). +// We need to map region codes (us-east-1) to Location descriptions? +// Actually, GetProducts allows filtering by "regionCode" if we use serviceCode="AmazonEC2". +func (c *AWSClient) fetchPrice(ctx context.Context, regionCode, instanceType string) (float64, error) { + input := &pricing.GetProductsInput{ + ServiceCode: aws.String("AmazonEC2"), + Filters: []types.Filter{ + { + Type: types.FilterTypeTermMatch, + Field: aws.String("instanceType"), + Value: aws.String(instanceType), + }, + { + Type: types.FilterTypeTermMatch, + Field: aws.String("regionCode"), + Value: aws.String(regionCode), + }, + { + Type: types.FilterTypeTermMatch, + Field: aws.String("operatingSystem"), + Value: aws.String("Linux"), + }, + { + Type: types.FilterTypeTermMatch, + Field: aws.String("preInstalledSw"), + Value: aws.String("NA"), + }, + { + Type: types.FilterTypeTermMatch, + Field: aws.String("tenancy"), + Value: aws.String("Shared"), + }, + { + Type: types.FilterTypeTermMatch, + Field: aws.String("capacitystatus"), + Value: aws.String("Used"), + }, + }, + MaxResults: aws.Int32(1), + } + + resp, err := c.client.GetProducts(ctx, input) + if err != nil { + return 0, fmt.Errorf("aws pricing api error: %w", err) + } + + if len(resp.PriceList) == 0 { + return 0, fmt.Errorf("no price found for %s in %s", instanceType, regionCode) + } + + // The PriceList is a list of JSON strings. We need to parse it. + // Structure is complex: Product -> Terms -> OnDemand -> PriceDimensions -> PricePerUnit. + priceStr := resp.PriceList[0] + + return parseAWSPriceJSON(priceStr) +} + +func parseAWSPriceJSON(jsonStr string) (float64, error) { + // Simplified parsing logic + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return 0, err + } + + terms, ok := data["terms"].(map[string]interface{}) + if !ok { + return 0, fmt.Errorf("missing terms") + } + onDemand, ok := terms["OnDemand"].(map[string]interface{}) + if !ok { + return 0, fmt.Errorf("missing OnDemand terms") + } + + // Iterate over the arbitrary keys (SKUs) + for _, term := range onDemand { + termMap, ok := term.(map[string]interface{}) + if !ok { + continue + } + priceDimensions, ok := termMap["priceDimensions"].(map[string]interface{}) + if !ok { + continue + } + for _, pd := range priceDimensions { + pdMap, ok := pd.(map[string]interface{}) + if !ok { + continue + } + pricePerUnit, ok := pdMap["pricePerUnit"].(map[string]interface{}) + if !ok { + continue + } + usd, ok := pricePerUnit["USD"].(string) + if !ok { + continue + } + return strconv.ParseFloat(usd, 64) + } + } + + return 0, fmt.Errorf("could not extract price from document") +} diff --git a/internal/pricing/data.go b/internal/pricing/data.go new file mode 100644 index 0000000..bab2a6a --- /dev/null +++ b/internal/pricing/data.go @@ -0,0 +1,13062 @@ +// Code generated by scripts/generate_pricing.go; DO NOT EDIT. +// Generated at 2026-01-11T22:28:37-05:00 +package pricing + +var InstancePrices = map[string]float64{ + "ap-northeast-1|a1.2xlarge": 0.256800, + "ap-northeast-1|a1.4xlarge": 0.513600, + "ap-northeast-1|a1.large": 0.064200, + "ap-northeast-1|a1.medium": 0.032100, + "ap-northeast-1|a1.metal": 0.514000, + "ap-northeast-1|a1.xlarge": 0.128400, + "ap-northeast-1|c1.medium": 0.158000, + "ap-northeast-1|c1.xlarge": 0.632000, + "ap-northeast-1|c3.2xlarge": 0.511000, + "ap-northeast-1|c3.4xlarge": 1.021000, + "ap-northeast-1|c3.8xlarge": 2.043000, + "ap-northeast-1|c3.large": 0.128000, + "ap-northeast-1|c3.xlarge": 0.255000, + "ap-northeast-1|c4.2xlarge": 0.504000, + "ap-northeast-1|c4.4xlarge": 1.008000, + "ap-northeast-1|c4.8xlarge": 2.016000, + "ap-northeast-1|c4.large": 0.126000, + "ap-northeast-1|c4.xlarge": 0.252000, + "ap-northeast-1|c5.12xlarge": 2.568000, + "ap-northeast-1|c5.18xlarge": 3.852000, + "ap-northeast-1|c5.24xlarge": 5.136000, + "ap-northeast-1|c5.2xlarge": 0.428000, + "ap-northeast-1|c5.4xlarge": 0.856000, + "ap-northeast-1|c5.9xlarge": 1.926000, + "ap-northeast-1|c5.large": 0.107000, + "ap-northeast-1|c5.metal": 5.136000, + "ap-northeast-1|c5.xlarge": 0.214000, + "ap-northeast-1|c5a.12xlarge": 2.304000, + "ap-northeast-1|c5a.16xlarge": 3.072000, + "ap-northeast-1|c5a.24xlarge": 4.608000, + "ap-northeast-1|c5a.2xlarge": 0.384000, + "ap-northeast-1|c5a.4xlarge": 0.768000, + "ap-northeast-1|c5a.8xlarge": 1.536000, + "ap-northeast-1|c5a.large": 0.096000, + "ap-northeast-1|c5a.xlarge": 0.192000, + "ap-northeast-1|c5d.12xlarge": 2.928000, + "ap-northeast-1|c5d.18xlarge": 4.392000, + "ap-northeast-1|c5d.24xlarge": 5.856000, + "ap-northeast-1|c5d.2xlarge": 0.488000, + "ap-northeast-1|c5d.4xlarge": 0.976000, + "ap-northeast-1|c5d.9xlarge": 2.196000, + "ap-northeast-1|c5d.large": 0.122000, + "ap-northeast-1|c5d.metal": 5.856000, + "ap-northeast-1|c5d.xlarge": 0.244000, + "ap-northeast-1|c5n.18xlarge": 4.896000, + "ap-northeast-1|c5n.2xlarge": 0.544000, + "ap-northeast-1|c5n.4xlarge": 1.088000, + "ap-northeast-1|c5n.9xlarge": 2.448000, + "ap-northeast-1|c5n.large": 0.136000, + "ap-northeast-1|c5n.metal": 4.896000, + "ap-northeast-1|c5n.xlarge": 0.272000, + "ap-northeast-1|c6a.12xlarge": 2.311200, + "ap-northeast-1|c6a.16xlarge": 3.081600, + "ap-northeast-1|c6a.24xlarge": 4.622400, + "ap-northeast-1|c6a.2xlarge": 0.385200, + "ap-northeast-1|c6a.32xlarge": 6.163200, + "ap-northeast-1|c6a.48xlarge": 9.244800, + "ap-northeast-1|c6a.4xlarge": 0.770400, + "ap-northeast-1|c6a.8xlarge": 1.540800, + "ap-northeast-1|c6a.large": 0.096300, + "ap-northeast-1|c6a.metal": 9.244800, + "ap-northeast-1|c6a.xlarge": 0.192600, + "ap-northeast-1|c6g.12xlarge": 2.054400, + "ap-northeast-1|c6g.16xlarge": 2.739200, + "ap-northeast-1|c6g.2xlarge": 0.342400, + "ap-northeast-1|c6g.4xlarge": 0.684800, + "ap-northeast-1|c6g.8xlarge": 1.369600, + "ap-northeast-1|c6g.large": 0.085600, + "ap-northeast-1|c6g.medium": 0.042800, + "ap-northeast-1|c6g.metal": 2.739200, + "ap-northeast-1|c6g.xlarge": 0.171200, + "ap-northeast-1|c6gd.12xlarge": 2.352000, + "ap-northeast-1|c6gd.16xlarge": 3.136000, + "ap-northeast-1|c6gd.2xlarge": 0.392000, + "ap-northeast-1|c6gd.4xlarge": 0.784000, + "ap-northeast-1|c6gd.8xlarge": 1.568000, + "ap-northeast-1|c6gd.large": 0.098000, + "ap-northeast-1|c6gd.medium": 0.049000, + "ap-northeast-1|c6gd.metal": 3.136000, + "ap-northeast-1|c6gd.xlarge": 0.196000, + "ap-northeast-1|c6gn.12xlarge": 2.616000, + "ap-northeast-1|c6gn.16xlarge": 3.488000, + "ap-northeast-1|c6gn.2xlarge": 0.436000, + "ap-northeast-1|c6gn.4xlarge": 0.872000, + "ap-northeast-1|c6gn.8xlarge": 1.744000, + "ap-northeast-1|c6gn.large": 0.109000, + "ap-northeast-1|c6gn.medium": 0.054500, + "ap-northeast-1|c6gn.xlarge": 0.218000, + "ap-northeast-1|c6i.12xlarge": 2.568000, + "ap-northeast-1|c6i.16xlarge": 3.424000, + "ap-northeast-1|c6i.24xlarge": 5.136000, + "ap-northeast-1|c6i.2xlarge": 0.428000, + "ap-northeast-1|c6i.32xlarge": 6.848000, + "ap-northeast-1|c6i.4xlarge": 0.856000, + "ap-northeast-1|c6i.8xlarge": 1.712000, + "ap-northeast-1|c6i.large": 0.107000, + "ap-northeast-1|c6i.metal": 6.848000, + "ap-northeast-1|c6i.xlarge": 0.214000, + "ap-northeast-1|c6id.12xlarge": 3.074400, + "ap-northeast-1|c6id.16xlarge": 4.099200, + "ap-northeast-1|c6id.24xlarge": 6.148800, + "ap-northeast-1|c6id.2xlarge": 0.512400, + "ap-northeast-1|c6id.32xlarge": 8.198400, + "ap-northeast-1|c6id.4xlarge": 1.024800, + "ap-northeast-1|c6id.8xlarge": 2.049600, + "ap-northeast-1|c6id.large": 0.128100, + "ap-northeast-1|c6id.metal": 8.198400, + "ap-northeast-1|c6id.xlarge": 0.256200, + "ap-northeast-1|c6in.12xlarge": 3.427200, + "ap-northeast-1|c6in.16xlarge": 4.569600, + "ap-northeast-1|c6in.24xlarge": 6.854400, + "ap-northeast-1|c6in.2xlarge": 0.571200, + "ap-northeast-1|c6in.32xlarge": 9.139200, + "ap-northeast-1|c6in.4xlarge": 1.142400, + "ap-northeast-1|c6in.8xlarge": 2.284800, + "ap-northeast-1|c6in.large": 0.142800, + "ap-northeast-1|c6in.metal": 9.139200, + "ap-northeast-1|c6in.xlarge": 0.285600, + "ap-northeast-1|c7a.12xlarge": 3.100800, + "ap-northeast-1|c7a.16xlarge": 4.134400, + "ap-northeast-1|c7a.24xlarge": 6.201600, + "ap-northeast-1|c7a.2xlarge": 0.516800, + "ap-northeast-1|c7a.32xlarge": 8.268800, + "ap-northeast-1|c7a.48xlarge": 12.403200, + "ap-northeast-1|c7a.4xlarge": 1.033600, + "ap-northeast-1|c7a.8xlarge": 2.067200, + "ap-northeast-1|c7a.large": 0.129200, + "ap-northeast-1|c7a.medium": 0.064600, + "ap-northeast-1|c7a.metal-48xl": 12.403200, + "ap-northeast-1|c7a.xlarge": 0.258400, + "ap-northeast-1|c7g.12xlarge": 2.183000, + "ap-northeast-1|c7g.16xlarge": 2.910700, + "ap-northeast-1|c7g.2xlarge": 0.363800, + "ap-northeast-1|c7g.4xlarge": 0.727700, + "ap-northeast-1|c7g.8xlarge": 1.455400, + "ap-northeast-1|c7g.large": 0.091000, + "ap-northeast-1|c7g.medium": 0.045500, + "ap-northeast-1|c7g.metal": 2.910700, + "ap-northeast-1|c7g.xlarge": 0.181900, + "ap-northeast-1|c7gd.12xlarge": 2.767200, + "ap-northeast-1|c7gd.16xlarge": 3.689600, + "ap-northeast-1|c7gd.2xlarge": 0.461200, + "ap-northeast-1|c7gd.4xlarge": 0.922400, + "ap-northeast-1|c7gd.8xlarge": 1.844800, + "ap-northeast-1|c7gd.large": 0.115300, + "ap-northeast-1|c7gd.medium": 0.057700, + "ap-northeast-1|c7gd.metal": 3.689600, + "ap-northeast-1|c7gd.xlarge": 0.230600, + "ap-northeast-1|c7gn.12xlarge": 3.777600, + "ap-northeast-1|c7gn.16xlarge": 5.036800, + "ap-northeast-1|c7gn.2xlarge": 0.629600, + "ap-northeast-1|c7gn.4xlarge": 1.259200, + "ap-northeast-1|c7gn.8xlarge": 2.518400, + "ap-northeast-1|c7gn.large": 0.157400, + "ap-northeast-1|c7gn.medium": 0.078700, + "ap-northeast-1|c7gn.metal": 5.036800, + "ap-northeast-1|c7gn.xlarge": 0.314800, + "ap-northeast-1|c7i-flex.12xlarge": 2.561580, + "ap-northeast-1|c7i-flex.16xlarge": 3.415440, + "ap-northeast-1|c7i-flex.2xlarge": 0.426930, + "ap-northeast-1|c7i-flex.4xlarge": 0.853860, + "ap-northeast-1|c7i-flex.8xlarge": 1.707720, + "ap-northeast-1|c7i-flex.large": 0.106730, + "ap-northeast-1|c7i-flex.xlarge": 0.213470, + "ap-northeast-1|c7i.12xlarge": 2.696400, + "ap-northeast-1|c7i.16xlarge": 3.595200, + "ap-northeast-1|c7i.24xlarge": 5.392800, + "ap-northeast-1|c7i.2xlarge": 0.449400, + "ap-northeast-1|c7i.48xlarge": 10.785600, + "ap-northeast-1|c7i.4xlarge": 0.898800, + "ap-northeast-1|c7i.8xlarge": 1.797600, + "ap-northeast-1|c7i.large": 0.112350, + "ap-northeast-1|c7i.metal-24xl": 5.392800, + "ap-northeast-1|c7i.metal-48xl": 10.785600, + "ap-northeast-1|c7i.xlarge": 0.224700, + "ap-northeast-1|c8g.12xlarge": 2.401440, + "ap-northeast-1|c8g.16xlarge": 3.201920, + "ap-northeast-1|c8g.24xlarge": 4.802880, + "ap-northeast-1|c8g.2xlarge": 0.400240, + "ap-northeast-1|c8g.48xlarge": 9.605760, + "ap-northeast-1|c8g.4xlarge": 0.800480, + "ap-northeast-1|c8g.8xlarge": 1.600960, + "ap-northeast-1|c8g.large": 0.100060, + "ap-northeast-1|c8g.medium": 0.050030, + "ap-northeast-1|c8g.metal-24xl": 4.802880, + "ap-northeast-1|c8g.metal-48xl": 9.605760, + "ap-northeast-1|c8g.xlarge": 0.200120, + "ap-northeast-1|c8gd.12xlarge": 2.988480, + "ap-northeast-1|c8gd.16xlarge": 3.984640, + "ap-northeast-1|c8gd.24xlarge": 5.976960, + "ap-northeast-1|c8gd.2xlarge": 0.498080, + "ap-northeast-1|c8gd.48xlarge": 11.953920, + "ap-northeast-1|c8gd.4xlarge": 0.996160, + "ap-northeast-1|c8gd.8xlarge": 1.992320, + "ap-northeast-1|c8gd.large": 0.124520, + "ap-northeast-1|c8gd.medium": 0.062260, + "ap-northeast-1|c8gd.metal-24xl": 5.976960, + "ap-northeast-1|c8gd.metal-48xl": 11.953920, + "ap-northeast-1|c8gd.xlarge": 0.249040, + "ap-northeast-1|c8i-flex.12xlarge": 2.689680, + "ap-northeast-1|c8i-flex.16xlarge": 3.586240, + "ap-northeast-1|c8i-flex.2xlarge": 0.448280, + "ap-northeast-1|c8i-flex.4xlarge": 0.896560, + "ap-northeast-1|c8i-flex.8xlarge": 1.793120, + "ap-northeast-1|c8i-flex.large": 0.112070, + "ap-northeast-1|c8i-flex.xlarge": 0.224140, + "ap-northeast-1|c8i.12xlarge": 2.831280, + "ap-northeast-1|c8i.16xlarge": 3.775040, + "ap-northeast-1|c8i.24xlarge": 5.662560, + "ap-northeast-1|c8i.2xlarge": 0.471880, + "ap-northeast-1|c8i.32xlarge": 7.550080, + "ap-northeast-1|c8i.48xlarge": 11.325120, + "ap-northeast-1|c8i.4xlarge": 0.943760, + "ap-northeast-1|c8i.8xlarge": 1.887520, + "ap-northeast-1|c8i.96xlarge": 22.650240, + "ap-northeast-1|c8i.large": 0.117970, + "ap-northeast-1|c8i.metal-48xl": 11.325120, + "ap-northeast-1|c8i.metal-96xl": 22.650240, + "ap-northeast-1|c8i.xlarge": 0.235940, + "ap-northeast-1|cr1.8xlarge": 4.105000, + "ap-northeast-1|d2.2xlarge": 1.688000, + "ap-northeast-1|d2.4xlarge": 3.376000, + "ap-northeast-1|d2.8xlarge": 6.752000, + "ap-northeast-1|d2.xlarge": 0.844000, + "ap-northeast-1|d3.2xlarge": 1.448000, + "ap-northeast-1|d3.4xlarge": 2.897000, + "ap-northeast-1|d3.8xlarge": 5.793440, + "ap-northeast-1|d3.xlarge": 0.724000, + "ap-northeast-1|d3en.12xlarge": 9.147600, + "ap-northeast-1|d3en.2xlarge": 1.525000, + "ap-northeast-1|d3en.4xlarge": 3.049000, + "ap-northeast-1|d3en.6xlarge": 4.574000, + "ap-northeast-1|d3en.8xlarge": 6.098400, + "ap-northeast-1|d3en.xlarge": 0.762000, + "ap-northeast-1|f2.12xlarge": 5.347200, + "ap-northeast-1|f2.48xlarge": 21.388800, + "ap-northeast-1|f2.6xlarge": 2.673600, + "ap-northeast-1|g2.2xlarge": 0.898000, + "ap-northeast-1|g2.8xlarge": 3.592000, + "ap-northeast-1|g3.16xlarge": 6.320000, + "ap-northeast-1|g3.4xlarge": 1.580000, + "ap-northeast-1|g3.8xlarge": 3.160000, + "ap-northeast-1|g3s.xlarge": 1.040000, + "ap-northeast-1|g4ad.16xlarge": 4.680000, + "ap-northeast-1|g4ad.2xlarge": 0.730300, + "ap-northeast-1|g4ad.4xlarge": 1.170000, + "ap-northeast-1|g4ad.8xlarge": 2.340000, + "ap-northeast-1|g4ad.xlarge": 0.510820, + "ap-northeast-1|g4dn.12xlarge": 5.281000, + "ap-northeast-1|g4dn.16xlarge": 5.875000, + "ap-northeast-1|g4dn.2xlarge": 1.015000, + "ap-northeast-1|g4dn.4xlarge": 1.625000, + "ap-northeast-1|g4dn.8xlarge": 2.938000, + "ap-northeast-1|g4dn.metal": 10.562000, + "ap-northeast-1|g4dn.xlarge": 0.710000, + "ap-northeast-1|g5.12xlarge": 8.226090, + "ap-northeast-1|g5.16xlarge": 5.940420, + "ap-northeast-1|g5.24xlarge": 11.811230, + "ap-northeast-1|g5.2xlarge": 1.757760, + "ap-northeast-1|g5.48xlarge": 23.622460, + "ap-northeast-1|g5.4xlarge": 2.355280, + "ap-northeast-1|g5.8xlarge": 3.550330, + "ap-northeast-1|g5.xlarge": 1.459000, + "ap-northeast-1|g5g.16xlarge": 3.703900, + "ap-northeast-1|g5g.2xlarge": 0.750500, + "ap-northeast-1|g5g.4xlarge": 1.117600, + "ap-northeast-1|g5g.8xlarge": 1.851900, + "ap-northeast-1|g5g.metal": 3.703900, + "ap-northeast-1|g5g.xlarge": 0.566900, + "ap-northeast-1|g6.12xlarge": 6.673690, + "ap-northeast-1|g6.16xlarge": 4.926370, + "ap-northeast-1|g6.24xlarge": 9.681030, + "ap-northeast-1|g6.2xlarge": 1.417810, + "ap-northeast-1|g6.48xlarge": 19.362060, + "ap-northeast-1|g6.4xlarge": 1.919030, + "ap-northeast-1|g6.8xlarge": 2.921480, + "ap-northeast-1|g6.xlarge": 1.167200, + "ap-northeast-1|g6e.12xlarge": 15.217420, + "ap-northeast-1|g6e.16xlarge": 10.989170, + "ap-northeast-1|g6e.24xlarge": 21.849560, + "ap-northeast-1|g6e.2xlarge": 3.251680, + "ap-northeast-1|g6e.48xlarge": 43.699120, + "ap-northeast-1|g6e.4xlarge": 4.357030, + "ap-northeast-1|g6e.8xlarge": 6.567750, + "ap-northeast-1|g6e.xlarge": 2.699000, + "ap-northeast-1|g6f.2xlarge": 0.688880, + "ap-northeast-1|g6f.4xlarge": 1.377760, + "ap-northeast-1|g6f.large": 0.292960, + "ap-northeast-1|g6f.xlarge": 0.344440, + "ap-northeast-1|gr6.4xlarge": 2.232300, + "ap-northeast-1|gr6.8xlarge": 3.548010, + "ap-northeast-1|gr6f.4xlarge": 1.546020, + "ap-northeast-1|hpc7g.16xlarge": 2.111700, + "ap-northeast-1|hpc7g.4xlarge": 2.111700, + "ap-northeast-1|hpc7g.8xlarge": 2.111700, + "ap-northeast-1|i2.2xlarge": 2.001000, + "ap-northeast-1|i2.4xlarge": 4.002000, + "ap-northeast-1|i2.8xlarge": 8.004000, + "ap-northeast-1|i2.xlarge": 1.001000, + "ap-northeast-1|i3.16xlarge": 5.856000, + "ap-northeast-1|i3.2xlarge": 0.732000, + "ap-northeast-1|i3.4xlarge": 1.464000, + "ap-northeast-1|i3.8xlarge": 2.928000, + "ap-northeast-1|i3.large": 0.183000, + "ap-northeast-1|i3.metal": 5.856000, + "ap-northeast-1|i3.xlarge": 0.366000, + "ap-northeast-1|i3en.12xlarge": 6.384000, + "ap-northeast-1|i3en.24xlarge": 12.768000, + "ap-northeast-1|i3en.2xlarge": 1.064000, + "ap-northeast-1|i3en.3xlarge": 1.596000, + "ap-northeast-1|i3en.6xlarge": 3.192000, + "ap-northeast-1|i3en.large": 0.266000, + "ap-northeast-1|i3en.metal": 12.768000, + "ap-northeast-1|i3en.xlarge": 0.532000, + "ap-northeast-1|i4i.12xlarge": 4.831000, + "ap-northeast-1|i4i.16xlarge": 6.442000, + "ap-northeast-1|i4i.24xlarge": 9.662400, + "ap-northeast-1|i4i.2xlarge": 0.805000, + "ap-northeast-1|i4i.32xlarge": 12.883200, + "ap-northeast-1|i4i.4xlarge": 1.610000, + "ap-northeast-1|i4i.8xlarge": 3.221000, + "ap-northeast-1|i4i.large": 0.201000, + "ap-northeast-1|i4i.metal": 12.883000, + "ap-northeast-1|i4i.xlarge": 0.403000, + "ap-northeast-1|i7i.12xlarge": 5.314300, + "ap-northeast-1|i7i.16xlarge": 7.085800, + "ap-northeast-1|i7i.24xlarge": 10.628600, + "ap-northeast-1|i7i.2xlarge": 0.885700, + "ap-northeast-1|i7i.48xlarge": 21.257300, + "ap-northeast-1|i7i.4xlarge": 1.771400, + "ap-northeast-1|i7i.8xlarge": 3.542900, + "ap-northeast-1|i7i.large": 0.221400, + "ap-northeast-1|i7i.metal-24xl": 10.628600, + "ap-northeast-1|i7i.metal-48xl": 21.257300, + "ap-northeast-1|i7i.xlarge": 0.442900, + "ap-northeast-1|i7ie.12xlarge": 7.341600, + "ap-northeast-1|i7ie.18xlarge": 11.012400, + "ap-northeast-1|i7ie.24xlarge": 14.683200, + "ap-northeast-1|i7ie.2xlarge": 1.223600, + "ap-northeast-1|i7ie.3xlarge": 1.835400, + "ap-northeast-1|i7ie.48xlarge": 29.366400, + "ap-northeast-1|i7ie.6xlarge": 3.670800, + "ap-northeast-1|i7ie.large": 0.305900, + "ap-northeast-1|i7ie.metal-24xl": 14.683200, + "ap-northeast-1|i7ie.metal-48xl": 29.366400, + "ap-northeast-1|i7ie.xlarge": 0.611800, + "ap-northeast-1|i8g.12xlarge": 4.838400, + "ap-northeast-1|i8g.16xlarge": 6.451200, + "ap-northeast-1|i8g.24xlarge": 9.676800, + "ap-northeast-1|i8g.2xlarge": 0.806400, + "ap-northeast-1|i8g.48xlarge": 19.353600, + "ap-northeast-1|i8g.4xlarge": 1.612800, + "ap-northeast-1|i8g.8xlarge": 3.225600, + "ap-northeast-1|i8g.large": 0.201600, + "ap-northeast-1|i8g.metal-24xl": 9.676800, + "ap-northeast-1|i8g.xlarge": 0.403200, + "ap-northeast-1|im4gn.16xlarge": 6.828100, + "ap-northeast-1|im4gn.2xlarge": 0.853510, + "ap-northeast-1|im4gn.4xlarge": 1.707020, + "ap-northeast-1|im4gn.8xlarge": 3.414050, + "ap-northeast-1|im4gn.large": 0.213380, + "ap-northeast-1|im4gn.xlarge": 0.426760, + "ap-northeast-1|inf1.24xlarge": 6.376000, + "ap-northeast-1|inf1.2xlarge": 0.489000, + "ap-northeast-1|inf1.6xlarge": 1.594000, + "ap-northeast-1|inf1.xlarge": 0.308000, + "ap-northeast-1|inf2.24xlarge": 9.735950, + "ap-northeast-1|inf2.48xlarge": 19.471900, + "ap-northeast-1|inf2.8xlarge": 2.951790, + "ap-northeast-1|inf2.xlarge": 1.137300, + "ap-northeast-1|is4gen.2xlarge": 1.356600, + "ap-northeast-1|is4gen.4xlarge": 2.713200, + "ap-northeast-1|is4gen.8xlarge": 5.426400, + "ap-northeast-1|is4gen.large": 0.339150, + "ap-northeast-1|is4gen.medium": 0.169580, + "ap-northeast-1|is4gen.xlarge": 0.678300, + "ap-northeast-1|m1.large": 0.243000, + "ap-northeast-1|m1.medium": 0.122000, + "ap-northeast-1|m1.small": 0.061000, + "ap-northeast-1|m1.xlarge": 0.486000, + "ap-northeast-1|m2.2xlarge": 0.575000, + "ap-northeast-1|m2.4xlarge": 1.150000, + "ap-northeast-1|m2.xlarge": 0.287000, + "ap-northeast-1|m3.2xlarge": 0.770000, + "ap-northeast-1|m3.large": 0.193000, + "ap-northeast-1|m3.medium": 0.096000, + "ap-northeast-1|m3.xlarge": 0.385000, + "ap-northeast-1|m4.10xlarge": 2.580000, + "ap-northeast-1|m4.16xlarge": 4.128000, + "ap-northeast-1|m4.2xlarge": 0.516000, + "ap-northeast-1|m4.4xlarge": 1.032000, + "ap-northeast-1|m4.large": 0.129000, + "ap-northeast-1|m4.xlarge": 0.258000, + "ap-northeast-1|m5.12xlarge": 2.976000, + "ap-northeast-1|m5.16xlarge": 3.968000, + "ap-northeast-1|m5.24xlarge": 5.952000, + "ap-northeast-1|m5.2xlarge": 0.496000, + "ap-northeast-1|m5.4xlarge": 0.992000, + "ap-northeast-1|m5.8xlarge": 1.984000, + "ap-northeast-1|m5.large": 0.124000, + "ap-northeast-1|m5.metal": 5.952000, + "ap-northeast-1|m5.xlarge": 0.248000, + "ap-northeast-1|m5a.12xlarge": 2.688000, + "ap-northeast-1|m5a.16xlarge": 3.584000, + "ap-northeast-1|m5a.24xlarge": 5.376000, + "ap-northeast-1|m5a.2xlarge": 0.448000, + "ap-northeast-1|m5a.4xlarge": 0.896000, + "ap-northeast-1|m5a.8xlarge": 1.792000, + "ap-northeast-1|m5a.large": 0.112000, + "ap-northeast-1|m5a.xlarge": 0.224000, + "ap-northeast-1|m5ad.12xlarge": 3.216000, + "ap-northeast-1|m5ad.16xlarge": 4.288000, + "ap-northeast-1|m5ad.24xlarge": 6.432000, + "ap-northeast-1|m5ad.2xlarge": 0.536000, + "ap-northeast-1|m5ad.4xlarge": 1.072000, + "ap-northeast-1|m5ad.8xlarge": 2.144000, + "ap-northeast-1|m5ad.large": 0.134000, + "ap-northeast-1|m5ad.xlarge": 0.268000, + "ap-northeast-1|m5d.12xlarge": 3.504000, + "ap-northeast-1|m5d.16xlarge": 4.672000, + "ap-northeast-1|m5d.24xlarge": 7.008000, + "ap-northeast-1|m5d.2xlarge": 0.584000, + "ap-northeast-1|m5d.4xlarge": 1.168000, + "ap-northeast-1|m5d.8xlarge": 2.336000, + "ap-northeast-1|m5d.large": 0.146000, + "ap-northeast-1|m5d.metal": 7.008000, + "ap-northeast-1|m5d.xlarge": 0.292000, + "ap-northeast-1|m5dn.12xlarge": 4.200000, + "ap-northeast-1|m5dn.16xlarge": 5.600000, + "ap-northeast-1|m5dn.24xlarge": 8.400000, + "ap-northeast-1|m5dn.2xlarge": 0.700000, + "ap-northeast-1|m5dn.4xlarge": 1.400000, + "ap-northeast-1|m5dn.8xlarge": 2.800000, + "ap-northeast-1|m5dn.large": 0.175000, + "ap-northeast-1|m5dn.metal": 8.400000, + "ap-northeast-1|m5dn.xlarge": 0.350000, + "ap-northeast-1|m5n.12xlarge": 3.672000, + "ap-northeast-1|m5n.16xlarge": 4.896000, + "ap-northeast-1|m5n.24xlarge": 7.344000, + "ap-northeast-1|m5n.2xlarge": 0.612000, + "ap-northeast-1|m5n.4xlarge": 1.224000, + "ap-northeast-1|m5n.8xlarge": 2.448000, + "ap-northeast-1|m5n.large": 0.153000, + "ap-northeast-1|m5n.metal": 7.344000, + "ap-northeast-1|m5n.xlarge": 0.306000, + "ap-northeast-1|m5zn.12xlarge": 5.120400, + "ap-northeast-1|m5zn.2xlarge": 0.853400, + "ap-northeast-1|m5zn.3xlarge": 1.280100, + "ap-northeast-1|m5zn.6xlarge": 2.560200, + "ap-northeast-1|m5zn.large": 0.213400, + "ap-northeast-1|m5zn.metal": 5.120400, + "ap-northeast-1|m5zn.xlarge": 0.426700, + "ap-northeast-1|m6a.12xlarge": 2.678400, + "ap-northeast-1|m6a.16xlarge": 3.571200, + "ap-northeast-1|m6a.24xlarge": 5.356800, + "ap-northeast-1|m6a.2xlarge": 0.446400, + "ap-northeast-1|m6a.32xlarge": 7.142400, + "ap-northeast-1|m6a.48xlarge": 10.713600, + "ap-northeast-1|m6a.4xlarge": 0.892800, + "ap-northeast-1|m6a.8xlarge": 1.785600, + "ap-northeast-1|m6a.large": 0.111600, + "ap-northeast-1|m6a.metal": 10.713600, + "ap-northeast-1|m6a.xlarge": 0.223200, + "ap-northeast-1|m6g.12xlarge": 2.376000, + "ap-northeast-1|m6g.16xlarge": 3.168000, + "ap-northeast-1|m6g.2xlarge": 0.396000, + "ap-northeast-1|m6g.4xlarge": 0.792000, + "ap-northeast-1|m6g.8xlarge": 1.584000, + "ap-northeast-1|m6g.large": 0.099000, + "ap-northeast-1|m6g.medium": 0.049500, + "ap-northeast-1|m6g.metal": 3.168000, + "ap-northeast-1|m6g.xlarge": 0.198000, + "ap-northeast-1|m6gd.12xlarge": 2.808000, + "ap-northeast-1|m6gd.16xlarge": 3.744000, + "ap-northeast-1|m6gd.2xlarge": 0.468000, + "ap-northeast-1|m6gd.4xlarge": 0.936000, + "ap-northeast-1|m6gd.8xlarge": 1.872000, + "ap-northeast-1|m6gd.large": 0.117000, + "ap-northeast-1|m6gd.medium": 0.058500, + "ap-northeast-1|m6gd.metal": 3.744000, + "ap-northeast-1|m6gd.xlarge": 0.234000, + "ap-northeast-1|m6i.12xlarge": 2.976000, + "ap-northeast-1|m6i.16xlarge": 3.968000, + "ap-northeast-1|m6i.24xlarge": 5.952000, + "ap-northeast-1|m6i.2xlarge": 0.496000, + "ap-northeast-1|m6i.32xlarge": 7.936000, + "ap-northeast-1|m6i.4xlarge": 0.992000, + "ap-northeast-1|m6i.8xlarge": 1.984000, + "ap-northeast-1|m6i.large": 0.124000, + "ap-northeast-1|m6i.metal": 7.936000, + "ap-northeast-1|m6i.xlarge": 0.248000, + "ap-northeast-1|m6id.12xlarge": 3.679200, + "ap-northeast-1|m6id.16xlarge": 4.905600, + "ap-northeast-1|m6id.24xlarge": 7.358400, + "ap-northeast-1|m6id.2xlarge": 0.613200, + "ap-northeast-1|m6id.32xlarge": 9.811200, + "ap-northeast-1|m6id.4xlarge": 1.226400, + "ap-northeast-1|m6id.8xlarge": 2.452800, + "ap-northeast-1|m6id.large": 0.153300, + "ap-northeast-1|m6id.metal": 9.811200, + "ap-northeast-1|m6id.xlarge": 0.306600, + "ap-northeast-1|m6idn.12xlarge": 4.914000, + "ap-northeast-1|m6idn.16xlarge": 6.552000, + "ap-northeast-1|m6idn.24xlarge": 9.828000, + "ap-northeast-1|m6idn.2xlarge": 0.819000, + "ap-northeast-1|m6idn.32xlarge": 13.104000, + "ap-northeast-1|m6idn.4xlarge": 1.638000, + "ap-northeast-1|m6idn.8xlarge": 3.276000, + "ap-northeast-1|m6idn.large": 0.204750, + "ap-northeast-1|m6idn.metal": 13.104000, + "ap-northeast-1|m6idn.xlarge": 0.409500, + "ap-northeast-1|m6in.12xlarge": 4.296240, + "ap-northeast-1|m6in.16xlarge": 5.728320, + "ap-northeast-1|m6in.24xlarge": 8.592480, + "ap-northeast-1|m6in.2xlarge": 0.716040, + "ap-northeast-1|m6in.32xlarge": 11.456640, + "ap-northeast-1|m6in.4xlarge": 1.432080, + "ap-northeast-1|m6in.8xlarge": 2.864160, + "ap-northeast-1|m6in.large": 0.179010, + "ap-northeast-1|m6in.metal": 11.456640, + "ap-northeast-1|m6in.xlarge": 0.358020, + "ap-northeast-1|m7a.12xlarge": 3.593520, + "ap-northeast-1|m7a.16xlarge": 4.791360, + "ap-northeast-1|m7a.24xlarge": 7.187040, + "ap-northeast-1|m7a.2xlarge": 0.598920, + "ap-northeast-1|m7a.32xlarge": 9.582720, + "ap-northeast-1|m7a.48xlarge": 14.374080, + "ap-northeast-1|m7a.4xlarge": 1.197840, + "ap-northeast-1|m7a.8xlarge": 2.395680, + "ap-northeast-1|m7a.large": 0.149730, + "ap-northeast-1|m7a.medium": 0.074870, + "ap-northeast-1|m7a.metal-48xl": 14.374080, + "ap-northeast-1|m7a.xlarge": 0.299460, + "ap-northeast-1|m7g.12xlarge": 2.529600, + "ap-northeast-1|m7g.16xlarge": 3.372800, + "ap-northeast-1|m7g.2xlarge": 0.421600, + "ap-northeast-1|m7g.4xlarge": 0.843200, + "ap-northeast-1|m7g.8xlarge": 1.686400, + "ap-northeast-1|m7g.large": 0.105400, + "ap-northeast-1|m7g.medium": 0.052700, + "ap-northeast-1|m7g.metal": 3.372800, + "ap-northeast-1|m7g.xlarge": 0.210800, + "ap-northeast-1|m7gd.12xlarge": 3.311300, + "ap-northeast-1|m7gd.16xlarge": 4.415000, + "ap-northeast-1|m7gd.2xlarge": 0.551900, + "ap-northeast-1|m7gd.4xlarge": 1.103800, + "ap-northeast-1|m7gd.8xlarge": 2.207500, + "ap-northeast-1|m7gd.large": 0.138000, + "ap-northeast-1|m7gd.medium": 0.069000, + "ap-northeast-1|m7gd.metal": 4.415000, + "ap-northeast-1|m7gd.xlarge": 0.275900, + "ap-northeast-1|m7i-flex.12xlarge": 2.968560, + "ap-northeast-1|m7i-flex.16xlarge": 3.958080, + "ap-northeast-1|m7i-flex.2xlarge": 0.494760, + "ap-northeast-1|m7i-flex.4xlarge": 0.989520, + "ap-northeast-1|m7i-flex.8xlarge": 1.979040, + "ap-northeast-1|m7i-flex.large": 0.123690, + "ap-northeast-1|m7i-flex.xlarge": 0.247380, + "ap-northeast-1|m7i.12xlarge": 3.124800, + "ap-northeast-1|m7i.16xlarge": 4.166400, + "ap-northeast-1|m7i.24xlarge": 6.249600, + "ap-northeast-1|m7i.2xlarge": 0.520800, + "ap-northeast-1|m7i.48xlarge": 12.499200, + "ap-northeast-1|m7i.4xlarge": 1.041600, + "ap-northeast-1|m7i.8xlarge": 2.083200, + "ap-northeast-1|m7i.large": 0.130200, + "ap-northeast-1|m7i.metal-24xl": 6.249600, + "ap-northeast-1|m7i.metal-48xl": 12.499200, + "ap-northeast-1|m7i.xlarge": 0.260400, + "ap-northeast-1|m8a.12xlarge": 3.773280, + "ap-northeast-1|m8a.16xlarge": 5.031040, + "ap-northeast-1|m8a.24xlarge": 7.546560, + "ap-northeast-1|m8a.2xlarge": 0.628880, + "ap-northeast-1|m8a.48xlarge": 15.093120, + "ap-northeast-1|m8a.4xlarge": 1.257760, + "ap-northeast-1|m8a.8xlarge": 2.515520, + "ap-northeast-1|m8a.large": 0.157220, + "ap-northeast-1|m8a.medium": 0.078610, + "ap-northeast-1|m8a.metal-24xl": 7.546560, + "ap-northeast-1|m8a.metal-48xl": 15.093120, + "ap-northeast-1|m8a.xlarge": 0.314440, + "ap-northeast-1|m8g.12xlarge": 2.782560, + "ap-northeast-1|m8g.16xlarge": 3.710080, + "ap-northeast-1|m8g.24xlarge": 5.565120, + "ap-northeast-1|m8g.2xlarge": 0.463760, + "ap-northeast-1|m8g.48xlarge": 11.130240, + "ap-northeast-1|m8g.4xlarge": 0.927520, + "ap-northeast-1|m8g.8xlarge": 1.855040, + "ap-northeast-1|m8g.large": 0.115940, + "ap-northeast-1|m8g.medium": 0.057970, + "ap-northeast-1|m8g.metal-24xl": 5.565120, + "ap-northeast-1|m8g.metal-48xl": 11.130240, + "ap-northeast-1|m8g.xlarge": 0.231880, + "ap-northeast-1|m8gd.12xlarge": 3.576000, + "ap-northeast-1|m8gd.16xlarge": 4.768000, + "ap-northeast-1|m8gd.24xlarge": 7.152000, + "ap-northeast-1|m8gd.2xlarge": 0.596000, + "ap-northeast-1|m8gd.48xlarge": 14.304000, + "ap-northeast-1|m8gd.4xlarge": 1.192000, + "ap-northeast-1|m8gd.8xlarge": 2.384000, + "ap-northeast-1|m8gd.large": 0.149000, + "ap-northeast-1|m8gd.medium": 0.074500, + "ap-northeast-1|m8gd.metal-24xl": 7.152000, + "ap-northeast-1|m8gd.metal-48xl": 14.304000, + "ap-northeast-1|m8gd.xlarge": 0.298000, + "ap-northeast-1|m8i.12xlarge": 3.281040, + "ap-northeast-1|m8i.16xlarge": 4.374720, + "ap-northeast-1|m8i.24xlarge": 6.562080, + "ap-northeast-1|m8i.2xlarge": 0.546840, + "ap-northeast-1|m8i.32xlarge": 8.749440, + "ap-northeast-1|m8i.48xlarge": 13.124160, + "ap-northeast-1|m8i.4xlarge": 1.093680, + "ap-northeast-1|m8i.8xlarge": 2.187360, + "ap-northeast-1|m8i.96xlarge": 26.248320, + "ap-northeast-1|m8i.large": 0.136710, + "ap-northeast-1|m8i.metal-48xl": 13.124160, + "ap-northeast-1|m8i.metal-96xl": 26.248320, + "ap-northeast-1|m8i.xlarge": 0.273420, + "ap-northeast-1|p2.16xlarge": 24.672000, + "ap-northeast-1|p2.8xlarge": 12.336000, + "ap-northeast-1|p2.xlarge": 1.542000, + "ap-northeast-1|p3.16xlarge": 33.552000, + "ap-northeast-1|p3.2xlarge": 4.194000, + "ap-northeast-1|p3.8xlarge": 16.776000, + "ap-northeast-1|p3dn.24xlarge": 42.783000, + "ap-northeast-1|p4d.24xlarge": 30.097840, + "ap-northeast-1|p4de.24xlarge": 37.622300, + "ap-northeast-1|p5.48xlarge": 68.800000, + "ap-northeast-1|p5.4xlarge": 8.600000, + "ap-northeast-1|p5en.48xlarge": 79.120000, + "ap-northeast-1|r3.2xlarge": 0.798000, + "ap-northeast-1|r3.4xlarge": 1.596000, + "ap-northeast-1|r3.8xlarge": 3.192000, + "ap-northeast-1|r3.large": 0.200000, + "ap-northeast-1|r3.xlarge": 0.399000, + "ap-northeast-1|r4.16xlarge": 5.120000, + "ap-northeast-1|r4.2xlarge": 0.640000, + "ap-northeast-1|r4.4xlarge": 1.280000, + "ap-northeast-1|r4.8xlarge": 2.560000, + "ap-northeast-1|r4.large": 0.160000, + "ap-northeast-1|r4.xlarge": 0.320000, + "ap-northeast-1|r5.12xlarge": 3.648000, + "ap-northeast-1|r5.16xlarge": 4.864000, + "ap-northeast-1|r5.24xlarge": 7.296000, + "ap-northeast-1|r5.2xlarge": 0.608000, + "ap-northeast-1|r5.4xlarge": 1.216000, + "ap-northeast-1|r5.8xlarge": 2.432000, + "ap-northeast-1|r5.large": 0.152000, + "ap-northeast-1|r5.metal": 7.296000, + "ap-northeast-1|r5.xlarge": 0.304000, + "ap-northeast-1|r5a.12xlarge": 3.288000, + "ap-northeast-1|r5a.16xlarge": 4.384000, + "ap-northeast-1|r5a.24xlarge": 6.576000, + "ap-northeast-1|r5a.2xlarge": 0.548000, + "ap-northeast-1|r5a.4xlarge": 1.096000, + "ap-northeast-1|r5a.8xlarge": 2.192000, + "ap-northeast-1|r5a.large": 0.137000, + "ap-northeast-1|r5a.xlarge": 0.274000, + "ap-northeast-1|r5ad.12xlarge": 3.816000, + "ap-northeast-1|r5ad.16xlarge": 5.088000, + "ap-northeast-1|r5ad.24xlarge": 7.632000, + "ap-northeast-1|r5ad.2xlarge": 0.636000, + "ap-northeast-1|r5ad.4xlarge": 1.272000, + "ap-northeast-1|r5ad.8xlarge": 2.544000, + "ap-northeast-1|r5ad.large": 0.159000, + "ap-northeast-1|r5ad.xlarge": 0.318000, + "ap-northeast-1|r5b.12xlarge": 4.344000, + "ap-northeast-1|r5b.16xlarge": 5.792000, + "ap-northeast-1|r5b.24xlarge": 8.688000, + "ap-northeast-1|r5b.2xlarge": 0.724000, + "ap-northeast-1|r5b.4xlarge": 1.448000, + "ap-northeast-1|r5b.8xlarge": 2.896000, + "ap-northeast-1|r5b.large": 0.181000, + "ap-northeast-1|r5b.metal": 8.688000, + "ap-northeast-1|r5b.xlarge": 0.362000, + "ap-northeast-1|r5d.12xlarge": 4.176000, + "ap-northeast-1|r5d.16xlarge": 5.568000, + "ap-northeast-1|r5d.24xlarge": 8.352000, + "ap-northeast-1|r5d.2xlarge": 0.696000, + "ap-northeast-1|r5d.4xlarge": 1.392000, + "ap-northeast-1|r5d.8xlarge": 2.784000, + "ap-northeast-1|r5d.large": 0.174000, + "ap-northeast-1|r5d.metal": 8.352000, + "ap-northeast-1|r5d.xlarge": 0.348000, + "ap-northeast-1|r5dn.12xlarge": 4.872000, + "ap-northeast-1|r5dn.16xlarge": 6.496000, + "ap-northeast-1|r5dn.24xlarge": 9.744000, + "ap-northeast-1|r5dn.2xlarge": 0.812000, + "ap-northeast-1|r5dn.4xlarge": 1.624000, + "ap-northeast-1|r5dn.8xlarge": 3.248000, + "ap-northeast-1|r5dn.large": 0.203000, + "ap-northeast-1|r5dn.metal": 9.744000, + "ap-northeast-1|r5dn.xlarge": 0.406000, + "ap-northeast-1|r5n.12xlarge": 4.344000, + "ap-northeast-1|r5n.16xlarge": 5.792000, + "ap-northeast-1|r5n.24xlarge": 8.688000, + "ap-northeast-1|r5n.2xlarge": 0.724000, + "ap-northeast-1|r5n.4xlarge": 1.448000, + "ap-northeast-1|r5n.8xlarge": 2.896000, + "ap-northeast-1|r5n.large": 0.181000, + "ap-northeast-1|r5n.metal": 8.688000, + "ap-northeast-1|r5n.xlarge": 0.362000, + "ap-northeast-1|r6a.12xlarge": 3.283200, + "ap-northeast-1|r6a.16xlarge": 4.377600, + "ap-northeast-1|r6a.24xlarge": 6.566400, + "ap-northeast-1|r6a.2xlarge": 0.547200, + "ap-northeast-1|r6a.32xlarge": 8.755200, + "ap-northeast-1|r6a.48xlarge": 13.132800, + "ap-northeast-1|r6a.4xlarge": 1.094400, + "ap-northeast-1|r6a.8xlarge": 2.188800, + "ap-northeast-1|r6a.large": 0.136800, + "ap-northeast-1|r6a.metal": 13.132800, + "ap-northeast-1|r6a.xlarge": 0.273600, + "ap-northeast-1|r6g.12xlarge": 2.918400, + "ap-northeast-1|r6g.16xlarge": 3.891200, + "ap-northeast-1|r6g.2xlarge": 0.486400, + "ap-northeast-1|r6g.4xlarge": 0.972800, + "ap-northeast-1|r6g.8xlarge": 1.945600, + "ap-northeast-1|r6g.large": 0.121600, + "ap-northeast-1|r6g.medium": 0.060800, + "ap-northeast-1|r6g.metal": 3.891200, + "ap-northeast-1|r6g.xlarge": 0.243200, + "ap-northeast-1|r6gd.12xlarge": 3.336000, + "ap-northeast-1|r6gd.16xlarge": 4.448000, + "ap-northeast-1|r6gd.2xlarge": 0.556000, + "ap-northeast-1|r6gd.4xlarge": 1.112000, + "ap-northeast-1|r6gd.8xlarge": 2.224000, + "ap-northeast-1|r6gd.large": 0.139000, + "ap-northeast-1|r6gd.medium": 0.069500, + "ap-northeast-1|r6gd.metal": 4.448000, + "ap-northeast-1|r6gd.xlarge": 0.278000, + "ap-northeast-1|r6i.12xlarge": 3.648000, + "ap-northeast-1|r6i.16xlarge": 4.864000, + "ap-northeast-1|r6i.24xlarge": 7.296000, + "ap-northeast-1|r6i.2xlarge": 0.608000, + "ap-northeast-1|r6i.32xlarge": 9.728000, + "ap-northeast-1|r6i.4xlarge": 1.216000, + "ap-northeast-1|r6i.8xlarge": 2.432000, + "ap-northeast-1|r6i.large": 0.152000, + "ap-northeast-1|r6i.metal": 9.728000, + "ap-northeast-1|r6i.xlarge": 0.304000, + "ap-northeast-1|r6id.12xlarge": 4.384800, + "ap-northeast-1|r6id.16xlarge": 5.846400, + "ap-northeast-1|r6id.24xlarge": 8.769600, + "ap-northeast-1|r6id.2xlarge": 0.730800, + "ap-northeast-1|r6id.32xlarge": 11.692800, + "ap-northeast-1|r6id.4xlarge": 1.461600, + "ap-northeast-1|r6id.8xlarge": 2.923200, + "ap-northeast-1|r6id.large": 0.182700, + "ap-northeast-1|r6id.metal": 11.692800, + "ap-northeast-1|r6id.xlarge": 0.365400, + "ap-northeast-1|r6idn.12xlarge": 5.700240, + "ap-northeast-1|r6idn.16xlarge": 7.600320, + "ap-northeast-1|r6idn.24xlarge": 11.400480, + "ap-northeast-1|r6idn.2xlarge": 0.950040, + "ap-northeast-1|r6idn.32xlarge": 15.200640, + "ap-northeast-1|r6idn.4xlarge": 1.900080, + "ap-northeast-1|r6idn.8xlarge": 3.800160, + "ap-northeast-1|r6idn.large": 0.237510, + "ap-northeast-1|r6idn.metal": 15.200640, + "ap-northeast-1|r6idn.xlarge": 0.475020, + "ap-northeast-1|r6in.12xlarge": 5.082480, + "ap-northeast-1|r6in.16xlarge": 6.776640, + "ap-northeast-1|r6in.24xlarge": 10.164960, + "ap-northeast-1|r6in.2xlarge": 0.847080, + "ap-northeast-1|r6in.32xlarge": 13.553280, + "ap-northeast-1|r6in.4xlarge": 1.694160, + "ap-northeast-1|r6in.8xlarge": 3.388320, + "ap-northeast-1|r6in.large": 0.211770, + "ap-northeast-1|r6in.metal": 13.553280, + "ap-northeast-1|r6in.xlarge": 0.423540, + "ap-northeast-1|r7a.12xlarge": 4.404960, + "ap-northeast-1|r7a.16xlarge": 5.873280, + "ap-northeast-1|r7a.24xlarge": 8.809920, + "ap-northeast-1|r7a.2xlarge": 0.734160, + "ap-northeast-1|r7a.32xlarge": 11.746560, + "ap-northeast-1|r7a.48xlarge": 17.619840, + "ap-northeast-1|r7a.4xlarge": 1.468320, + "ap-northeast-1|r7a.8xlarge": 2.936640, + "ap-northeast-1|r7a.large": 0.183540, + "ap-northeast-1|r7a.medium": 0.091770, + "ap-northeast-1|r7a.metal-48xl": 17.619840, + "ap-northeast-1|r7a.xlarge": 0.367080, + "ap-northeast-1|r7g.12xlarge": 3.100800, + "ap-northeast-1|r7g.16xlarge": 4.134400, + "ap-northeast-1|r7g.2xlarge": 0.516800, + "ap-northeast-1|r7g.4xlarge": 1.033600, + "ap-northeast-1|r7g.8xlarge": 2.067200, + "ap-northeast-1|r7g.large": 0.129200, + "ap-northeast-1|r7g.medium": 0.064600, + "ap-northeast-1|r7g.metal": 4.134400, + "ap-northeast-1|r7g.xlarge": 0.258400, + "ap-northeast-1|r7gd.12xlarge": 3.946300, + "ap-northeast-1|r7gd.16xlarge": 5.261800, + "ap-northeast-1|r7gd.2xlarge": 0.657700, + "ap-northeast-1|r7gd.4xlarge": 1.315400, + "ap-northeast-1|r7gd.8xlarge": 2.630900, + "ap-northeast-1|r7gd.large": 0.164400, + "ap-northeast-1|r7gd.medium": 0.082200, + "ap-northeast-1|r7gd.metal": 5.261800, + "ap-northeast-1|r7gd.xlarge": 0.328900, + "ap-northeast-1|r7i.12xlarge": 3.830400, + "ap-northeast-1|r7i.16xlarge": 5.107200, + "ap-northeast-1|r7i.24xlarge": 7.660800, + "ap-northeast-1|r7i.2xlarge": 0.638400, + "ap-northeast-1|r7i.48xlarge": 15.321600, + "ap-northeast-1|r7i.4xlarge": 1.276800, + "ap-northeast-1|r7i.8xlarge": 2.553600, + "ap-northeast-1|r7i.large": 0.159600, + "ap-northeast-1|r7i.metal-24xl": 7.660800, + "ap-northeast-1|r7i.metal-48xl": 15.321600, + "ap-northeast-1|r7i.xlarge": 0.319200, + "ap-northeast-1|r7iz.12xlarge": 5.448000, + "ap-northeast-1|r7iz.16xlarge": 7.264000, + "ap-northeast-1|r7iz.2xlarge": 0.908000, + "ap-northeast-1|r7iz.32xlarge": 14.528000, + "ap-northeast-1|r7iz.4xlarge": 1.816000, + "ap-northeast-1|r7iz.8xlarge": 3.632000, + "ap-northeast-1|r7iz.large": 0.227000, + "ap-northeast-1|r7iz.metal-16xl": 7.264000, + "ap-northeast-1|r7iz.metal-32xl": 14.528000, + "ap-northeast-1|r7iz.xlarge": 0.454000, + "ap-northeast-1|r8g.12xlarge": 3.410880, + "ap-northeast-1|r8g.16xlarge": 4.547840, + "ap-northeast-1|r8g.24xlarge": 6.821760, + "ap-northeast-1|r8g.2xlarge": 0.568480, + "ap-northeast-1|r8g.48xlarge": 13.643520, + "ap-northeast-1|r8g.4xlarge": 1.136960, + "ap-northeast-1|r8g.8xlarge": 2.273920, + "ap-northeast-1|r8g.large": 0.142120, + "ap-northeast-1|r8g.medium": 0.071060, + "ap-northeast-1|r8g.metal-24xl": 6.821760, + "ap-northeast-1|r8g.metal-48xl": 13.643520, + "ap-northeast-1|r8g.xlarge": 0.284240, + "ap-northeast-1|r8gd.12xlarge": 4.261920, + "ap-northeast-1|r8gd.16xlarge": 5.682560, + "ap-northeast-1|r8gd.24xlarge": 8.523840, + "ap-northeast-1|r8gd.2xlarge": 0.710320, + "ap-northeast-1|r8gd.48xlarge": 17.047680, + "ap-northeast-1|r8gd.4xlarge": 1.420640, + "ap-northeast-1|r8gd.8xlarge": 2.841280, + "ap-northeast-1|r8gd.large": 0.177580, + "ap-northeast-1|r8gd.medium": 0.088790, + "ap-northeast-1|r8gd.metal-24xl": 8.523840, + "ap-northeast-1|r8gd.metal-48xl": 17.047680, + "ap-northeast-1|r8gd.xlarge": 0.355160, + "ap-northeast-1|r8i-flex.12xlarge": 3.820800, + "ap-northeast-1|r8i-flex.16xlarge": 5.094400, + "ap-northeast-1|r8i-flex.2xlarge": 0.636800, + "ap-northeast-1|r8i-flex.4xlarge": 1.273600, + "ap-northeast-1|r8i-flex.8xlarge": 2.547200, + "ap-northeast-1|r8i-flex.large": 0.159200, + "ap-northeast-1|r8i-flex.xlarge": 0.318400, + "ap-northeast-1|r8i.12xlarge": 4.021920, + "ap-northeast-1|r8i.16xlarge": 5.362560, + "ap-northeast-1|r8i.24xlarge": 8.043840, + "ap-northeast-1|r8i.2xlarge": 0.670320, + "ap-northeast-1|r8i.32xlarge": 10.725120, + "ap-northeast-1|r8i.48xlarge": 16.087680, + "ap-northeast-1|r8i.4xlarge": 1.340640, + "ap-northeast-1|r8i.8xlarge": 2.681280, + "ap-northeast-1|r8i.96xlarge": 32.175360, + "ap-northeast-1|r8i.large": 0.167580, + "ap-northeast-1|r8i.metal-48xl": 16.087680, + "ap-northeast-1|r8i.metal-96xl": 32.175360, + "ap-northeast-1|r8i.xlarge": 0.335160, + "ap-northeast-1|t1.micro": 0.026000, + "ap-northeast-1|t2.2xlarge": 0.486400, + "ap-northeast-1|t2.large": 0.121600, + "ap-northeast-1|t2.medium": 0.060800, + "ap-northeast-1|t2.micro": 0.015200, + "ap-northeast-1|t2.nano": 0.007600, + "ap-northeast-1|t2.small": 0.030400, + "ap-northeast-1|t2.xlarge": 0.243200, + "ap-northeast-1|t3.2xlarge": 0.435200, + "ap-northeast-1|t3.large": 0.108800, + "ap-northeast-1|t3.medium": 0.054400, + "ap-northeast-1|t3.micro": 0.013600, + "ap-northeast-1|t3.nano": 0.006800, + "ap-northeast-1|t3.small": 0.027200, + "ap-northeast-1|t3.xlarge": 0.217600, + "ap-northeast-1|t3a.2xlarge": 0.391700, + "ap-northeast-1|t3a.large": 0.097900, + "ap-northeast-1|t3a.medium": 0.049000, + "ap-northeast-1|t3a.micro": 0.012200, + "ap-northeast-1|t3a.nano": 0.006100, + "ap-northeast-1|t3a.small": 0.024500, + "ap-northeast-1|t3a.xlarge": 0.195800, + "ap-northeast-1|t4g.2xlarge": 0.345600, + "ap-northeast-1|t4g.large": 0.086400, + "ap-northeast-1|t4g.medium": 0.043200, + "ap-northeast-1|t4g.micro": 0.010800, + "ap-northeast-1|t4g.nano": 0.005400, + "ap-northeast-1|t4g.small": 0.021600, + "ap-northeast-1|t4g.xlarge": 0.172800, + "ap-northeast-1|u-12tb1.112xlarge": 131.733000, + "ap-northeast-1|u-3tb1.56xlarge": 32.933300, + "ap-northeast-1|u-6tb1.112xlarge": 65.867000, + "ap-northeast-1|u-6tb1.56xlarge": 55.979600, + "ap-northeast-1|u-9tb1.112xlarge": 98.800000, + "ap-northeast-1|u7i-6tb.112xlarge": 75.747050, + "ap-northeast-1|vt1.24xlarge": 6.545880, + "ap-northeast-1|vt1.3xlarge": 0.818240, + "ap-northeast-1|vt1.6xlarge": 1.636470, + "ap-northeast-1|x1.16xlarge": 9.671000, + "ap-northeast-1|x1.32xlarge": 19.341000, + "ap-northeast-1|x1e.16xlarge": 19.344000, + "ap-northeast-1|x1e.2xlarge": 2.418000, + "ap-northeast-1|x1e.32xlarge": 38.688000, + "ap-northeast-1|x1e.4xlarge": 4.836000, + "ap-northeast-1|x1e.8xlarge": 9.672000, + "ap-northeast-1|x1e.xlarge": 1.209000, + "ap-northeast-1|x2idn.16xlarge": 9.670500, + "ap-northeast-1|x2idn.24xlarge": 14.505750, + "ap-northeast-1|x2idn.32xlarge": 19.341000, + "ap-northeast-1|x2idn.metal": 19.341000, + "ap-northeast-1|x2iedn.16xlarge": 19.341000, + "ap-northeast-1|x2iedn.24xlarge": 29.011500, + "ap-northeast-1|x2iedn.2xlarge": 2.417630, + "ap-northeast-1|x2iedn.32xlarge": 38.682000, + "ap-northeast-1|x2iedn.4xlarge": 4.835250, + "ap-northeast-1|x2iedn.8xlarge": 9.670500, + "ap-northeast-1|x2iedn.metal": 38.682000, + "ap-northeast-1|x2iedn.xlarge": 1.208810, + "ap-northeast-1|x2iezn.12xlarge": 14.508000, + "ap-northeast-1|x2iezn.2xlarge": 2.418000, + "ap-northeast-1|x2iezn.4xlarge": 4.836000, + "ap-northeast-1|x2iezn.6xlarge": 7.254000, + "ap-northeast-1|x2iezn.8xlarge": 9.672000, + "ap-northeast-1|x2iezn.metal": 14.508000, + "ap-northeast-1|x8aedz.12xlarge": 20.020560, + "ap-northeast-1|x8aedz.24xlarge": 40.041120, + "ap-northeast-1|x8aedz.3xlarge": 5.005140, + "ap-northeast-1|x8aedz.6xlarge": 10.010280, + "ap-northeast-1|x8aedz.large": 0.834190, + "ap-northeast-1|x8aedz.metal-12xl": 20.020560, + "ap-northeast-1|x8aedz.metal-24xl": 40.041120, + "ap-northeast-1|x8aedz.xlarge": 1.668380, + "ap-northeast-1|z1d.12xlarge": 5.448000, + "ap-northeast-1|z1d.2xlarge": 0.908000, + "ap-northeast-1|z1d.3xlarge": 1.362000, + "ap-northeast-1|z1d.6xlarge": 2.724000, + "ap-northeast-1|z1d.large": 0.227000, + "ap-northeast-1|z1d.metal": 5.448000, + "ap-northeast-1|z1d.xlarge": 0.454000, + "ap-northeast-2|c3.2xlarge": 0.460000, + "ap-northeast-2|c3.4xlarge": 0.919000, + "ap-northeast-2|c3.8xlarge": 1.839000, + "ap-northeast-2|c3.large": 0.115000, + "ap-northeast-2|c3.xlarge": 0.230000, + "ap-northeast-2|c4.2xlarge": 0.454000, + "ap-northeast-2|c4.4xlarge": 0.907000, + "ap-northeast-2|c4.8xlarge": 1.815000, + "ap-northeast-2|c4.large": 0.114000, + "ap-northeast-2|c4.xlarge": 0.227000, + "ap-northeast-2|c5.12xlarge": 2.304000, + "ap-northeast-2|c5.18xlarge": 3.456000, + "ap-northeast-2|c5.24xlarge": 4.608000, + "ap-northeast-2|c5.2xlarge": 0.384000, + "ap-northeast-2|c5.4xlarge": 0.768000, + "ap-northeast-2|c5.9xlarge": 1.728000, + "ap-northeast-2|c5.large": 0.096000, + "ap-northeast-2|c5.metal": 4.608000, + "ap-northeast-2|c5.xlarge": 0.192000, + "ap-northeast-2|c5a.12xlarge": 2.064000, + "ap-northeast-2|c5a.16xlarge": 2.752000, + "ap-northeast-2|c5a.24xlarge": 4.128000, + "ap-northeast-2|c5a.2xlarge": 0.344000, + "ap-northeast-2|c5a.4xlarge": 0.688000, + "ap-northeast-2|c5a.8xlarge": 1.376000, + "ap-northeast-2|c5a.large": 0.086000, + "ap-northeast-2|c5a.xlarge": 0.172000, + "ap-northeast-2|c5d.12xlarge": 2.640000, + "ap-northeast-2|c5d.18xlarge": 3.960000, + "ap-northeast-2|c5d.24xlarge": 5.280000, + "ap-northeast-2|c5d.2xlarge": 0.440000, + "ap-northeast-2|c5d.4xlarge": 0.880000, + "ap-northeast-2|c5d.9xlarge": 1.980000, + "ap-northeast-2|c5d.large": 0.110000, + "ap-northeast-2|c5d.metal": 5.280000, + "ap-northeast-2|c5d.xlarge": 0.220000, + "ap-northeast-2|c5n.18xlarge": 4.392000, + "ap-northeast-2|c5n.2xlarge": 0.488000, + "ap-northeast-2|c5n.4xlarge": 0.976000, + "ap-northeast-2|c5n.9xlarge": 2.196000, + "ap-northeast-2|c5n.large": 0.122000, + "ap-northeast-2|c5n.metal": 4.392000, + "ap-northeast-2|c5n.xlarge": 0.244000, + "ap-northeast-2|c6g.12xlarge": 1.848000, + "ap-northeast-2|c6g.16xlarge": 2.464000, + "ap-northeast-2|c6g.2xlarge": 0.308000, + "ap-northeast-2|c6g.4xlarge": 0.616000, + "ap-northeast-2|c6g.8xlarge": 1.232000, + "ap-northeast-2|c6g.large": 0.077000, + "ap-northeast-2|c6g.medium": 0.038500, + "ap-northeast-2|c6g.metal": 2.464000, + "ap-northeast-2|c6g.xlarge": 0.154000, + "ap-northeast-2|c6gd.12xlarge": 2.112000, + "ap-northeast-2|c6gd.16xlarge": 2.816000, + "ap-northeast-2|c6gd.2xlarge": 0.352000, + "ap-northeast-2|c6gd.4xlarge": 0.704000, + "ap-northeast-2|c6gd.8xlarge": 1.408000, + "ap-northeast-2|c6gd.large": 0.088000, + "ap-northeast-2|c6gd.medium": 0.044000, + "ap-northeast-2|c6gd.metal": 2.816000, + "ap-northeast-2|c6gd.xlarge": 0.176000, + "ap-northeast-2|c6gn.12xlarge": 2.340000, + "ap-northeast-2|c6gn.16xlarge": 3.120000, + "ap-northeast-2|c6gn.2xlarge": 0.390000, + "ap-northeast-2|c6gn.4xlarge": 0.780000, + "ap-northeast-2|c6gn.8xlarge": 1.560000, + "ap-northeast-2|c6gn.large": 0.097500, + "ap-northeast-2|c6gn.medium": 0.048750, + "ap-northeast-2|c6gn.xlarge": 0.195000, + "ap-northeast-2|c6i.12xlarge": 2.304000, + "ap-northeast-2|c6i.16xlarge": 3.072000, + "ap-northeast-2|c6i.24xlarge": 4.608000, + "ap-northeast-2|c6i.2xlarge": 0.384000, + "ap-northeast-2|c6i.32xlarge": 6.144000, + "ap-northeast-2|c6i.4xlarge": 0.768000, + "ap-northeast-2|c6i.8xlarge": 1.536000, + "ap-northeast-2|c6i.large": 0.096000, + "ap-northeast-2|c6i.metal": 6.144000, + "ap-northeast-2|c6i.xlarge": 0.192000, + "ap-northeast-2|c6id.12xlarge": 2.772000, + "ap-northeast-2|c6id.16xlarge": 3.696000, + "ap-northeast-2|c6id.24xlarge": 5.544000, + "ap-northeast-2|c6id.2xlarge": 0.462000, + "ap-northeast-2|c6id.32xlarge": 7.392000, + "ap-northeast-2|c6id.4xlarge": 0.924000, + "ap-northeast-2|c6id.8xlarge": 1.848000, + "ap-northeast-2|c6id.large": 0.115500, + "ap-northeast-2|c6id.metal": 7.392000, + "ap-northeast-2|c6id.xlarge": 0.231000, + "ap-northeast-2|c6in.12xlarge": 3.074400, + "ap-northeast-2|c6in.16xlarge": 4.099200, + "ap-northeast-2|c6in.24xlarge": 6.148800, + "ap-northeast-2|c6in.2xlarge": 0.512400, + "ap-northeast-2|c6in.32xlarge": 8.198400, + "ap-northeast-2|c6in.4xlarge": 1.024800, + "ap-northeast-2|c6in.8xlarge": 2.049600, + "ap-northeast-2|c6in.large": 0.128100, + "ap-northeast-2|c6in.metal": 8.198400, + "ap-northeast-2|c6in.xlarge": 0.256200, + "ap-northeast-2|c7g.12xlarge": 1.958400, + "ap-northeast-2|c7g.16xlarge": 2.611200, + "ap-northeast-2|c7g.2xlarge": 0.326400, + "ap-northeast-2|c7g.4xlarge": 0.652800, + "ap-northeast-2|c7g.8xlarge": 1.305600, + "ap-northeast-2|c7g.large": 0.081600, + "ap-northeast-2|c7g.medium": 0.040800, + "ap-northeast-2|c7g.metal": 2.611200, + "ap-northeast-2|c7g.xlarge": 0.163200, + "ap-northeast-2|c7gd.12xlarge": 2.495000, + "ap-northeast-2|c7gd.16xlarge": 3.326700, + "ap-northeast-2|c7gd.2xlarge": 0.415800, + "ap-northeast-2|c7gd.4xlarge": 0.831700, + "ap-northeast-2|c7gd.8xlarge": 1.663400, + "ap-northeast-2|c7gd.large": 0.104000, + "ap-northeast-2|c7gd.medium": 0.052000, + "ap-northeast-2|c7gd.metal": 3.326700, + "ap-northeast-2|c7gd.xlarge": 0.207900, + "ap-northeast-2|c7i-flex.12xlarge": 2.298240, + "ap-northeast-2|c7i-flex.16xlarge": 3.064320, + "ap-northeast-2|c7i-flex.2xlarge": 0.383040, + "ap-northeast-2|c7i-flex.4xlarge": 0.766080, + "ap-northeast-2|c7i-flex.8xlarge": 1.532160, + "ap-northeast-2|c7i-flex.large": 0.095760, + "ap-northeast-2|c7i-flex.xlarge": 0.191520, + "ap-northeast-2|c7i.12xlarge": 2.419200, + "ap-northeast-2|c7i.16xlarge": 3.225600, + "ap-northeast-2|c7i.24xlarge": 4.838400, + "ap-northeast-2|c7i.2xlarge": 0.403200, + "ap-northeast-2|c7i.48xlarge": 9.676800, + "ap-northeast-2|c7i.4xlarge": 0.806400, + "ap-northeast-2|c7i.8xlarge": 1.612800, + "ap-northeast-2|c7i.large": 0.100800, + "ap-northeast-2|c7i.metal-24xl": 4.838400, + "ap-northeast-2|c7i.metal-48xl": 9.676800, + "ap-northeast-2|c7i.xlarge": 0.201600, + "ap-northeast-2|c8g.12xlarge": 2.154240, + "ap-northeast-2|c8g.16xlarge": 2.872320, + "ap-northeast-2|c8g.24xlarge": 4.308480, + "ap-northeast-2|c8g.2xlarge": 0.359040, + "ap-northeast-2|c8g.48xlarge": 8.616960, + "ap-northeast-2|c8g.4xlarge": 0.718080, + "ap-northeast-2|c8g.8xlarge": 1.436160, + "ap-northeast-2|c8g.large": 0.089760, + "ap-northeast-2|c8g.medium": 0.044880, + "ap-northeast-2|c8g.metal-24xl": 4.308480, + "ap-northeast-2|c8g.metal-48xl": 8.616960, + "ap-northeast-2|c8g.xlarge": 0.179520, + "ap-northeast-2|c8i-flex.12xlarge": 2.413200, + "ap-northeast-2|c8i-flex.16xlarge": 3.217600, + "ap-northeast-2|c8i-flex.2xlarge": 0.402200, + "ap-northeast-2|c8i-flex.4xlarge": 0.804400, + "ap-northeast-2|c8i-flex.8xlarge": 1.608800, + "ap-northeast-2|c8i-flex.large": 0.100550, + "ap-northeast-2|c8i-flex.xlarge": 0.201100, + "ap-northeast-2|c8i.12xlarge": 2.540160, + "ap-northeast-2|c8i.16xlarge": 3.386880, + "ap-northeast-2|c8i.24xlarge": 5.080320, + "ap-northeast-2|c8i.2xlarge": 0.423360, + "ap-northeast-2|c8i.32xlarge": 6.773760, + "ap-northeast-2|c8i.48xlarge": 10.160640, + "ap-northeast-2|c8i.4xlarge": 0.846720, + "ap-northeast-2|c8i.8xlarge": 1.693440, + "ap-northeast-2|c8i.96xlarge": 20.321280, + "ap-northeast-2|c8i.large": 0.105840, + "ap-northeast-2|c8i.metal-48xl": 10.160640, + "ap-northeast-2|c8i.metal-96xl": 20.321280, + "ap-northeast-2|c8i.xlarge": 0.211680, + "ap-northeast-2|d2.2xlarge": 1.688000, + "ap-northeast-2|d2.4xlarge": 3.376000, + "ap-northeast-2|d2.8xlarge": 6.752000, + "ap-northeast-2|d2.xlarge": 0.844000, + "ap-northeast-2|f2.12xlarge": 4.752000, + "ap-northeast-2|f2.48xlarge": 19.008000, + "ap-northeast-2|f2.6xlarge": 2.376000, + "ap-northeast-2|g2.2xlarge": 0.898000, + "ap-northeast-2|g2.8xlarge": 3.592000, + "ap-northeast-2|g3.16xlarge": 5.680000, + "ap-northeast-2|g3.4xlarge": 1.420000, + "ap-northeast-2|g3.8xlarge": 2.840000, + "ap-northeast-2|g3s.xlarge": 0.934000, + "ap-northeast-2|g4dn.12xlarge": 4.812000, + "ap-northeast-2|g4dn.16xlarge": 5.353000, + "ap-northeast-2|g4dn.2xlarge": 0.925000, + "ap-northeast-2|g4dn.4xlarge": 1.481000, + "ap-northeast-2|g4dn.8xlarge": 2.677000, + "ap-northeast-2|g4dn.metal": 9.624000, + "ap-northeast-2|g4dn.xlarge": 0.647000, + "ap-northeast-2|g5.12xlarge": 6.974420, + "ap-northeast-2|g5.16xlarge": 5.036530, + "ap-northeast-2|g5.24xlarge": 10.014040, + "ap-northeast-2|g5.2xlarge": 1.490300, + "ap-northeast-2|g5.48xlarge": 20.028090, + "ap-northeast-2|g5.4xlarge": 1.996910, + "ap-northeast-2|g5.8xlarge": 3.010120, + "ap-northeast-2|g5.xlarge": 1.237000, + "ap-northeast-2|g5g.16xlarge": 3.375200, + "ap-northeast-2|g5g.2xlarge": 0.683900, + "ap-northeast-2|g5g.4xlarge": 1.018500, + "ap-northeast-2|g5g.8xlarge": 1.687600, + "ap-northeast-2|g5g.metal": 3.375200, + "ap-northeast-2|g5g.xlarge": 0.516600, + "ap-northeast-2|g6.12xlarge": 5.658230, + "ap-northeast-2|g6.16xlarge": 4.176780, + "ap-northeast-2|g6.24xlarge": 8.207970, + "ap-northeast-2|g6.2xlarge": 1.202080, + "ap-northeast-2|g6.48xlarge": 16.415950, + "ap-northeast-2|g6.4xlarge": 1.627040, + "ap-northeast-2|g6.8xlarge": 2.476950, + "ap-northeast-2|g6.xlarge": 0.989600, + "ap-northeast-2|g6e.12xlarge": 12.900140, + "ap-northeast-2|g6e.16xlarge": 9.315750, + "ap-northeast-2|g6e.24xlarge": 18.522340, + "ap-northeast-2|g6e.2xlarge": 2.756520, + "ap-northeast-2|g6e.48xlarge": 37.044680, + "ap-northeast-2|g6e.4xlarge": 3.693550, + "ap-northeast-2|g6e.8xlarge": 5.567620, + "ap-northeast-2|g6e.xlarge": 2.288000, + "ap-northeast-2|g6f.2xlarge": 0.584060, + "ap-northeast-2|g6f.4xlarge": 1.168120, + "ap-northeast-2|g6f.large": 0.248380, + "ap-northeast-2|g6f.xlarge": 0.292030, + "ap-northeast-2|gr6.4xlarge": 1.892600, + "ap-northeast-2|gr6.8xlarge": 3.008090, + "ap-northeast-2|gr6f.4xlarge": 1.310750, + "ap-northeast-2|i2.2xlarge": 2.001000, + "ap-northeast-2|i2.4xlarge": 4.002000, + "ap-northeast-2|i2.8xlarge": 8.004000, + "ap-northeast-2|i2.xlarge": 1.001000, + "ap-northeast-2|i3.16xlarge": 5.856000, + "ap-northeast-2|i3.2xlarge": 0.732000, + "ap-northeast-2|i3.4xlarge": 1.464000, + "ap-northeast-2|i3.8xlarge": 2.928000, + "ap-northeast-2|i3.large": 0.183000, + "ap-northeast-2|i3.metal": 5.856000, + "ap-northeast-2|i3.xlarge": 0.366000, + "ap-northeast-2|i3en.12xlarge": 6.384000, + "ap-northeast-2|i3en.24xlarge": 12.768000, + "ap-northeast-2|i3en.2xlarge": 1.064000, + "ap-northeast-2|i3en.3xlarge": 1.596000, + "ap-northeast-2|i3en.6xlarge": 3.192000, + "ap-northeast-2|i3en.large": 0.266000, + "ap-northeast-2|i3en.metal": 12.768000, + "ap-northeast-2|i3en.xlarge": 0.532000, + "ap-northeast-2|i4i.12xlarge": 4.831000, + "ap-northeast-2|i4i.16xlarge": 6.442000, + "ap-northeast-2|i4i.24xlarge": 9.662400, + "ap-northeast-2|i4i.2xlarge": 0.805000, + "ap-northeast-2|i4i.32xlarge": 12.883200, + "ap-northeast-2|i4i.4xlarge": 1.610000, + "ap-northeast-2|i4i.8xlarge": 3.221000, + "ap-northeast-2|i4i.large": 0.201000, + "ap-northeast-2|i4i.metal": 12.883000, + "ap-northeast-2|i4i.xlarge": 0.403000, + "ap-northeast-2|i7i.12xlarge": 5.314300, + "ap-northeast-2|i7i.16xlarge": 7.085800, + "ap-northeast-2|i7i.24xlarge": 10.628600, + "ap-northeast-2|i7i.2xlarge": 0.885700, + "ap-northeast-2|i7i.48xlarge": 21.257300, + "ap-northeast-2|i7i.4xlarge": 1.771400, + "ap-northeast-2|i7i.8xlarge": 3.542900, + "ap-northeast-2|i7i.large": 0.221400, + "ap-northeast-2|i7i.metal-24xl": 10.628600, + "ap-northeast-2|i7i.metal-48xl": 21.257300, + "ap-northeast-2|i7i.xlarge": 0.442900, + "ap-northeast-2|i8g.12xlarge": 4.831200, + "ap-northeast-2|i8g.16xlarge": 6.441600, + "ap-northeast-2|i8g.24xlarge": 9.662400, + "ap-northeast-2|i8g.2xlarge": 0.805200, + "ap-northeast-2|i8g.48xlarge": 19.324800, + "ap-northeast-2|i8g.4xlarge": 1.610400, + "ap-northeast-2|i8g.8xlarge": 3.220800, + "ap-northeast-2|i8g.large": 0.201300, + "ap-northeast-2|i8g.metal-24xl": 9.662400, + "ap-northeast-2|i8g.xlarge": 0.402600, + "ap-northeast-2|inf1.24xlarge": 5.812000, + "ap-northeast-2|inf1.2xlarge": 0.446000, + "ap-northeast-2|inf1.6xlarge": 1.453000, + "ap-northeast-2|inf1.xlarge": 0.281000, + "ap-northeast-2|inf2.xlarge": 0.909840, + "ap-northeast-2|m3.2xlarge": 0.732000, + "ap-northeast-2|m3.large": 0.183000, + "ap-northeast-2|m3.medium": 0.091000, + "ap-northeast-2|m3.xlarge": 0.366000, + "ap-northeast-2|m4.10xlarge": 2.460000, + "ap-northeast-2|m4.16xlarge": 3.936000, + "ap-northeast-2|m4.2xlarge": 0.492000, + "ap-northeast-2|m4.4xlarge": 0.984000, + "ap-northeast-2|m4.large": 0.123000, + "ap-northeast-2|m4.xlarge": 0.246000, + "ap-northeast-2|m5.12xlarge": 2.832000, + "ap-northeast-2|m5.16xlarge": 3.776000, + "ap-northeast-2|m5.24xlarge": 5.664000, + "ap-northeast-2|m5.2xlarge": 0.472000, + "ap-northeast-2|m5.4xlarge": 0.944000, + "ap-northeast-2|m5.8xlarge": 1.888000, + "ap-northeast-2|m5.large": 0.118000, + "ap-northeast-2|m5.metal": 5.664000, + "ap-northeast-2|m5.xlarge": 0.236000, + "ap-northeast-2|m5a.12xlarge": 2.544000, + "ap-northeast-2|m5a.16xlarge": 3.392000, + "ap-northeast-2|m5a.24xlarge": 5.088000, + "ap-northeast-2|m5a.2xlarge": 0.424000, + "ap-northeast-2|m5a.4xlarge": 0.848000, + "ap-northeast-2|m5a.8xlarge": 1.696000, + "ap-northeast-2|m5a.large": 0.106000, + "ap-northeast-2|m5a.xlarge": 0.212000, + "ap-northeast-2|m5ad.12xlarge": 3.048000, + "ap-northeast-2|m5ad.16xlarge": 4.064000, + "ap-northeast-2|m5ad.24xlarge": 6.096000, + "ap-northeast-2|m5ad.2xlarge": 0.508000, + "ap-northeast-2|m5ad.4xlarge": 1.016000, + "ap-northeast-2|m5ad.8xlarge": 2.032000, + "ap-northeast-2|m5ad.large": 0.127000, + "ap-northeast-2|m5ad.xlarge": 0.254000, + "ap-northeast-2|m5d.12xlarge": 3.336000, + "ap-northeast-2|m5d.16xlarge": 4.448000, + "ap-northeast-2|m5d.24xlarge": 6.672000, + "ap-northeast-2|m5d.2xlarge": 0.556000, + "ap-northeast-2|m5d.4xlarge": 1.112000, + "ap-northeast-2|m5d.8xlarge": 2.224000, + "ap-northeast-2|m5d.large": 0.139000, + "ap-northeast-2|m5d.metal": 6.672000, + "ap-northeast-2|m5d.xlarge": 0.278000, + "ap-northeast-2|m5zn.12xlarge": 4.872000, + "ap-northeast-2|m5zn.2xlarge": 0.812000, + "ap-northeast-2|m5zn.3xlarge": 1.218000, + "ap-northeast-2|m5zn.6xlarge": 2.436000, + "ap-northeast-2|m5zn.large": 0.203000, + "ap-northeast-2|m5zn.metal": 4.872000, + "ap-northeast-2|m5zn.xlarge": 0.406000, + "ap-northeast-2|m6g.12xlarge": 2.256000, + "ap-northeast-2|m6g.16xlarge": 3.008000, + "ap-northeast-2|m6g.2xlarge": 0.376000, + "ap-northeast-2|m6g.4xlarge": 0.752000, + "ap-northeast-2|m6g.8xlarge": 1.504000, + "ap-northeast-2|m6g.large": 0.094000, + "ap-northeast-2|m6g.medium": 0.047000, + "ap-northeast-2|m6g.metal": 3.008000, + "ap-northeast-2|m6g.xlarge": 0.188000, + "ap-northeast-2|m6gd.12xlarge": 2.668800, + "ap-northeast-2|m6gd.16xlarge": 3.558400, + "ap-northeast-2|m6gd.2xlarge": 0.444800, + "ap-northeast-2|m6gd.4xlarge": 0.889600, + "ap-northeast-2|m6gd.8xlarge": 1.779200, + "ap-northeast-2|m6gd.large": 0.111200, + "ap-northeast-2|m6gd.medium": 0.055600, + "ap-northeast-2|m6gd.metal": 3.558400, + "ap-northeast-2|m6gd.xlarge": 0.222400, + "ap-northeast-2|m6i.12xlarge": 2.832000, + "ap-northeast-2|m6i.16xlarge": 3.776000, + "ap-northeast-2|m6i.24xlarge": 5.664000, + "ap-northeast-2|m6i.2xlarge": 0.472000, + "ap-northeast-2|m6i.32xlarge": 7.552000, + "ap-northeast-2|m6i.4xlarge": 0.944000, + "ap-northeast-2|m6i.8xlarge": 1.888000, + "ap-northeast-2|m6i.large": 0.118000, + "ap-northeast-2|m6i.metal": 7.552000, + "ap-northeast-2|m6i.xlarge": 0.236000, + "ap-northeast-2|m6id.12xlarge": 3.502800, + "ap-northeast-2|m6id.16xlarge": 4.670400, + "ap-northeast-2|m6id.24xlarge": 7.005600, + "ap-northeast-2|m6id.2xlarge": 0.583800, + "ap-northeast-2|m6id.32xlarge": 9.340800, + "ap-northeast-2|m6id.4xlarge": 1.167600, + "ap-northeast-2|m6id.8xlarge": 2.335200, + "ap-northeast-2|m6id.large": 0.145950, + "ap-northeast-2|m6id.metal": 9.340800, + "ap-northeast-2|m6id.xlarge": 0.291900, + "ap-northeast-2|m6idn.12xlarge": 4.633200, + "ap-northeast-2|m6idn.16xlarge": 6.177600, + "ap-northeast-2|m6idn.24xlarge": 9.266400, + "ap-northeast-2|m6idn.2xlarge": 0.772200, + "ap-northeast-2|m6idn.32xlarge": 12.355200, + "ap-northeast-2|m6idn.4xlarge": 1.544400, + "ap-northeast-2|m6idn.8xlarge": 3.088800, + "ap-northeast-2|m6idn.large": 0.193050, + "ap-northeast-2|m6idn.metal": 12.355200, + "ap-northeast-2|m6idn.xlarge": 0.386100, + "ap-northeast-2|m6in.12xlarge": 4.043520, + "ap-northeast-2|m6in.16xlarge": 5.391360, + "ap-northeast-2|m6in.24xlarge": 8.087040, + "ap-northeast-2|m6in.2xlarge": 0.673920, + "ap-northeast-2|m6in.32xlarge": 10.782720, + "ap-northeast-2|m6in.4xlarge": 1.347840, + "ap-northeast-2|m6in.8xlarge": 2.695680, + "ap-northeast-2|m6in.large": 0.168480, + "ap-northeast-2|m6in.metal": 10.782720, + "ap-northeast-2|m6in.xlarge": 0.336960, + "ap-northeast-2|m7g.12xlarge": 2.407200, + "ap-northeast-2|m7g.16xlarge": 3.209600, + "ap-northeast-2|m7g.2xlarge": 0.401200, + "ap-northeast-2|m7g.4xlarge": 0.802400, + "ap-northeast-2|m7g.8xlarge": 1.604800, + "ap-northeast-2|m7g.large": 0.100300, + "ap-northeast-2|m7g.medium": 0.050200, + "ap-northeast-2|m7g.metal": 3.209600, + "ap-northeast-2|m7g.xlarge": 0.200600, + "ap-northeast-2|m7gd.12xlarge": 3.152600, + "ap-northeast-2|m7gd.16xlarge": 4.203500, + "ap-northeast-2|m7gd.2xlarge": 0.525400, + "ap-northeast-2|m7gd.4xlarge": 1.050900, + "ap-northeast-2|m7gd.8xlarge": 2.101800, + "ap-northeast-2|m7gd.large": 0.131400, + "ap-northeast-2|m7gd.medium": 0.065700, + "ap-northeast-2|m7gd.metal": 4.203500, + "ap-northeast-2|m7gd.xlarge": 0.262700, + "ap-northeast-2|m7i-flex.12xlarge": 2.825040, + "ap-northeast-2|m7i-flex.16xlarge": 3.766720, + "ap-northeast-2|m7i-flex.2xlarge": 0.470840, + "ap-northeast-2|m7i-flex.4xlarge": 0.941680, + "ap-northeast-2|m7i-flex.8xlarge": 1.883360, + "ap-northeast-2|m7i-flex.large": 0.117710, + "ap-northeast-2|m7i-flex.xlarge": 0.235420, + "ap-northeast-2|m7i.12xlarge": 2.973600, + "ap-northeast-2|m7i.16xlarge": 3.964800, + "ap-northeast-2|m7i.24xlarge": 5.947200, + "ap-northeast-2|m7i.2xlarge": 0.495600, + "ap-northeast-2|m7i.48xlarge": 11.894400, + "ap-northeast-2|m7i.4xlarge": 0.991200, + "ap-northeast-2|m7i.8xlarge": 1.982400, + "ap-northeast-2|m7i.large": 0.123900, + "ap-northeast-2|m7i.metal-24xl": 5.947200, + "ap-northeast-2|m7i.metal-48xl": 11.894400, + "ap-northeast-2|m7i.xlarge": 0.247800, + "ap-northeast-2|m8g.12xlarge": 2.648160, + "ap-northeast-2|m8g.16xlarge": 3.530880, + "ap-northeast-2|m8g.24xlarge": 5.296320, + "ap-northeast-2|m8g.2xlarge": 0.441360, + "ap-northeast-2|m8g.48xlarge": 10.592640, + "ap-northeast-2|m8g.4xlarge": 0.882720, + "ap-northeast-2|m8g.8xlarge": 1.765440, + "ap-northeast-2|m8g.large": 0.110340, + "ap-northeast-2|m8g.medium": 0.055170, + "ap-northeast-2|m8g.metal-24xl": 5.296320, + "ap-northeast-2|m8g.metal-48xl": 10.592640, + "ap-northeast-2|m8g.xlarge": 0.220680, + "ap-northeast-2|m8i.12xlarge": 3.122160, + "ap-northeast-2|m8i.16xlarge": 4.162880, + "ap-northeast-2|m8i.24xlarge": 6.244320, + "ap-northeast-2|m8i.2xlarge": 0.520360, + "ap-northeast-2|m8i.32xlarge": 8.325760, + "ap-northeast-2|m8i.48xlarge": 12.488640, + "ap-northeast-2|m8i.4xlarge": 1.040720, + "ap-northeast-2|m8i.8xlarge": 2.081440, + "ap-northeast-2|m8i.96xlarge": 24.977280, + "ap-northeast-2|m8i.large": 0.130090, + "ap-northeast-2|m8i.metal-48xl": 12.488640, + "ap-northeast-2|m8i.metal-96xl": 24.977280, + "ap-northeast-2|m8i.xlarge": 0.260180, + "ap-northeast-2|p2.16xlarge": 23.440000, + "ap-northeast-2|p2.8xlarge": 11.720000, + "ap-northeast-2|p2.xlarge": 1.465000, + "ap-northeast-2|p3.16xlarge": 33.872000, + "ap-northeast-2|p3.2xlarge": 4.234000, + "ap-northeast-2|p3.8xlarge": 16.936000, + "ap-northeast-2|p4d.24xlarge": 30.410280, + "ap-northeast-2|p5.48xlarge": 75.955200, + "ap-northeast-2|p5en.48xlarge": 87.348480, + "ap-northeast-2|r3.2xlarge": 0.798000, + "ap-northeast-2|r3.4xlarge": 1.596000, + "ap-northeast-2|r3.8xlarge": 3.192000, + "ap-northeast-2|r3.large": 0.200000, + "ap-northeast-2|r3.xlarge": 0.399000, + "ap-northeast-2|r4.16xlarge": 5.120000, + "ap-northeast-2|r4.2xlarge": 0.640000, + "ap-northeast-2|r4.4xlarge": 1.280000, + "ap-northeast-2|r4.8xlarge": 2.560000, + "ap-northeast-2|r4.large": 0.160000, + "ap-northeast-2|r4.xlarge": 0.320000, + "ap-northeast-2|r5.12xlarge": 3.648000, + "ap-northeast-2|r5.16xlarge": 4.864000, + "ap-northeast-2|r5.24xlarge": 7.296000, + "ap-northeast-2|r5.2xlarge": 0.608000, + "ap-northeast-2|r5.4xlarge": 1.216000, + "ap-northeast-2|r5.8xlarge": 2.432000, + "ap-northeast-2|r5.large": 0.152000, + "ap-northeast-2|r5.metal": 7.296000, + "ap-northeast-2|r5.xlarge": 0.304000, + "ap-northeast-2|r5a.12xlarge": 3.264000, + "ap-northeast-2|r5a.16xlarge": 4.352000, + "ap-northeast-2|r5a.24xlarge": 6.528000, + "ap-northeast-2|r5a.2xlarge": 0.544000, + "ap-northeast-2|r5a.4xlarge": 1.088000, + "ap-northeast-2|r5a.8xlarge": 2.176000, + "ap-northeast-2|r5a.large": 0.136000, + "ap-northeast-2|r5a.xlarge": 0.272000, + "ap-northeast-2|r5ad.12xlarge": 3.792000, + "ap-northeast-2|r5ad.16xlarge": 5.056000, + "ap-northeast-2|r5ad.24xlarge": 7.584000, + "ap-northeast-2|r5ad.2xlarge": 0.632000, + "ap-northeast-2|r5ad.4xlarge": 1.264000, + "ap-northeast-2|r5ad.8xlarge": 2.528000, + "ap-northeast-2|r5ad.large": 0.158000, + "ap-northeast-2|r5ad.xlarge": 0.316000, + "ap-northeast-2|r5b.12xlarge": 4.272000, + "ap-northeast-2|r5b.16xlarge": 5.696000, + "ap-northeast-2|r5b.24xlarge": 8.544000, + "ap-northeast-2|r5b.2xlarge": 0.712000, + "ap-northeast-2|r5b.4xlarge": 1.424000, + "ap-northeast-2|r5b.8xlarge": 2.848000, + "ap-northeast-2|r5b.large": 0.178000, + "ap-northeast-2|r5b.metal": 8.544000, + "ap-northeast-2|r5b.xlarge": 0.356000, + "ap-northeast-2|r5d.12xlarge": 4.152000, + "ap-northeast-2|r5d.16xlarge": 5.536000, + "ap-northeast-2|r5d.24xlarge": 8.304000, + "ap-northeast-2|r5d.2xlarge": 0.692000, + "ap-northeast-2|r5d.4xlarge": 1.384000, + "ap-northeast-2|r5d.8xlarge": 2.768000, + "ap-northeast-2|r5d.large": 0.173000, + "ap-northeast-2|r5d.metal": 8.304000, + "ap-northeast-2|r5d.xlarge": 0.346000, + "ap-northeast-2|r5dn.12xlarge": 4.776000, + "ap-northeast-2|r5dn.16xlarge": 6.368000, + "ap-northeast-2|r5dn.24xlarge": 9.552000, + "ap-northeast-2|r5dn.2xlarge": 0.796000, + "ap-northeast-2|r5dn.4xlarge": 1.592000, + "ap-northeast-2|r5dn.8xlarge": 3.184000, + "ap-northeast-2|r5dn.large": 0.199000, + "ap-northeast-2|r5dn.metal": 9.552000, + "ap-northeast-2|r5dn.xlarge": 0.398000, + "ap-northeast-2|r5n.12xlarge": 4.272000, + "ap-northeast-2|r5n.16xlarge": 5.696000, + "ap-northeast-2|r5n.24xlarge": 8.544000, + "ap-northeast-2|r5n.2xlarge": 0.712000, + "ap-northeast-2|r5n.4xlarge": 1.424000, + "ap-northeast-2|r5n.8xlarge": 2.848000, + "ap-northeast-2|r5n.large": 0.178000, + "ap-northeast-2|r5n.metal": 8.544000, + "ap-northeast-2|r5n.xlarge": 0.356000, + "ap-northeast-2|r6g.12xlarge": 2.928000, + "ap-northeast-2|r6g.16xlarge": 3.904000, + "ap-northeast-2|r6g.2xlarge": 0.488000, + "ap-northeast-2|r6g.4xlarge": 0.976000, + "ap-northeast-2|r6g.8xlarge": 1.952000, + "ap-northeast-2|r6g.large": 0.122000, + "ap-northeast-2|r6g.medium": 0.061000, + "ap-northeast-2|r6g.metal": 3.904000, + "ap-northeast-2|r6g.xlarge": 0.244000, + "ap-northeast-2|r6gd.12xlarge": 3.321600, + "ap-northeast-2|r6gd.16xlarge": 4.428800, + "ap-northeast-2|r6gd.2xlarge": 0.553600, + "ap-northeast-2|r6gd.4xlarge": 1.107200, + "ap-northeast-2|r6gd.8xlarge": 2.214400, + "ap-northeast-2|r6gd.large": 0.138400, + "ap-northeast-2|r6gd.medium": 0.069200, + "ap-northeast-2|r6gd.metal": 4.428800, + "ap-northeast-2|r6gd.xlarge": 0.276800, + "ap-northeast-2|r6i.12xlarge": 3.648000, + "ap-northeast-2|r6i.16xlarge": 4.864000, + "ap-northeast-2|r6i.24xlarge": 7.296000, + "ap-northeast-2|r6i.2xlarge": 0.608000, + "ap-northeast-2|r6i.32xlarge": 9.728000, + "ap-northeast-2|r6i.4xlarge": 1.216000, + "ap-northeast-2|r6i.8xlarge": 2.432000, + "ap-northeast-2|r6i.large": 0.152000, + "ap-northeast-2|r6i.metal": 9.728000, + "ap-northeast-2|r6i.xlarge": 0.304000, + "ap-northeast-2|r6id.12xlarge": 4.360800, + "ap-northeast-2|r6id.16xlarge": 5.814400, + "ap-northeast-2|r6id.24xlarge": 8.721600, + "ap-northeast-2|r6id.2xlarge": 0.726800, + "ap-northeast-2|r6id.32xlarge": 11.628800, + "ap-northeast-2|r6id.4xlarge": 1.453600, + "ap-northeast-2|r6id.8xlarge": 2.907200, + "ap-northeast-2|r6id.large": 0.181700, + "ap-northeast-2|r6id.metal": 11.628800, + "ap-northeast-2|r6id.xlarge": 0.363400, + "ap-northeast-2|r7g.12xlarge": 3.100800, + "ap-northeast-2|r7g.16xlarge": 4.134400, + "ap-northeast-2|r7g.2xlarge": 0.516800, + "ap-northeast-2|r7g.4xlarge": 1.033600, + "ap-northeast-2|r7g.8xlarge": 2.067200, + "ap-northeast-2|r7g.large": 0.129200, + "ap-northeast-2|r7g.medium": 0.064600, + "ap-northeast-2|r7g.metal": 4.134400, + "ap-northeast-2|r7g.xlarge": 0.258400, + "ap-northeast-2|r7gd.12xlarge": 3.925000, + "ap-northeast-2|r7gd.16xlarge": 5.233300, + "ap-northeast-2|r7gd.2xlarge": 0.654200, + "ap-northeast-2|r7gd.4xlarge": 1.308300, + "ap-northeast-2|r7gd.8xlarge": 2.616600, + "ap-northeast-2|r7gd.large": 0.163500, + "ap-northeast-2|r7gd.medium": 0.081800, + "ap-northeast-2|r7gd.metal": 5.233300, + "ap-northeast-2|r7gd.xlarge": 0.327100, + "ap-northeast-2|r7i.12xlarge": 3.830400, + "ap-northeast-2|r7i.16xlarge": 5.107200, + "ap-northeast-2|r7i.24xlarge": 7.660800, + "ap-northeast-2|r7i.2xlarge": 0.638400, + "ap-northeast-2|r7i.48xlarge": 15.321600, + "ap-northeast-2|r7i.4xlarge": 1.276800, + "ap-northeast-2|r7i.8xlarge": 2.553600, + "ap-northeast-2|r7i.large": 0.159600, + "ap-northeast-2|r7i.metal-24xl": 7.660800, + "ap-northeast-2|r7i.metal-48xl": 15.321600, + "ap-northeast-2|r7i.xlarge": 0.319200, + "ap-northeast-2|r8g.12xlarge": 3.410880, + "ap-northeast-2|r8g.16xlarge": 4.547840, + "ap-northeast-2|r8g.24xlarge": 6.821760, + "ap-northeast-2|r8g.2xlarge": 0.568480, + "ap-northeast-2|r8g.48xlarge": 13.643520, + "ap-northeast-2|r8g.4xlarge": 1.136960, + "ap-northeast-2|r8g.8xlarge": 2.273920, + "ap-northeast-2|r8g.large": 0.142120, + "ap-northeast-2|r8g.medium": 0.071060, + "ap-northeast-2|r8g.metal-24xl": 6.821760, + "ap-northeast-2|r8g.metal-48xl": 13.643520, + "ap-northeast-2|r8g.xlarge": 0.284240, + "ap-northeast-2|r8i-flex.12xlarge": 3.820800, + "ap-northeast-2|r8i-flex.16xlarge": 5.094400, + "ap-northeast-2|r8i-flex.2xlarge": 0.636800, + "ap-northeast-2|r8i-flex.4xlarge": 1.273600, + "ap-northeast-2|r8i-flex.8xlarge": 2.547200, + "ap-northeast-2|r8i-flex.large": 0.159200, + "ap-northeast-2|r8i-flex.xlarge": 0.318400, + "ap-northeast-2|r8i.12xlarge": 4.021920, + "ap-northeast-2|r8i.16xlarge": 5.362560, + "ap-northeast-2|r8i.24xlarge": 8.043840, + "ap-northeast-2|r8i.2xlarge": 0.670320, + "ap-northeast-2|r8i.32xlarge": 10.725120, + "ap-northeast-2|r8i.48xlarge": 16.087680, + "ap-northeast-2|r8i.4xlarge": 1.340640, + "ap-northeast-2|r8i.8xlarge": 2.681280, + "ap-northeast-2|r8i.96xlarge": 32.175360, + "ap-northeast-2|r8i.large": 0.167580, + "ap-northeast-2|r8i.metal-48xl": 16.087680, + "ap-northeast-2|r8i.metal-96xl": 32.175360, + "ap-northeast-2|r8i.xlarge": 0.335160, + "ap-northeast-2|t2.2xlarge": 0.460800, + "ap-northeast-2|t2.large": 0.115200, + "ap-northeast-2|t2.medium": 0.057600, + "ap-northeast-2|t2.micro": 0.014400, + "ap-northeast-2|t2.nano": 0.007200, + "ap-northeast-2|t2.small": 0.028800, + "ap-northeast-2|t2.xlarge": 0.230400, + "ap-northeast-2|t3.2xlarge": 0.416000, + "ap-northeast-2|t3.large": 0.104000, + "ap-northeast-2|t3.medium": 0.052000, + "ap-northeast-2|t3.micro": 0.013000, + "ap-northeast-2|t3.nano": 0.006500, + "ap-northeast-2|t3.small": 0.026000, + "ap-northeast-2|t3.xlarge": 0.208000, + "ap-northeast-2|t3a.2xlarge": 0.374400, + "ap-northeast-2|t3a.large": 0.093600, + "ap-northeast-2|t3a.medium": 0.046800, + "ap-northeast-2|t3a.micro": 0.011700, + "ap-northeast-2|t3a.nano": 0.005900, + "ap-northeast-2|t3a.small": 0.023400, + "ap-northeast-2|t3a.xlarge": 0.187200, + "ap-northeast-2|t4g.2xlarge": 0.332800, + "ap-northeast-2|t4g.large": 0.083200, + "ap-northeast-2|t4g.medium": 0.041600, + "ap-northeast-2|t4g.micro": 0.010400, + "ap-northeast-2|t4g.nano": 0.005200, + "ap-northeast-2|t4g.small": 0.020800, + "ap-northeast-2|t4g.xlarge": 0.166400, + "ap-northeast-2|u-12tb1.112xlarge": 131.733000, + "ap-northeast-2|u-24tb1.112xlarge": 263.470000, + "ap-northeast-2|u-6tb1.112xlarge": 65.867000, + "ap-northeast-2|u-6tb1.56xlarge": 55.979600, + "ap-northeast-2|u-9tb1.112xlarge": 98.800000, + "ap-northeast-2|u7i-12tb.224xlarge": 151.497590, + "ap-northeast-2|u7i-6tb.112xlarge": 75.747050, + "ap-northeast-2|u7i-8tb.112xlarge": 100.996060, + "ap-northeast-2|u7in-16tb.224xlarge": 217.716380, + "ap-northeast-2|x1.16xlarge": 9.671000, + "ap-northeast-2|x1.32xlarge": 19.341000, + "ap-northeast-2|x1e.16xlarge": 19.344000, + "ap-northeast-2|x1e.2xlarge": 2.418000, + "ap-northeast-2|x1e.32xlarge": 38.688000, + "ap-northeast-2|x1e.4xlarge": 4.836000, + "ap-northeast-2|x1e.8xlarge": 9.672000, + "ap-northeast-2|x1e.xlarge": 1.209000, + "ap-northeast-2|x2idn.16xlarge": 9.670500, + "ap-northeast-2|x2idn.24xlarge": 14.505750, + "ap-northeast-2|x2idn.32xlarge": 19.341000, + "ap-northeast-2|x2idn.metal": 19.341000, + "ap-northeast-2|x2iedn.16xlarge": 19.341000, + "ap-northeast-2|x2iedn.24xlarge": 29.011500, + "ap-northeast-2|x2iedn.2xlarge": 2.417630, + "ap-northeast-2|x2iedn.32xlarge": 38.682000, + "ap-northeast-2|x2iedn.4xlarge": 4.835250, + "ap-northeast-2|x2iedn.8xlarge": 9.670500, + "ap-northeast-2|x2iedn.metal": 38.682000, + "ap-northeast-2|x2iedn.xlarge": 1.208810, + "ap-northeast-2|z1d.12xlarge": 5.400000, + "ap-northeast-2|z1d.2xlarge": 0.900000, + "ap-northeast-2|z1d.3xlarge": 1.350000, + "ap-northeast-2|z1d.6xlarge": 2.700000, + "ap-northeast-2|z1d.large": 0.225000, + "ap-northeast-2|z1d.metal": 5.400000, + "ap-northeast-2|z1d.xlarge": 0.450000, + "ap-south-1|a1.2xlarge": 0.204000, + "ap-south-1|a1.4xlarge": 0.408000, + "ap-south-1|a1.large": 0.051000, + "ap-south-1|a1.medium": 0.025500, + "ap-south-1|a1.metal": 0.408000, + "ap-south-1|a1.xlarge": 0.102000, + "ap-south-1|c4.2xlarge": 0.400000, + "ap-south-1|c4.4xlarge": 0.800000, + "ap-south-1|c4.8xlarge": 1.600000, + "ap-south-1|c4.large": 0.100000, + "ap-south-1|c4.xlarge": 0.200000, + "ap-south-1|c5.12xlarge": 2.040000, + "ap-south-1|c5.18xlarge": 3.060000, + "ap-south-1|c5.24xlarge": 4.080000, + "ap-south-1|c5.2xlarge": 0.340000, + "ap-south-1|c5.4xlarge": 0.680000, + "ap-south-1|c5.9xlarge": 1.530000, + "ap-south-1|c5.large": 0.085000, + "ap-south-1|c5.metal": 4.080000, + "ap-south-1|c5.xlarge": 0.170000, + "ap-south-1|c5a.12xlarge": 1.128000, + "ap-south-1|c5a.16xlarge": 1.504000, + "ap-south-1|c5a.24xlarge": 2.256000, + "ap-south-1|c5a.2xlarge": 0.188000, + "ap-south-1|c5a.4xlarge": 0.376000, + "ap-south-1|c5a.8xlarge": 0.752000, + "ap-south-1|c5a.large": 0.047000, + "ap-south-1|c5a.xlarge": 0.094000, + "ap-south-1|c5d.12xlarge": 2.376000, + "ap-south-1|c5d.18xlarge": 3.564000, + "ap-south-1|c5d.24xlarge": 4.752000, + "ap-south-1|c5d.2xlarge": 0.396000, + "ap-south-1|c5d.4xlarge": 0.792000, + "ap-south-1|c5d.9xlarge": 1.782000, + "ap-south-1|c5d.large": 0.099000, + "ap-south-1|c5d.metal": 4.752000, + "ap-south-1|c5d.xlarge": 0.198000, + "ap-south-1|c5n.18xlarge": 3.888000, + "ap-south-1|c5n.2xlarge": 0.432000, + "ap-south-1|c5n.4xlarge": 0.864000, + "ap-south-1|c5n.9xlarge": 1.944000, + "ap-south-1|c5n.large": 0.108000, + "ap-south-1|c5n.metal": 3.888000, + "ap-south-1|c5n.xlarge": 0.216000, + "ap-south-1|c6a.12xlarge": 1.122000, + "ap-south-1|c6a.16xlarge": 1.496000, + "ap-south-1|c6a.24xlarge": 2.244000, + "ap-south-1|c6a.2xlarge": 0.187000, + "ap-south-1|c6a.32xlarge": 2.992000, + "ap-south-1|c6a.48xlarge": 4.488000, + "ap-south-1|c6a.4xlarge": 0.374000, + "ap-south-1|c6a.8xlarge": 0.748000, + "ap-south-1|c6a.large": 0.046750, + "ap-south-1|c6a.metal": 4.488000, + "ap-south-1|c6a.xlarge": 0.093500, + "ap-south-1|c6g.12xlarge": 1.022400, + "ap-south-1|c6g.16xlarge": 1.363200, + "ap-south-1|c6g.2xlarge": 0.170400, + "ap-south-1|c6g.4xlarge": 0.340800, + "ap-south-1|c6g.8xlarge": 0.681600, + "ap-south-1|c6g.large": 0.042600, + "ap-south-1|c6g.medium": 0.021300, + "ap-south-1|c6g.metal": 1.363200, + "ap-south-1|c6g.xlarge": 0.085200, + "ap-south-1|c6gd.12xlarge": 1.176000, + "ap-south-1|c6gd.16xlarge": 1.568000, + "ap-south-1|c6gd.2xlarge": 0.196000, + "ap-south-1|c6gd.4xlarge": 0.392000, + "ap-south-1|c6gd.8xlarge": 0.784000, + "ap-south-1|c6gd.large": 0.049000, + "ap-south-1|c6gd.medium": 0.024500, + "ap-south-1|c6gd.metal": 1.568000, + "ap-south-1|c6gd.xlarge": 0.098000, + "ap-south-1|c6gn.12xlarge": 2.076000, + "ap-south-1|c6gn.16xlarge": 2.768000, + "ap-south-1|c6gn.2xlarge": 0.346000, + "ap-south-1|c6gn.4xlarge": 0.692000, + "ap-south-1|c6gn.8xlarge": 1.384000, + "ap-south-1|c6gn.large": 0.086500, + "ap-south-1|c6gn.medium": 0.043250, + "ap-south-1|c6gn.xlarge": 0.173000, + "ap-south-1|c6i.12xlarge": 2.040000, + "ap-south-1|c6i.16xlarge": 2.720000, + "ap-south-1|c6i.24xlarge": 4.080000, + "ap-south-1|c6i.2xlarge": 0.340000, + "ap-south-1|c6i.32xlarge": 5.440000, + "ap-south-1|c6i.4xlarge": 0.680000, + "ap-south-1|c6i.8xlarge": 1.360000, + "ap-south-1|c6i.large": 0.085000, + "ap-south-1|c6i.metal": 5.440000, + "ap-south-1|c6i.xlarge": 0.170000, + "ap-south-1|c6in.12xlarge": 2.721600, + "ap-south-1|c6in.16xlarge": 3.628800, + "ap-south-1|c6in.24xlarge": 5.443200, + "ap-south-1|c6in.2xlarge": 0.453600, + "ap-south-1|c6in.32xlarge": 7.257600, + "ap-south-1|c6in.4xlarge": 0.907200, + "ap-south-1|c6in.8xlarge": 1.814400, + "ap-south-1|c6in.large": 0.113400, + "ap-south-1|c6in.metal": 7.257600, + "ap-south-1|c6in.xlarge": 0.226800, + "ap-south-1|c7g.12xlarge": 1.177900, + "ap-south-1|c7g.16xlarge": 1.570600, + "ap-south-1|c7g.2xlarge": 0.196300, + "ap-south-1|c7g.4xlarge": 0.392600, + "ap-south-1|c7g.8xlarge": 0.785300, + "ap-south-1|c7g.large": 0.049100, + "ap-south-1|c7g.medium": 0.024500, + "ap-south-1|c7g.metal": 1.570600, + "ap-south-1|c7g.xlarge": 0.098200, + "ap-south-1|c7gd.12xlarge": 1.382400, + "ap-south-1|c7gd.16xlarge": 1.843200, + "ap-south-1|c7gd.2xlarge": 0.230400, + "ap-south-1|c7gd.4xlarge": 0.460800, + "ap-south-1|c7gd.8xlarge": 0.921600, + "ap-south-1|c7gd.large": 0.057600, + "ap-south-1|c7gd.medium": 0.028800, + "ap-south-1|c7gd.metal": 1.843200, + "ap-south-1|c7gd.xlarge": 0.115200, + "ap-south-1|c7i-flex.12xlarge": 2.034900, + "ap-south-1|c7i-flex.16xlarge": 2.713200, + "ap-south-1|c7i-flex.2xlarge": 0.339150, + "ap-south-1|c7i-flex.4xlarge": 0.678300, + "ap-south-1|c7i-flex.8xlarge": 1.356600, + "ap-south-1|c7i-flex.large": 0.084790, + "ap-south-1|c7i-flex.xlarge": 0.169580, + "ap-south-1|c7i.12xlarge": 2.142000, + "ap-south-1|c7i.16xlarge": 2.856000, + "ap-south-1|c7i.24xlarge": 4.284000, + "ap-south-1|c7i.2xlarge": 0.357000, + "ap-south-1|c7i.48xlarge": 8.568000, + "ap-south-1|c7i.4xlarge": 0.714000, + "ap-south-1|c7i.8xlarge": 1.428000, + "ap-south-1|c7i.large": 0.089250, + "ap-south-1|c7i.metal-24xl": 4.284000, + "ap-south-1|c7i.metal-48xl": 8.568000, + "ap-south-1|c7i.xlarge": 0.178500, + "ap-south-1|c8g.12xlarge": 1.295520, + "ap-south-1|c8g.16xlarge": 1.727360, + "ap-south-1|c8g.24xlarge": 2.591040, + "ap-south-1|c8g.2xlarge": 0.215920, + "ap-south-1|c8g.48xlarge": 5.182080, + "ap-south-1|c8g.4xlarge": 0.431840, + "ap-south-1|c8g.8xlarge": 0.863680, + "ap-south-1|c8g.large": 0.053980, + "ap-south-1|c8g.medium": 0.026990, + "ap-south-1|c8g.metal-24xl": 2.591040, + "ap-south-1|c8g.metal-48xl": 5.182080, + "ap-south-1|c8g.xlarge": 0.107960, + "ap-south-1|c8i-flex.12xlarge": 2.136480, + "ap-south-1|c8i-flex.16xlarge": 2.848640, + "ap-south-1|c8i-flex.2xlarge": 0.356080, + "ap-south-1|c8i-flex.4xlarge": 0.712160, + "ap-south-1|c8i-flex.8xlarge": 1.424320, + "ap-south-1|c8i-flex.large": 0.089020, + "ap-south-1|c8i-flex.xlarge": 0.178040, + "ap-south-1|c8i.12xlarge": 2.249040, + "ap-south-1|c8i.16xlarge": 2.998720, + "ap-south-1|c8i.24xlarge": 4.498080, + "ap-south-1|c8i.2xlarge": 0.374840, + "ap-south-1|c8i.32xlarge": 5.997440, + "ap-south-1|c8i.48xlarge": 8.996160, + "ap-south-1|c8i.4xlarge": 0.749680, + "ap-south-1|c8i.8xlarge": 1.499360, + "ap-south-1|c8i.96xlarge": 17.992320, + "ap-south-1|c8i.large": 0.093710, + "ap-south-1|c8i.metal-48xl": 8.996160, + "ap-south-1|c8i.metal-96xl": 17.992320, + "ap-south-1|c8i.xlarge": 0.187420, + "ap-south-1|d2.2xlarge": 1.653000, + "ap-south-1|d2.4xlarge": 3.306000, + "ap-south-1|d2.8xlarge": 6.612000, + "ap-south-1|d2.xlarge": 0.827000, + "ap-south-1|d3.2xlarge": 1.047000, + "ap-south-1|d3.4xlarge": 2.095000, + "ap-south-1|d3.8xlarge": 4.189040, + "ap-south-1|d3.xlarge": 0.524000, + "ap-south-1|g4dn.12xlarge": 4.306000, + "ap-south-1|g4dn.16xlarge": 4.791000, + "ap-south-1|g4dn.2xlarge": 0.828000, + "ap-south-1|g4dn.4xlarge": 1.325000, + "ap-south-1|g4dn.8xlarge": 2.395000, + "ap-south-1|g4dn.metal": 8.612000, + "ap-south-1|g4dn.xlarge": 0.579000, + "ap-south-1|g5.12xlarge": 6.810910, + "ap-south-1|g5.16xlarge": 4.918460, + "ap-south-1|g5.24xlarge": 9.779280, + "ap-south-1|g5.2xlarge": 1.455360, + "ap-south-1|g5.48xlarge": 19.558550, + "ap-south-1|g5.4xlarge": 1.950090, + "ap-south-1|g5.8xlarge": 2.939550, + "ap-south-1|g5.xlarge": 1.208000, + "ap-south-1|g6.12xlarge": 5.525580, + "ap-south-1|g6.16xlarge": 4.078860, + "ap-south-1|g6.24xlarge": 8.015550, + "ap-south-1|g6.2xlarge": 1.173900, + "ap-south-1|g6.48xlarge": 16.031100, + "ap-south-1|g6.4xlarge": 1.588890, + "ap-south-1|g6.8xlarge": 2.418880, + "ap-south-1|g6.xlarge": 0.966400, + "ap-south-1|g6f.2xlarge": 0.570380, + "ap-south-1|g6f.4xlarge": 1.140760, + "ap-south-1|g6f.large": 0.242560, + "ap-south-1|g6f.xlarge": 0.285190, + "ap-south-1|gr6.4xlarge": 1.848300, + "ap-south-1|gr6.8xlarge": 2.937680, + "ap-south-1|gr6f.4xlarge": 1.280070, + "ap-south-1|i2.2xlarge": 1.933000, + "ap-south-1|i2.4xlarge": 3.867000, + "ap-south-1|i2.8xlarge": 7.733000, + "ap-south-1|i2.xlarge": 0.967000, + "ap-south-1|i3.16xlarge": 5.664000, + "ap-south-1|i3.2xlarge": 0.708000, + "ap-south-1|i3.4xlarge": 1.416000, + "ap-south-1|i3.8xlarge": 2.832000, + "ap-south-1|i3.large": 0.177000, + "ap-south-1|i3.metal": 5.664000, + "ap-south-1|i3.xlarge": 0.354000, + "ap-south-1|i3en.12xlarge": 6.168000, + "ap-south-1|i3en.24xlarge": 12.336000, + "ap-south-1|i3en.2xlarge": 1.028000, + "ap-south-1|i3en.3xlarge": 1.542000, + "ap-south-1|i3en.6xlarge": 3.084000, + "ap-south-1|i3en.large": 0.257000, + "ap-south-1|i3en.metal": 12.336000, + "ap-south-1|i3en.xlarge": 0.514000, + "ap-south-1|i4i.12xlarge": 4.673000, + "ap-south-1|i4i.16xlarge": 6.230000, + "ap-south-1|i4i.24xlarge": 9.345600, + "ap-south-1|i4i.2xlarge": 0.779000, + "ap-south-1|i4i.32xlarge": 12.460800, + "ap-south-1|i4i.4xlarge": 1.558000, + "ap-south-1|i4i.8xlarge": 3.115000, + "ap-south-1|i4i.large": 0.195000, + "ap-south-1|i4i.metal": 12.461000, + "ap-south-1|i4i.xlarge": 0.389000, + "ap-south-1|i7i.12xlarge": 5.140100, + "ap-south-1|i7i.16xlarge": 6.853400, + "ap-south-1|i7i.24xlarge": 10.280200, + "ap-south-1|i7i.2xlarge": 0.856700, + "ap-south-1|i7i.48xlarge": 20.560300, + "ap-south-1|i7i.4xlarge": 1.713400, + "ap-south-1|i7i.8xlarge": 3.426700, + "ap-south-1|i7i.large": 0.214200, + "ap-south-1|i7i.metal-24xl": 10.280200, + "ap-south-1|i7i.metal-48xl": 20.560300, + "ap-south-1|i7i.xlarge": 0.428300, + "ap-south-1|i7ie.12xlarge": 7.093200, + "ap-south-1|i7ie.18xlarge": 10.639800, + "ap-south-1|i7ie.24xlarge": 14.186400, + "ap-south-1|i7ie.2xlarge": 1.182200, + "ap-south-1|i7ie.3xlarge": 1.773300, + "ap-south-1|i7ie.48xlarge": 28.372800, + "ap-south-1|i7ie.6xlarge": 3.546600, + "ap-south-1|i7ie.large": 0.295600, + "ap-south-1|i7ie.metal-24xl": 14.186400, + "ap-south-1|i7ie.metal-48xl": 28.372800, + "ap-south-1|i7ie.xlarge": 0.591100, + "ap-south-1|i8g.12xlarge": 4.672800, + "ap-south-1|i8g.16xlarge": 6.230400, + "ap-south-1|i8g.24xlarge": 9.345600, + "ap-south-1|i8g.2xlarge": 0.778800, + "ap-south-1|i8g.48xlarge": 18.691200, + "ap-south-1|i8g.4xlarge": 1.557600, + "ap-south-1|i8g.8xlarge": 3.115200, + "ap-south-1|i8g.large": 0.194700, + "ap-south-1|i8g.metal-24xl": 9.345600, + "ap-south-1|i8g.xlarge": 0.389400, + "ap-south-1|im4gn.16xlarge": 6.608000, + "ap-south-1|im4gn.2xlarge": 0.826000, + "ap-south-1|im4gn.4xlarge": 1.652000, + "ap-south-1|im4gn.8xlarge": 3.304000, + "ap-south-1|im4gn.large": 0.206500, + "ap-south-1|im4gn.xlarge": 0.413000, + "ap-south-1|inf1.24xlarge": 4.965000, + "ap-south-1|inf1.2xlarge": 0.381000, + "ap-south-1|inf1.6xlarge": 1.241000, + "ap-south-1|inf1.xlarge": 0.240000, + "ap-south-1|inf2.24xlarge": 8.437820, + "ap-south-1|inf2.48xlarge": 16.875650, + "ap-south-1|inf2.8xlarge": 2.558220, + "ap-south-1|inf2.xlarge": 0.985660, + "ap-south-1|is4gen.2xlarge": 1.310000, + "ap-south-1|is4gen.4xlarge": 2.620000, + "ap-south-1|is4gen.8xlarge": 5.240000, + "ap-south-1|is4gen.large": 0.327500, + "ap-south-1|is4gen.medium": 0.163750, + "ap-south-1|is4gen.xlarge": 0.655000, + "ap-south-1|m4.10xlarge": 2.100000, + "ap-south-1|m4.16xlarge": 3.360000, + "ap-south-1|m4.2xlarge": 0.420000, + "ap-south-1|m4.4xlarge": 0.840000, + "ap-south-1|m4.large": 0.105000, + "ap-south-1|m4.xlarge": 0.210000, + "ap-south-1|m5.12xlarge": 2.424000, + "ap-south-1|m5.16xlarge": 3.232000, + "ap-south-1|m5.24xlarge": 4.848000, + "ap-south-1|m5.2xlarge": 0.404000, + "ap-south-1|m5.4xlarge": 0.808000, + "ap-south-1|m5.8xlarge": 1.616000, + "ap-south-1|m5.large": 0.101000, + "ap-south-1|m5.metal": 4.848000, + "ap-south-1|m5.xlarge": 0.202000, + "ap-south-1|m5a.12xlarge": 1.333000, + "ap-south-1|m5a.16xlarge": 1.778000, + "ap-south-1|m5a.24xlarge": 2.666000, + "ap-south-1|m5a.2xlarge": 0.222000, + "ap-south-1|m5a.4xlarge": 0.444000, + "ap-south-1|m5a.8xlarge": 0.889000, + "ap-south-1|m5a.large": 0.056000, + "ap-south-1|m5a.xlarge": 0.111000, + "ap-south-1|m5ad.12xlarge": 1.610000, + "ap-south-1|m5ad.16xlarge": 2.147000, + "ap-south-1|m5ad.24xlarge": 3.221000, + "ap-south-1|m5ad.2xlarge": 0.268000, + "ap-south-1|m5ad.4xlarge": 0.537000, + "ap-south-1|m5ad.8xlarge": 1.074000, + "ap-south-1|m5ad.large": 0.067000, + "ap-south-1|m5ad.xlarge": 0.134000, + "ap-south-1|m5d.12xlarge": 2.928000, + "ap-south-1|m5d.16xlarge": 3.904000, + "ap-south-1|m5d.24xlarge": 5.856000, + "ap-south-1|m5d.2xlarge": 0.488000, + "ap-south-1|m5d.4xlarge": 0.976000, + "ap-south-1|m5d.8xlarge": 1.952000, + "ap-south-1|m5d.large": 0.122000, + "ap-south-1|m5d.metal": 5.856000, + "ap-south-1|m5d.xlarge": 0.244000, + "ap-south-1|m6a.12xlarge": 1.333200, + "ap-south-1|m6a.16xlarge": 1.777600, + "ap-south-1|m6a.24xlarge": 2.666400, + "ap-south-1|m6a.2xlarge": 0.222200, + "ap-south-1|m6a.32xlarge": 3.555200, + "ap-south-1|m6a.48xlarge": 5.332800, + "ap-south-1|m6a.4xlarge": 0.444400, + "ap-south-1|m6a.8xlarge": 0.888800, + "ap-south-1|m6a.large": 0.055550, + "ap-south-1|m6a.metal": 5.332800, + "ap-south-1|m6a.xlarge": 0.111100, + "ap-south-1|m6g.12xlarge": 1.214400, + "ap-south-1|m6g.16xlarge": 1.619200, + "ap-south-1|m6g.2xlarge": 0.202400, + "ap-south-1|m6g.4xlarge": 0.404800, + "ap-south-1|m6g.8xlarge": 0.809600, + "ap-south-1|m6g.large": 0.050600, + "ap-south-1|m6g.medium": 0.025300, + "ap-south-1|m6g.metal": 1.619200, + "ap-south-1|m6g.xlarge": 0.101200, + "ap-south-1|m6gd.12xlarge": 1.449600, + "ap-south-1|m6gd.16xlarge": 1.932800, + "ap-south-1|m6gd.2xlarge": 0.241600, + "ap-south-1|m6gd.4xlarge": 0.483200, + "ap-south-1|m6gd.8xlarge": 0.966400, + "ap-south-1|m6gd.large": 0.060400, + "ap-south-1|m6gd.medium": 0.030200, + "ap-south-1|m6gd.metal": 1.932800, + "ap-south-1|m6gd.xlarge": 0.120800, + "ap-south-1|m6i.12xlarge": 2.424000, + "ap-south-1|m6i.16xlarge": 3.232000, + "ap-south-1|m6i.24xlarge": 4.848000, + "ap-south-1|m6i.2xlarge": 0.404000, + "ap-south-1|m6i.32xlarge": 6.464000, + "ap-south-1|m6i.4xlarge": 0.808000, + "ap-south-1|m6i.8xlarge": 1.616000, + "ap-south-1|m6i.large": 0.101000, + "ap-south-1|m6i.metal": 6.464000, + "ap-south-1|m6i.xlarge": 0.202000, + "ap-south-1|m6id.12xlarge": 3.074400, + "ap-south-1|m6id.16xlarge": 4.099200, + "ap-south-1|m6id.24xlarge": 6.148800, + "ap-south-1|m6id.2xlarge": 0.512400, + "ap-south-1|m6id.32xlarge": 8.198400, + "ap-south-1|m6id.4xlarge": 1.024800, + "ap-south-1|m6id.8xlarge": 2.049600, + "ap-south-1|m6id.large": 0.128100, + "ap-south-1|m6id.metal": 8.198400, + "ap-south-1|m6id.xlarge": 0.256200, + "ap-south-1|m6idn.12xlarge": 4.071600, + "ap-south-1|m6idn.16xlarge": 5.428800, + "ap-south-1|m6idn.24xlarge": 8.143200, + "ap-south-1|m6idn.2xlarge": 0.678600, + "ap-south-1|m6idn.32xlarge": 10.857600, + "ap-south-1|m6idn.4xlarge": 1.357200, + "ap-south-1|m6idn.8xlarge": 2.714400, + "ap-south-1|m6idn.large": 0.169650, + "ap-south-1|m6idn.metal": 10.857600, + "ap-south-1|m6idn.xlarge": 0.339300, + "ap-south-1|m6in.12xlarge": 3.481920, + "ap-south-1|m6in.16xlarge": 4.642560, + "ap-south-1|m6in.24xlarge": 6.963840, + "ap-south-1|m6in.2xlarge": 0.580320, + "ap-south-1|m6in.32xlarge": 9.285120, + "ap-south-1|m6in.4xlarge": 1.160640, + "ap-south-1|m6in.8xlarge": 2.321280, + "ap-south-1|m6in.large": 0.145080, + "ap-south-1|m6in.metal": 9.285120, + "ap-south-1|m6in.xlarge": 0.290160, + "ap-south-1|m7g.12xlarge": 1.399700, + "ap-south-1|m7g.16xlarge": 1.866200, + "ap-south-1|m7g.2xlarge": 0.233300, + "ap-south-1|m7g.4xlarge": 0.466600, + "ap-south-1|m7g.8xlarge": 0.933100, + "ap-south-1|m7g.large": 0.058300, + "ap-south-1|m7g.medium": 0.029200, + "ap-south-1|m7g.metal": 1.866200, + "ap-south-1|m7g.xlarge": 0.116600, + "ap-south-1|m7gd.12xlarge": 1.704000, + "ap-south-1|m7gd.16xlarge": 2.272000, + "ap-south-1|m7gd.2xlarge": 0.284000, + "ap-south-1|m7gd.4xlarge": 0.568000, + "ap-south-1|m7gd.8xlarge": 1.136000, + "ap-south-1|m7gd.large": 0.071000, + "ap-south-1|m7gd.medium": 0.035500, + "ap-south-1|m7gd.metal": 2.272000, + "ap-south-1|m7gd.xlarge": 0.142000, + "ap-south-1|m7i-flex.12xlarge": 2.418000, + "ap-south-1|m7i-flex.16xlarge": 3.224000, + "ap-south-1|m7i-flex.2xlarge": 0.403000, + "ap-south-1|m7i-flex.4xlarge": 0.806000, + "ap-south-1|m7i-flex.8xlarge": 1.612000, + "ap-south-1|m7i-flex.large": 0.100750, + "ap-south-1|m7i-flex.xlarge": 0.201500, + "ap-south-1|m7i.12xlarge": 2.545200, + "ap-south-1|m7i.16xlarge": 3.393600, + "ap-south-1|m7i.24xlarge": 5.090400, + "ap-south-1|m7i.2xlarge": 0.424200, + "ap-south-1|m7i.48xlarge": 10.180800, + "ap-south-1|m7i.4xlarge": 0.848400, + "ap-south-1|m7i.8xlarge": 1.696800, + "ap-south-1|m7i.large": 0.106050, + "ap-south-1|m7i.metal-24xl": 5.090400, + "ap-south-1|m7i.metal-48xl": 10.180800, + "ap-south-1|m7i.xlarge": 0.212100, + "ap-south-1|m8g.12xlarge": 1.539840, + "ap-south-1|m8g.16xlarge": 2.053120, + "ap-south-1|m8g.24xlarge": 3.079680, + "ap-south-1|m8g.2xlarge": 0.256640, + "ap-south-1|m8g.48xlarge": 6.159360, + "ap-south-1|m8g.4xlarge": 0.513280, + "ap-south-1|m8g.8xlarge": 1.026560, + "ap-south-1|m8g.large": 0.064160, + "ap-south-1|m8g.medium": 0.032080, + "ap-south-1|m8g.metal-24xl": 3.079680, + "ap-south-1|m8g.metal-48xl": 6.159360, + "ap-south-1|m8g.xlarge": 0.128320, + "ap-south-1|m8i-flex.12xlarge": 2.538960, + "ap-south-1|m8i-flex.16xlarge": 3.385280, + "ap-south-1|m8i-flex.2xlarge": 0.423160, + "ap-south-1|m8i-flex.4xlarge": 0.846320, + "ap-south-1|m8i-flex.8xlarge": 1.692640, + "ap-south-1|m8i-flex.large": 0.105790, + "ap-south-1|m8i-flex.xlarge": 0.211580, + "ap-south-1|m8i.12xlarge": 2.672400, + "ap-south-1|m8i.16xlarge": 3.563200, + "ap-south-1|m8i.24xlarge": 5.344800, + "ap-south-1|m8i.2xlarge": 0.445400, + "ap-south-1|m8i.32xlarge": 7.126400, + "ap-south-1|m8i.48xlarge": 10.689600, + "ap-south-1|m8i.4xlarge": 0.890800, + "ap-south-1|m8i.8xlarge": 1.781600, + "ap-south-1|m8i.96xlarge": 21.379200, + "ap-south-1|m8i.large": 0.111350, + "ap-south-1|m8i.metal-48xl": 10.689600, + "ap-south-1|m8i.metal-96xl": 21.379200, + "ap-south-1|m8i.xlarge": 0.222700, + "ap-south-1|p2.16xlarge": 27.488000, + "ap-south-1|p2.8xlarge": 13.744000, + "ap-south-1|p2.xlarge": 1.718000, + "ap-south-1|p4d.24xlarge": 26.344400, + "ap-south-1|p5.48xlarge": 66.048000, + "ap-south-1|p5.4xlarge": 8.256000, + "ap-south-1|p5en.48xlarge": 75.955200, + "ap-south-1|r3.2xlarge": 0.758000, + "ap-south-1|r3.4xlarge": 1.516000, + "ap-south-1|r3.8xlarge": 3.032000, + "ap-south-1|r3.large": 0.190000, + "ap-south-1|r3.xlarge": 0.379000, + "ap-south-1|r4.16xlarge": 4.384000, + "ap-south-1|r4.2xlarge": 0.548000, + "ap-south-1|r4.4xlarge": 1.096000, + "ap-south-1|r4.8xlarge": 2.192000, + "ap-south-1|r4.large": 0.137000, + "ap-south-1|r4.xlarge": 0.274000, + "ap-south-1|r5.12xlarge": 3.120000, + "ap-south-1|r5.16xlarge": 4.160000, + "ap-south-1|r5.24xlarge": 6.240000, + "ap-south-1|r5.2xlarge": 0.520000, + "ap-south-1|r5.4xlarge": 1.040000, + "ap-south-1|r5.8xlarge": 2.080000, + "ap-south-1|r5.large": 0.130000, + "ap-south-1|r5.metal": 6.240000, + "ap-south-1|r5.xlarge": 0.260000, + "ap-south-1|r5a.12xlarge": 1.716000, + "ap-south-1|r5a.16xlarge": 2.288000, + "ap-south-1|r5a.24xlarge": 3.432000, + "ap-south-1|r5a.2xlarge": 0.286000, + "ap-south-1|r5a.4xlarge": 0.572000, + "ap-south-1|r5a.8xlarge": 1.144000, + "ap-south-1|r5a.large": 0.072000, + "ap-south-1|r5a.xlarge": 0.143000, + "ap-south-1|r5ad.12xlarge": 1.993000, + "ap-south-1|r5ad.16xlarge": 2.658000, + "ap-south-1|r5ad.24xlarge": 3.986000, + "ap-south-1|r5ad.2xlarge": 0.332000, + "ap-south-1|r5ad.4xlarge": 0.664000, + "ap-south-1|r5ad.8xlarge": 1.329000, + "ap-south-1|r5ad.large": 0.083000, + "ap-south-1|r5ad.xlarge": 0.166000, + "ap-south-1|r5d.12xlarge": 3.624000, + "ap-south-1|r5d.16xlarge": 4.832000, + "ap-south-1|r5d.24xlarge": 7.248000, + "ap-south-1|r5d.2xlarge": 0.604000, + "ap-south-1|r5d.4xlarge": 1.208000, + "ap-south-1|r5d.8xlarge": 2.416000, + "ap-south-1|r5d.large": 0.151000, + "ap-south-1|r5d.metal": 7.248000, + "ap-south-1|r5d.xlarge": 0.302000, + "ap-south-1|r5n.12xlarge": 3.672000, + "ap-south-1|r5n.16xlarge": 4.896000, + "ap-south-1|r5n.24xlarge": 7.344000, + "ap-south-1|r5n.2xlarge": 0.612000, + "ap-south-1|r5n.4xlarge": 1.224000, + "ap-south-1|r5n.8xlarge": 2.448000, + "ap-south-1|r5n.large": 0.153000, + "ap-south-1|r5n.metal": 7.344000, + "ap-south-1|r5n.xlarge": 0.306000, + "ap-south-1|r6a.12xlarge": 1.716000, + "ap-south-1|r6a.16xlarge": 2.288000, + "ap-south-1|r6a.24xlarge": 3.432000, + "ap-south-1|r6a.2xlarge": 0.286000, + "ap-south-1|r6a.32xlarge": 4.576000, + "ap-south-1|r6a.48xlarge": 6.864000, + "ap-south-1|r6a.4xlarge": 0.572000, + "ap-south-1|r6a.8xlarge": 1.144000, + "ap-south-1|r6a.large": 0.071500, + "ap-south-1|r6a.metal": 6.864000, + "ap-south-1|r6a.xlarge": 0.143000, + "ap-south-1|r6g.12xlarge": 1.560000, + "ap-south-1|r6g.16xlarge": 2.080000, + "ap-south-1|r6g.2xlarge": 0.260000, + "ap-south-1|r6g.4xlarge": 0.520000, + "ap-south-1|r6g.8xlarge": 1.040000, + "ap-south-1|r6g.large": 0.065000, + "ap-south-1|r6g.medium": 0.032500, + "ap-south-1|r6g.metal": 2.080000, + "ap-south-1|r6g.xlarge": 0.130000, + "ap-south-1|r6gd.12xlarge": 1.793800, + "ap-south-1|r6gd.16xlarge": 2.391700, + "ap-south-1|r6gd.2xlarge": 0.299000, + "ap-south-1|r6gd.4xlarge": 0.597900, + "ap-south-1|r6gd.8xlarge": 1.195800, + "ap-south-1|r6gd.large": 0.074700, + "ap-south-1|r6gd.medium": 0.037400, + "ap-south-1|r6gd.metal": 2.391700, + "ap-south-1|r6gd.xlarge": 0.149500, + "ap-south-1|r6i.12xlarge": 3.120000, + "ap-south-1|r6i.16xlarge": 4.160000, + "ap-south-1|r6i.24xlarge": 6.240000, + "ap-south-1|r6i.2xlarge": 0.520000, + "ap-south-1|r6i.32xlarge": 8.320000, + "ap-south-1|r6i.4xlarge": 1.040000, + "ap-south-1|r6i.8xlarge": 2.080000, + "ap-south-1|r6i.large": 0.130000, + "ap-south-1|r6i.metal": 8.320000, + "ap-south-1|r6i.xlarge": 0.260000, + "ap-south-1|r6id.12xlarge": 3.806400, + "ap-south-1|r6id.16xlarge": 5.075200, + "ap-south-1|r6id.24xlarge": 7.612800, + "ap-south-1|r6id.2xlarge": 0.634400, + "ap-south-1|r6id.32xlarge": 10.150400, + "ap-south-1|r6id.4xlarge": 1.268800, + "ap-south-1|r6id.8xlarge": 2.537600, + "ap-south-1|r6id.large": 0.158600, + "ap-south-1|r6id.metal": 10.150400, + "ap-south-1|r6id.xlarge": 0.317200, + "ap-south-1|r7g.12xlarge": 1.801900, + "ap-south-1|r7g.16xlarge": 2.402600, + "ap-south-1|r7g.2xlarge": 0.300300, + "ap-south-1|r7g.4xlarge": 0.600600, + "ap-south-1|r7g.8xlarge": 1.201300, + "ap-south-1|r7g.large": 0.075100, + "ap-south-1|r7g.medium": 0.037500, + "ap-south-1|r7g.metal": 2.402600, + "ap-south-1|r7g.xlarge": 0.150200, + "ap-south-1|r7gd.12xlarge": 2.112000, + "ap-south-1|r7gd.16xlarge": 2.816000, + "ap-south-1|r7gd.2xlarge": 0.352000, + "ap-south-1|r7gd.4xlarge": 0.704000, + "ap-south-1|r7gd.8xlarge": 1.408000, + "ap-south-1|r7gd.large": 0.088000, + "ap-south-1|r7gd.medium": 0.044000, + "ap-south-1|r7gd.metal": 2.816000, + "ap-south-1|r7gd.xlarge": 0.176000, + "ap-south-1|r7i.12xlarge": 3.276000, + "ap-south-1|r7i.16xlarge": 4.368000, + "ap-south-1|r7i.24xlarge": 6.552000, + "ap-south-1|r7i.2xlarge": 0.546000, + "ap-south-1|r7i.48xlarge": 13.104000, + "ap-south-1|r7i.4xlarge": 1.092000, + "ap-south-1|r7i.8xlarge": 2.184000, + "ap-south-1|r7i.large": 0.136500, + "ap-south-1|r7i.metal-24xl": 6.552000, + "ap-south-1|r7i.metal-48xl": 13.104000, + "ap-south-1|r7i.xlarge": 0.273000, + "ap-south-1|r8g.12xlarge": 1.981920, + "ap-south-1|r8g.16xlarge": 2.642560, + "ap-south-1|r8g.24xlarge": 3.963840, + "ap-south-1|r8g.2xlarge": 0.330320, + "ap-south-1|r8g.48xlarge": 7.927680, + "ap-south-1|r8g.4xlarge": 0.660640, + "ap-south-1|r8g.8xlarge": 1.321280, + "ap-south-1|r8g.large": 0.082580, + "ap-south-1|r8g.medium": 0.041290, + "ap-south-1|r8g.metal-24xl": 3.963840, + "ap-south-1|r8g.metal-48xl": 7.927680, + "ap-south-1|r8g.xlarge": 0.165160, + "ap-south-1|r8i-flex.12xlarge": 3.267840, + "ap-south-1|r8i-flex.16xlarge": 4.357120, + "ap-south-1|r8i-flex.2xlarge": 0.544640, + "ap-south-1|r8i-flex.4xlarge": 1.089280, + "ap-south-1|r8i-flex.8xlarge": 2.178560, + "ap-south-1|r8i-flex.large": 0.136160, + "ap-south-1|r8i-flex.xlarge": 0.272320, + "ap-south-1|r8i.12xlarge": 3.439920, + "ap-south-1|r8i.16xlarge": 4.586560, + "ap-south-1|r8i.24xlarge": 6.879840, + "ap-south-1|r8i.2xlarge": 0.573320, + "ap-south-1|r8i.32xlarge": 9.173120, + "ap-south-1|r8i.48xlarge": 13.759680, + "ap-south-1|r8i.4xlarge": 1.146640, + "ap-south-1|r8i.8xlarge": 2.293280, + "ap-south-1|r8i.96xlarge": 27.519360, + "ap-south-1|r8i.large": 0.143330, + "ap-south-1|r8i.metal-48xl": 13.759680, + "ap-south-1|r8i.metal-96xl": 27.519360, + "ap-south-1|r8i.xlarge": 0.286660, + "ap-south-1|t2.2xlarge": 0.396800, + "ap-south-1|t2.large": 0.099200, + "ap-south-1|t2.medium": 0.049600, + "ap-south-1|t2.micro": 0.012400, + "ap-south-1|t2.nano": 0.006200, + "ap-south-1|t2.small": 0.024800, + "ap-south-1|t2.xlarge": 0.198400, + "ap-south-1|t3.2xlarge": 0.358400, + "ap-south-1|t3.large": 0.089600, + "ap-south-1|t3.medium": 0.044800, + "ap-south-1|t3.micro": 0.011200, + "ap-south-1|t3.nano": 0.005600, + "ap-south-1|t3.small": 0.022400, + "ap-south-1|t3.xlarge": 0.179200, + "ap-south-1|t3a.2xlarge": 0.197100, + "ap-south-1|t3a.large": 0.049300, + "ap-south-1|t3a.medium": 0.024600, + "ap-south-1|t3a.micro": 0.006200, + "ap-south-1|t3a.nano": 0.003100, + "ap-south-1|t3a.small": 0.012300, + "ap-south-1|t3a.xlarge": 0.098600, + "ap-south-1|t4g.2xlarge": 0.179200, + "ap-south-1|t4g.large": 0.044800, + "ap-south-1|t4g.medium": 0.022400, + "ap-south-1|t4g.micro": 0.005600, + "ap-south-1|t4g.nano": 0.002800, + "ap-south-1|t4g.small": 0.011200, + "ap-south-1|t4g.xlarge": 0.089600, + "ap-south-1|u-12tb1.112xlarge": 112.667000, + "ap-south-1|u-6tb1.112xlarge": 56.333000, + "ap-south-1|u-6tb1.56xlarge": 47.876760, + "ap-south-1|u-9tb1.112xlarge": 84.500000, + "ap-south-1|u7i-12tb.224xlarge": 129.566690, + "ap-south-1|u7i-6tb.112xlarge": 64.782950, + "ap-south-1|u7i-8tb.112xlarge": 86.377780, + "ap-south-1|u7in-16tb.224xlarge": 186.204960, + "ap-south-1|x1.16xlarge": 6.881000, + "ap-south-1|x1.32xlarge": 13.762000, + "ap-south-1|x1e.16xlarge": 13.760000, + "ap-south-1|x1e.2xlarge": 1.720000, + "ap-south-1|x1e.32xlarge": 27.520000, + "ap-south-1|x1e.4xlarge": 3.440000, + "ap-south-1|x1e.8xlarge": 6.880000, + "ap-south-1|x1e.xlarge": 0.860000, + "ap-south-1|x2idn.16xlarge": 6.881000, + "ap-south-1|x2idn.24xlarge": 10.321500, + "ap-south-1|x2idn.32xlarge": 13.762000, + "ap-south-1|x2idn.metal": 13.762000, + "ap-south-1|x2iedn.16xlarge": 13.762000, + "ap-south-1|x2iedn.24xlarge": 20.643000, + "ap-south-1|x2iedn.2xlarge": 1.720250, + "ap-south-1|x2iedn.32xlarge": 27.524000, + "ap-south-1|x2iedn.4xlarge": 3.440500, + "ap-south-1|x2iedn.8xlarge": 6.881000, + "ap-south-1|x2iedn.metal": 27.524000, + "ap-south-1|x2iedn.xlarge": 0.860130, + "ap-south-1|z1d.12xlarge": 4.704000, + "ap-south-1|z1d.2xlarge": 0.784000, + "ap-south-1|z1d.3xlarge": 1.176000, + "ap-south-1|z1d.6xlarge": 2.352000, + "ap-south-1|z1d.large": 0.196000, + "ap-south-1|z1d.metal": 4.704000, + "ap-south-1|z1d.xlarge": 0.392000, + "ap-southeast-1|a1.2xlarge": 0.235200, + "ap-southeast-1|a1.4xlarge": 0.470400, + "ap-southeast-1|a1.large": 0.058800, + "ap-southeast-1|a1.medium": 0.029400, + "ap-southeast-1|a1.metal": 0.470000, + "ap-southeast-1|a1.xlarge": 0.117600, + "ap-southeast-1|c1.medium": 0.164000, + "ap-southeast-1|c1.xlarge": 0.655000, + "ap-southeast-1|c3.2xlarge": 0.529000, + "ap-southeast-1|c3.4xlarge": 1.058000, + "ap-southeast-1|c3.8xlarge": 2.117000, + "ap-southeast-1|c3.large": 0.132000, + "ap-southeast-1|c3.xlarge": 0.265000, + "ap-southeast-1|c4.2xlarge": 0.462000, + "ap-southeast-1|c4.4xlarge": 0.924000, + "ap-southeast-1|c4.8xlarge": 1.848000, + "ap-southeast-1|c4.large": 0.115000, + "ap-southeast-1|c4.xlarge": 0.231000, + "ap-southeast-1|c5.12xlarge": 2.352000, + "ap-southeast-1|c5.18xlarge": 3.528000, + "ap-southeast-1|c5.24xlarge": 4.704000, + "ap-southeast-1|c5.2xlarge": 0.392000, + "ap-southeast-1|c5.4xlarge": 0.784000, + "ap-southeast-1|c5.9xlarge": 1.764000, + "ap-southeast-1|c5.large": 0.098000, + "ap-southeast-1|c5.metal": 4.704000, + "ap-southeast-1|c5.xlarge": 0.196000, + "ap-southeast-1|c5a.12xlarge": 2.112000, + "ap-southeast-1|c5a.16xlarge": 2.816000, + "ap-southeast-1|c5a.24xlarge": 4.224000, + "ap-southeast-1|c5a.2xlarge": 0.352000, + "ap-southeast-1|c5a.4xlarge": 0.704000, + "ap-southeast-1|c5a.8xlarge": 1.408000, + "ap-southeast-1|c5a.large": 0.088000, + "ap-southeast-1|c5a.xlarge": 0.176000, + "ap-southeast-1|c5ad.12xlarge": 2.424000, + "ap-southeast-1|c5ad.16xlarge": 3.232000, + "ap-southeast-1|c5ad.24xlarge": 4.848000, + "ap-southeast-1|c5ad.2xlarge": 0.404000, + "ap-southeast-1|c5ad.4xlarge": 0.808000, + "ap-southeast-1|c5ad.8xlarge": 1.616000, + "ap-southeast-1|c5ad.large": 0.101000, + "ap-southeast-1|c5ad.xlarge": 0.202000, + "ap-southeast-1|c5d.12xlarge": 2.688000, + "ap-southeast-1|c5d.18xlarge": 4.032000, + "ap-southeast-1|c5d.24xlarge": 5.376000, + "ap-southeast-1|c5d.2xlarge": 0.448000, + "ap-southeast-1|c5d.4xlarge": 0.896000, + "ap-southeast-1|c5d.9xlarge": 2.016000, + "ap-southeast-1|c5d.large": 0.112000, + "ap-southeast-1|c5d.metal": 5.376000, + "ap-southeast-1|c5d.xlarge": 0.224000, + "ap-southeast-1|c5n.18xlarge": 4.464000, + "ap-southeast-1|c5n.2xlarge": 0.496000, + "ap-southeast-1|c5n.4xlarge": 0.992000, + "ap-southeast-1|c5n.9xlarge": 2.232000, + "ap-southeast-1|c5n.large": 0.124000, + "ap-southeast-1|c5n.metal": 4.464000, + "ap-southeast-1|c5n.xlarge": 0.248000, + "ap-southeast-1|c6a.12xlarge": 2.116800, + "ap-southeast-1|c6a.16xlarge": 2.822400, + "ap-southeast-1|c6a.24xlarge": 4.233600, + "ap-southeast-1|c6a.2xlarge": 0.352800, + "ap-southeast-1|c6a.32xlarge": 5.644800, + "ap-southeast-1|c6a.48xlarge": 8.467200, + "ap-southeast-1|c6a.4xlarge": 0.705600, + "ap-southeast-1|c6a.8xlarge": 1.411200, + "ap-southeast-1|c6a.large": 0.088200, + "ap-southeast-1|c6a.metal": 8.467200, + "ap-southeast-1|c6a.xlarge": 0.176400, + "ap-southeast-1|c6g.12xlarge": 1.881600, + "ap-southeast-1|c6g.16xlarge": 2.508800, + "ap-southeast-1|c6g.2xlarge": 0.313600, + "ap-southeast-1|c6g.4xlarge": 0.627200, + "ap-southeast-1|c6g.8xlarge": 1.254400, + "ap-southeast-1|c6g.large": 0.078400, + "ap-southeast-1|c6g.medium": 0.039200, + "ap-southeast-1|c6g.metal": 2.508800, + "ap-southeast-1|c6g.xlarge": 0.156800, + "ap-southeast-1|c6gd.12xlarge": 2.160000, + "ap-southeast-1|c6gd.16xlarge": 2.880000, + "ap-southeast-1|c6gd.2xlarge": 0.360000, + "ap-southeast-1|c6gd.4xlarge": 0.720000, + "ap-southeast-1|c6gd.8xlarge": 1.440000, + "ap-southeast-1|c6gd.large": 0.090000, + "ap-southeast-1|c6gd.medium": 0.045000, + "ap-southeast-1|c6gd.metal": 2.880000, + "ap-southeast-1|c6gd.xlarge": 0.180000, + "ap-southeast-1|c6gn.12xlarge": 2.376000, + "ap-southeast-1|c6gn.16xlarge": 3.168000, + "ap-southeast-1|c6gn.2xlarge": 0.396000, + "ap-southeast-1|c6gn.4xlarge": 0.792000, + "ap-southeast-1|c6gn.8xlarge": 1.584000, + "ap-southeast-1|c6gn.large": 0.099000, + "ap-southeast-1|c6gn.medium": 0.049500, + "ap-southeast-1|c6gn.xlarge": 0.198000, + "ap-southeast-1|c6i.12xlarge": 2.352000, + "ap-southeast-1|c6i.16xlarge": 3.136000, + "ap-southeast-1|c6i.24xlarge": 4.704000, + "ap-southeast-1|c6i.2xlarge": 0.392000, + "ap-southeast-1|c6i.32xlarge": 6.272000, + "ap-southeast-1|c6i.4xlarge": 0.784000, + "ap-southeast-1|c6i.8xlarge": 1.568000, + "ap-southeast-1|c6i.large": 0.098000, + "ap-southeast-1|c6i.metal": 6.272000, + "ap-southeast-1|c6i.xlarge": 0.196000, + "ap-southeast-1|c6id.12xlarge": 2.822400, + "ap-southeast-1|c6id.16xlarge": 3.763200, + "ap-southeast-1|c6id.24xlarge": 5.644800, + "ap-southeast-1|c6id.2xlarge": 0.470400, + "ap-southeast-1|c6id.32xlarge": 7.526400, + "ap-southeast-1|c6id.4xlarge": 0.940800, + "ap-southeast-1|c6id.8xlarge": 1.881600, + "ap-southeast-1|c6id.large": 0.117600, + "ap-southeast-1|c6id.metal": 7.526400, + "ap-southeast-1|c6id.xlarge": 0.235200, + "ap-southeast-1|c6in.12xlarge": 3.124800, + "ap-southeast-1|c6in.16xlarge": 4.166400, + "ap-southeast-1|c6in.24xlarge": 6.249600, + "ap-southeast-1|c6in.2xlarge": 0.520800, + "ap-southeast-1|c6in.32xlarge": 8.332800, + "ap-southeast-1|c6in.4xlarge": 1.041600, + "ap-southeast-1|c6in.8xlarge": 2.083200, + "ap-southeast-1|c6in.large": 0.130200, + "ap-southeast-1|c6in.metal": 8.332800, + "ap-southeast-1|c6in.xlarge": 0.260400, + "ap-southeast-1|c7g.12xlarge": 1.999200, + "ap-southeast-1|c7g.16xlarge": 2.665600, + "ap-southeast-1|c7g.2xlarge": 0.333200, + "ap-southeast-1|c7g.4xlarge": 0.666400, + "ap-southeast-1|c7g.8xlarge": 1.332800, + "ap-southeast-1|c7g.large": 0.083300, + "ap-southeast-1|c7g.medium": 0.041700, + "ap-southeast-1|c7g.metal": 2.665600, + "ap-southeast-1|c7g.xlarge": 0.166600, + "ap-southeast-1|c7gd.12xlarge": 2.540200, + "ap-southeast-1|c7gd.16xlarge": 3.386900, + "ap-southeast-1|c7gd.2xlarge": 0.423400, + "ap-southeast-1|c7gd.4xlarge": 0.846700, + "ap-southeast-1|c7gd.8xlarge": 1.693400, + "ap-southeast-1|c7gd.large": 0.105800, + "ap-southeast-1|c7gd.medium": 0.052900, + "ap-southeast-1|c7gd.metal": 3.386900, + "ap-southeast-1|c7gd.xlarge": 0.211700, + "ap-southeast-1|c7i-flex.12xlarge": 2.346610, + "ap-southeast-1|c7i-flex.16xlarge": 3.128820, + "ap-southeast-1|c7i-flex.2xlarge": 0.391100, + "ap-southeast-1|c7i-flex.4xlarge": 0.782200, + "ap-southeast-1|c7i-flex.8xlarge": 1.564410, + "ap-southeast-1|c7i-flex.large": 0.097780, + "ap-southeast-1|c7i-flex.xlarge": 0.195550, + "ap-southeast-1|c7i.12xlarge": 2.469600, + "ap-southeast-1|c7i.16xlarge": 3.292800, + "ap-southeast-1|c7i.24xlarge": 4.939200, + "ap-southeast-1|c7i.2xlarge": 0.411600, + "ap-southeast-1|c7i.48xlarge": 9.878400, + "ap-southeast-1|c7i.4xlarge": 0.823200, + "ap-southeast-1|c7i.8xlarge": 1.646400, + "ap-southeast-1|c7i.large": 0.102900, + "ap-southeast-1|c7i.metal-24xl": 4.939200, + "ap-southeast-1|c7i.metal-48xl": 9.878400, + "ap-southeast-1|c7i.xlarge": 0.205800, + "ap-southeast-1|c8g.12xlarge": 2.199360, + "ap-southeast-1|c8g.16xlarge": 2.932480, + "ap-southeast-1|c8g.24xlarge": 4.398720, + "ap-southeast-1|c8g.2xlarge": 0.366560, + "ap-southeast-1|c8g.48xlarge": 8.797440, + "ap-southeast-1|c8g.4xlarge": 0.733120, + "ap-southeast-1|c8g.8xlarge": 1.466240, + "ap-southeast-1|c8g.large": 0.091640, + "ap-southeast-1|c8g.medium": 0.045820, + "ap-southeast-1|c8g.metal-24xl": 4.398720, + "ap-southeast-1|c8g.metal-48xl": 8.797440, + "ap-southeast-1|c8g.xlarge": 0.183280, + "ap-southeast-1|c8gn.12xlarge": 3.265400, + "ap-southeast-1|c8gn.16xlarge": 4.353900, + "ap-southeast-1|c8gn.24xlarge": 6.530900, + "ap-southeast-1|c8gn.2xlarge": 0.544200, + "ap-southeast-1|c8gn.48xlarge": 13.061800, + "ap-southeast-1|c8gn.4xlarge": 1.088500, + "ap-southeast-1|c8gn.8xlarge": 2.177000, + "ap-southeast-1|c8gn.large": 0.136100, + "ap-southeast-1|c8gn.medium": 0.068000, + "ap-southeast-1|c8gn.xlarge": 0.272100, + "ap-southeast-1|c8i-flex.12xlarge": 2.463600, + "ap-southeast-1|c8i-flex.16xlarge": 3.284800, + "ap-southeast-1|c8i-flex.2xlarge": 0.410600, + "ap-southeast-1|c8i-flex.4xlarge": 0.821200, + "ap-southeast-1|c8i-flex.8xlarge": 1.642400, + "ap-southeast-1|c8i-flex.large": 0.102650, + "ap-southeast-1|c8i-flex.xlarge": 0.205300, + "ap-southeast-1|c8i.12xlarge": 2.593200, + "ap-southeast-1|c8i.16xlarge": 3.457600, + "ap-southeast-1|c8i.24xlarge": 5.186400, + "ap-southeast-1|c8i.2xlarge": 0.432200, + "ap-southeast-1|c8i.32xlarge": 6.915200, + "ap-southeast-1|c8i.48xlarge": 10.372800, + "ap-southeast-1|c8i.4xlarge": 0.864400, + "ap-southeast-1|c8i.8xlarge": 1.728800, + "ap-southeast-1|c8i.96xlarge": 20.745600, + "ap-southeast-1|c8i.large": 0.108050, + "ap-southeast-1|c8i.metal-48xl": 10.372800, + "ap-southeast-1|c8i.metal-96xl": 20.745600, + "ap-southeast-1|c8i.xlarge": 0.216100, + "ap-southeast-1|d2.2xlarge": 1.740000, + "ap-southeast-1|d2.4xlarge": 3.480000, + "ap-southeast-1|d2.8xlarge": 6.960000, + "ap-southeast-1|d2.xlarge": 0.870000, + "ap-southeast-1|d3.2xlarge": 1.252000, + "ap-southeast-1|d3.4xlarge": 2.504000, + "ap-southeast-1|d3.8xlarge": 5.008080, + "ap-southeast-1|d3.xlarge": 0.626000, + "ap-southeast-1|d3en.12xlarge": 7.907520, + "ap-southeast-1|d3en.2xlarge": 1.318000, + "ap-southeast-1|d3en.4xlarge": 2.636000, + "ap-southeast-1|d3en.6xlarge": 3.954000, + "ap-southeast-1|d3en.8xlarge": 5.271680, + "ap-southeast-1|d3en.xlarge": 0.659000, + "ap-southeast-1|g2.2xlarge": 1.000000, + "ap-southeast-1|g2.8xlarge": 4.000000, + "ap-southeast-1|g3.16xlarge": 6.680000, + "ap-southeast-1|g3.4xlarge": 1.670000, + "ap-southeast-1|g3.8xlarge": 3.340000, + "ap-southeast-1|g4dn.12xlarge": 5.474000, + "ap-southeast-1|g4dn.16xlarge": 6.089000, + "ap-southeast-1|g4dn.2xlarge": 1.052000, + "ap-southeast-1|g4dn.4xlarge": 1.685000, + "ap-southeast-1|g4dn.8xlarge": 3.045000, + "ap-southeast-1|g4dn.metal": 10.948000, + "ap-southeast-1|g4dn.xlarge": 0.736000, + "ap-southeast-1|g5g.16xlarge": 3.839500, + "ap-southeast-1|g5g.2xlarge": 0.778000, + "ap-southeast-1|g5g.4xlarge": 1.158600, + "ap-southeast-1|g5g.8xlarge": 1.919800, + "ap-southeast-1|g5g.metal": 3.839500, + "ap-southeast-1|g5g.xlarge": 0.587700, + "ap-southeast-1|hpc6a.48xlarge": 3.320500, + "ap-southeast-1|i2.2xlarge": 2.035000, + "ap-southeast-1|i2.4xlarge": 4.070000, + "ap-southeast-1|i2.8xlarge": 8.140000, + "ap-southeast-1|i2.xlarge": 1.018000, + "ap-southeast-1|i3.16xlarge": 5.984000, + "ap-southeast-1|i3.2xlarge": 0.748000, + "ap-southeast-1|i3.4xlarge": 1.496000, + "ap-southeast-1|i3.8xlarge": 2.992000, + "ap-southeast-1|i3.large": 0.187000, + "ap-southeast-1|i3.metal": 5.984000, + "ap-southeast-1|i3.xlarge": 0.374000, + "ap-southeast-1|i3en.12xlarge": 6.504000, + "ap-southeast-1|i3en.24xlarge": 13.008000, + "ap-southeast-1|i3en.2xlarge": 1.084000, + "ap-southeast-1|i3en.3xlarge": 1.626000, + "ap-southeast-1|i3en.6xlarge": 3.252000, + "ap-southeast-1|i3en.large": 0.271000, + "ap-southeast-1|i3en.metal": 13.008000, + "ap-southeast-1|i3en.xlarge": 0.542000, + "ap-southeast-1|i4g.16xlarge": 5.924160, + "ap-southeast-1|i4g.2xlarge": 0.740520, + "ap-southeast-1|i4g.4xlarge": 1.481040, + "ap-southeast-1|i4g.8xlarge": 2.962080, + "ap-southeast-1|i4g.large": 0.185130, + "ap-southeast-1|i4g.xlarge": 0.370260, + "ap-southeast-1|i4i.12xlarge": 4.937000, + "ap-southeast-1|i4i.16xlarge": 6.582000, + "ap-southeast-1|i4i.24xlarge": 9.873600, + "ap-southeast-1|i4i.2xlarge": 0.823000, + "ap-southeast-1|i4i.32xlarge": 13.164800, + "ap-southeast-1|i4i.4xlarge": 1.646000, + "ap-southeast-1|i4i.8xlarge": 3.291000, + "ap-southeast-1|i4i.large": 0.206000, + "ap-southeast-1|i4i.metal": 13.165000, + "ap-southeast-1|i4i.xlarge": 0.411000, + "ap-southeast-1|i7i.12xlarge": 5.430500, + "ap-southeast-1|i7i.16xlarge": 7.240600, + "ap-southeast-1|i7i.24xlarge": 10.861000, + "ap-southeast-1|i7i.2xlarge": 0.905100, + "ap-southeast-1|i7i.48xlarge": 21.721900, + "ap-southeast-1|i7i.4xlarge": 1.810200, + "ap-southeast-1|i7i.8xlarge": 3.620300, + "ap-southeast-1|i7i.large": 0.226300, + "ap-southeast-1|i7i.metal-24xl": 10.861000, + "ap-southeast-1|i7i.metal-48xl": 21.721900, + "ap-southeast-1|i7i.xlarge": 0.452500, + "ap-southeast-1|i7ie.12xlarge": 7.479600, + "ap-southeast-1|i7ie.18xlarge": 11.219400, + "ap-southeast-1|i7ie.24xlarge": 14.959200, + "ap-southeast-1|i7ie.2xlarge": 1.246600, + "ap-southeast-1|i7ie.3xlarge": 1.869900, + "ap-southeast-1|i7ie.48xlarge": 29.918400, + "ap-southeast-1|i7ie.6xlarge": 3.739800, + "ap-southeast-1|i7ie.large": 0.311700, + "ap-southeast-1|i7ie.metal-24xl": 14.959200, + "ap-southeast-1|i7ie.metal-48xl": 29.918400, + "ap-southeast-1|i7ie.xlarge": 0.623300, + "ap-southeast-1|i8g.12xlarge": 4.936800, + "ap-southeast-1|i8g.16xlarge": 6.582400, + "ap-southeast-1|i8g.24xlarge": 9.873600, + "ap-southeast-1|i8g.2xlarge": 0.822800, + "ap-southeast-1|i8g.48xlarge": 19.747200, + "ap-southeast-1|i8g.4xlarge": 1.645600, + "ap-southeast-1|i8g.8xlarge": 3.291200, + "ap-southeast-1|i8g.large": 0.205700, + "ap-southeast-1|i8g.metal-24xl": 9.873600, + "ap-southeast-1|i8g.xlarge": 0.411400, + "ap-southeast-1|im4gn.16xlarge": 6.977340, + "ap-southeast-1|im4gn.2xlarge": 0.872170, + "ap-southeast-1|im4gn.4xlarge": 1.744340, + "ap-southeast-1|im4gn.8xlarge": 3.488670, + "ap-southeast-1|im4gn.large": 0.218040, + "ap-southeast-1|im4gn.xlarge": 0.436080, + "ap-southeast-1|inf1.24xlarge": 6.376000, + "ap-southeast-1|inf1.2xlarge": 0.489000, + "ap-southeast-1|inf1.6xlarge": 1.594000, + "ap-southeast-1|inf1.xlarge": 0.308000, + "ap-southeast-1|inf2.24xlarge": 9.086890, + "ap-southeast-1|inf2.48xlarge": 18.173770, + "ap-southeast-1|inf2.8xlarge": 2.755000, + "ap-southeast-1|inf2.xlarge": 1.061480, + "ap-southeast-1|is4gen.2xlarge": 1.382100, + "ap-southeast-1|is4gen.4xlarge": 2.764210, + "ap-southeast-1|is4gen.8xlarge": 5.528420, + "ap-southeast-1|is4gen.large": 0.345530, + "ap-southeast-1|is4gen.medium": 0.172760, + "ap-southeast-1|is4gen.xlarge": 0.691050, + "ap-southeast-1|m1.large": 0.233000, + "ap-southeast-1|m1.medium": 0.117000, + "ap-southeast-1|m1.small": 0.058000, + "ap-southeast-1|m1.xlarge": 0.467000, + "ap-southeast-1|m2.2xlarge": 0.592000, + "ap-southeast-1|m2.4xlarge": 1.183000, + "ap-southeast-1|m2.xlarge": 0.296000, + "ap-southeast-1|m3.2xlarge": 0.784000, + "ap-southeast-1|m3.large": 0.196000, + "ap-southeast-1|m3.medium": 0.098000, + "ap-southeast-1|m3.xlarge": 0.392000, + "ap-southeast-1|m4.10xlarge": 2.500000, + "ap-southeast-1|m4.16xlarge": 4.000000, + "ap-southeast-1|m4.2xlarge": 0.500000, + "ap-southeast-1|m4.4xlarge": 1.000000, + "ap-southeast-1|m4.large": 0.125000, + "ap-southeast-1|m4.xlarge": 0.250000, + "ap-southeast-1|m5.12xlarge": 2.880000, + "ap-southeast-1|m5.16xlarge": 3.840000, + "ap-southeast-1|m5.24xlarge": 5.760000, + "ap-southeast-1|m5.2xlarge": 0.480000, + "ap-southeast-1|m5.4xlarge": 0.960000, + "ap-southeast-1|m5.8xlarge": 1.920000, + "ap-southeast-1|m5.large": 0.120000, + "ap-southeast-1|m5.metal": 5.760000, + "ap-southeast-1|m5.xlarge": 0.240000, + "ap-southeast-1|m5a.12xlarge": 2.592000, + "ap-southeast-1|m5a.16xlarge": 3.456000, + "ap-southeast-1|m5a.24xlarge": 5.184000, + "ap-southeast-1|m5a.2xlarge": 0.432000, + "ap-southeast-1|m5a.4xlarge": 0.864000, + "ap-southeast-1|m5a.8xlarge": 1.728000, + "ap-southeast-1|m5a.large": 0.108000, + "ap-southeast-1|m5a.xlarge": 0.216000, + "ap-southeast-1|m5ad.12xlarge": 3.096000, + "ap-southeast-1|m5ad.16xlarge": 4.128000, + "ap-southeast-1|m5ad.24xlarge": 6.192000, + "ap-southeast-1|m5ad.2xlarge": 0.516000, + "ap-southeast-1|m5ad.4xlarge": 1.032000, + "ap-southeast-1|m5ad.8xlarge": 2.064000, + "ap-southeast-1|m5ad.large": 0.129000, + "ap-southeast-1|m5ad.xlarge": 0.258000, + "ap-southeast-1|m5d.12xlarge": 3.384000, + "ap-southeast-1|m5d.16xlarge": 4.512000, + "ap-southeast-1|m5d.24xlarge": 6.768000, + "ap-southeast-1|m5d.2xlarge": 0.564000, + "ap-southeast-1|m5d.4xlarge": 1.128000, + "ap-southeast-1|m5d.8xlarge": 2.256000, + "ap-southeast-1|m5d.large": 0.141000, + "ap-southeast-1|m5d.metal": 6.768000, + "ap-southeast-1|m5d.xlarge": 0.282000, + "ap-southeast-1|m5dn.12xlarge": 4.008000, + "ap-southeast-1|m5dn.16xlarge": 5.344000, + "ap-southeast-1|m5dn.24xlarge": 8.016000, + "ap-southeast-1|m5dn.2xlarge": 0.668000, + "ap-southeast-1|m5dn.4xlarge": 1.336000, + "ap-southeast-1|m5dn.8xlarge": 2.672000, + "ap-southeast-1|m5dn.large": 0.167000, + "ap-southeast-1|m5dn.metal": 8.016000, + "ap-southeast-1|m5dn.xlarge": 0.334000, + "ap-southeast-1|m5n.12xlarge": 3.504000, + "ap-southeast-1|m5n.16xlarge": 4.672000, + "ap-southeast-1|m5n.24xlarge": 7.008000, + "ap-southeast-1|m5n.2xlarge": 0.584000, + "ap-southeast-1|m5n.4xlarge": 1.168000, + "ap-southeast-1|m5n.8xlarge": 2.336000, + "ap-southeast-1|m5n.large": 0.146000, + "ap-southeast-1|m5n.metal": 7.008000, + "ap-southeast-1|m5n.xlarge": 0.292000, + "ap-southeast-1|m5zn.12xlarge": 4.956000, + "ap-southeast-1|m5zn.2xlarge": 0.826000, + "ap-southeast-1|m5zn.3xlarge": 1.239000, + "ap-southeast-1|m5zn.6xlarge": 2.478000, + "ap-southeast-1|m5zn.large": 0.206500, + "ap-southeast-1|m5zn.metal": 4.956000, + "ap-southeast-1|m5zn.xlarge": 0.413000, + "ap-southeast-1|m6a.12xlarge": 2.592000, + "ap-southeast-1|m6a.16xlarge": 3.456000, + "ap-southeast-1|m6a.24xlarge": 5.184000, + "ap-southeast-1|m6a.2xlarge": 0.432000, + "ap-southeast-1|m6a.32xlarge": 6.912000, + "ap-southeast-1|m6a.48xlarge": 10.368000, + "ap-southeast-1|m6a.4xlarge": 0.864000, + "ap-southeast-1|m6a.8xlarge": 1.728000, + "ap-southeast-1|m6a.large": 0.108000, + "ap-southeast-1|m6a.metal": 10.368000, + "ap-southeast-1|m6a.xlarge": 0.216000, + "ap-southeast-1|m6g.12xlarge": 2.304000, + "ap-southeast-1|m6g.16xlarge": 3.072000, + "ap-southeast-1|m6g.2xlarge": 0.384000, + "ap-southeast-1|m6g.4xlarge": 0.768000, + "ap-southeast-1|m6g.8xlarge": 1.536000, + "ap-southeast-1|m6g.large": 0.096000, + "ap-southeast-1|m6g.medium": 0.048000, + "ap-southeast-1|m6g.metal": 3.072000, + "ap-southeast-1|m6g.xlarge": 0.192000, + "ap-southeast-1|m6gd.12xlarge": 2.712000, + "ap-southeast-1|m6gd.16xlarge": 3.616000, + "ap-southeast-1|m6gd.2xlarge": 0.452000, + "ap-southeast-1|m6gd.4xlarge": 0.904000, + "ap-southeast-1|m6gd.8xlarge": 1.808000, + "ap-southeast-1|m6gd.large": 0.113000, + "ap-southeast-1|m6gd.medium": 0.056500, + "ap-southeast-1|m6gd.metal": 3.616000, + "ap-southeast-1|m6gd.xlarge": 0.226000, + "ap-southeast-1|m6i.12xlarge": 2.880000, + "ap-southeast-1|m6i.16xlarge": 3.840000, + "ap-southeast-1|m6i.24xlarge": 5.760000, + "ap-southeast-1|m6i.2xlarge": 0.480000, + "ap-southeast-1|m6i.32xlarge": 7.680000, + "ap-southeast-1|m6i.4xlarge": 0.960000, + "ap-southeast-1|m6i.8xlarge": 1.920000, + "ap-southeast-1|m6i.large": 0.120000, + "ap-southeast-1|m6i.metal": 7.680000, + "ap-southeast-1|m6i.xlarge": 0.240000, + "ap-southeast-1|m6id.12xlarge": 3.553200, + "ap-southeast-1|m6id.16xlarge": 4.737600, + "ap-southeast-1|m6id.24xlarge": 7.106400, + "ap-southeast-1|m6id.2xlarge": 0.592200, + "ap-southeast-1|m6id.32xlarge": 9.475200, + "ap-southeast-1|m6id.4xlarge": 1.184400, + "ap-southeast-1|m6id.8xlarge": 2.368800, + "ap-southeast-1|m6id.large": 0.148050, + "ap-southeast-1|m6id.metal": 9.475200, + "ap-southeast-1|m6id.xlarge": 0.296100, + "ap-southeast-1|m6idn.12xlarge": 4.689360, + "ap-southeast-1|m6idn.16xlarge": 6.252480, + "ap-southeast-1|m6idn.24xlarge": 9.378720, + "ap-southeast-1|m6idn.2xlarge": 0.781560, + "ap-southeast-1|m6idn.32xlarge": 12.504960, + "ap-southeast-1|m6idn.4xlarge": 1.563120, + "ap-southeast-1|m6idn.8xlarge": 3.126240, + "ap-southeast-1|m6idn.large": 0.195390, + "ap-southeast-1|m6idn.metal": 12.504960, + "ap-southeast-1|m6idn.xlarge": 0.390780, + "ap-southeast-1|m6in.12xlarge": 4.099680, + "ap-southeast-1|m6in.16xlarge": 5.466240, + "ap-southeast-1|m6in.24xlarge": 8.199360, + "ap-southeast-1|m6in.2xlarge": 0.683280, + "ap-southeast-1|m6in.32xlarge": 10.932480, + "ap-southeast-1|m6in.4xlarge": 1.366560, + "ap-southeast-1|m6in.8xlarge": 2.733120, + "ap-southeast-1|m6in.large": 0.170820, + "ap-southeast-1|m6in.metal": 10.932480, + "ap-southeast-1|m6in.xlarge": 0.341640, + "ap-southeast-1|m7g.12xlarge": 2.448000, + "ap-southeast-1|m7g.16xlarge": 3.264000, + "ap-southeast-1|m7g.2xlarge": 0.408000, + "ap-southeast-1|m7g.4xlarge": 0.816000, + "ap-southeast-1|m7g.8xlarge": 1.632000, + "ap-southeast-1|m7g.large": 0.102000, + "ap-southeast-1|m7g.medium": 0.051000, + "ap-southeast-1|m7g.metal": 3.264000, + "ap-southeast-1|m7g.xlarge": 0.204000, + "ap-southeast-1|m7gd.12xlarge": 3.197900, + "ap-southeast-1|m7gd.16xlarge": 4.263800, + "ap-southeast-1|m7gd.2xlarge": 0.533000, + "ap-southeast-1|m7gd.4xlarge": 1.066000, + "ap-southeast-1|m7gd.8xlarge": 2.131900, + "ap-southeast-1|m7gd.large": 0.133200, + "ap-southeast-1|m7gd.medium": 0.066600, + "ap-southeast-1|m7gd.metal": 4.263800, + "ap-southeast-1|m7gd.xlarge": 0.266500, + "ap-southeast-1|m7i-flex.12xlarge": 2.872800, + "ap-southeast-1|m7i-flex.16xlarge": 3.830400, + "ap-southeast-1|m7i-flex.2xlarge": 0.478800, + "ap-southeast-1|m7i-flex.4xlarge": 0.957600, + "ap-southeast-1|m7i-flex.8xlarge": 1.915200, + "ap-southeast-1|m7i-flex.large": 0.119700, + "ap-southeast-1|m7i-flex.xlarge": 0.239400, + "ap-southeast-1|m7i.12xlarge": 3.024000, + "ap-southeast-1|m7i.16xlarge": 4.032000, + "ap-southeast-1|m7i.24xlarge": 6.048000, + "ap-southeast-1|m7i.2xlarge": 0.504000, + "ap-southeast-1|m7i.48xlarge": 12.096000, + "ap-southeast-1|m7i.4xlarge": 1.008000, + "ap-southeast-1|m7i.8xlarge": 2.016000, + "ap-southeast-1|m7i.large": 0.126000, + "ap-southeast-1|m7i.metal-24xl": 6.048000, + "ap-southeast-1|m7i.metal-48xl": 12.096000, + "ap-southeast-1|m7i.xlarge": 0.252000, + "ap-southeast-1|m8g.12xlarge": 2.692800, + "ap-southeast-1|m8g.16xlarge": 3.590400, + "ap-southeast-1|m8g.24xlarge": 5.385600, + "ap-southeast-1|m8g.2xlarge": 0.448800, + "ap-southeast-1|m8g.48xlarge": 10.771200, + "ap-southeast-1|m8g.4xlarge": 0.897600, + "ap-southeast-1|m8g.8xlarge": 1.795200, + "ap-southeast-1|m8g.large": 0.112200, + "ap-southeast-1|m8g.medium": 0.056100, + "ap-southeast-1|m8g.metal-24xl": 5.385600, + "ap-southeast-1|m8g.metal-48xl": 10.771200, + "ap-southeast-1|m8g.xlarge": 0.224400, + "ap-southeast-1|m8i.12xlarge": 3.175200, + "ap-southeast-1|m8i.16xlarge": 4.233600, + "ap-southeast-1|m8i.24xlarge": 6.350400, + "ap-southeast-1|m8i.2xlarge": 0.529200, + "ap-southeast-1|m8i.32xlarge": 8.467200, + "ap-southeast-1|m8i.48xlarge": 12.700800, + "ap-southeast-1|m8i.4xlarge": 1.058400, + "ap-southeast-1|m8i.8xlarge": 2.116800, + "ap-southeast-1|m8i.96xlarge": 25.401600, + "ap-southeast-1|m8i.large": 0.132300, + "ap-southeast-1|m8i.metal-48xl": 12.700800, + "ap-southeast-1|m8i.metal-96xl": 25.401600, + "ap-southeast-1|m8i.xlarge": 0.264600, + "ap-southeast-1|p2.16xlarge": 27.488000, + "ap-southeast-1|p2.8xlarge": 13.744000, + "ap-southeast-1|p2.xlarge": 1.718000, + "ap-southeast-1|p3.16xlarge": 33.872000, + "ap-southeast-1|p3.2xlarge": 4.234000, + "ap-southeast-1|p3.8xlarge": 16.936000, + "ap-southeast-1|p4d.24xlarge": 26.349170, + "ap-southeast-1|p4de.24xlarge": 32.936460, + "ap-southeast-1|r3.2xlarge": 0.798000, + "ap-southeast-1|r3.4xlarge": 1.596000, + "ap-southeast-1|r3.8xlarge": 3.192000, + "ap-southeast-1|r3.large": 0.200000, + "ap-southeast-1|r3.xlarge": 0.399000, + "ap-southeast-1|r4.16xlarge": 5.120000, + "ap-southeast-1|r4.2xlarge": 0.640000, + "ap-southeast-1|r4.4xlarge": 1.280000, + "ap-southeast-1|r4.8xlarge": 2.560000, + "ap-southeast-1|r4.large": 0.160000, + "ap-southeast-1|r4.xlarge": 0.320000, + "ap-southeast-1|r5.12xlarge": 3.648000, + "ap-southeast-1|r5.16xlarge": 4.864000, + "ap-southeast-1|r5.24xlarge": 7.296000, + "ap-southeast-1|r5.2xlarge": 0.608000, + "ap-southeast-1|r5.4xlarge": 1.216000, + "ap-southeast-1|r5.8xlarge": 2.432000, + "ap-southeast-1|r5.large": 0.152000, + "ap-southeast-1|r5.metal": 7.296000, + "ap-southeast-1|r5.xlarge": 0.304000, + "ap-southeast-1|r5a.12xlarge": 3.264000, + "ap-southeast-1|r5a.16xlarge": 4.352000, + "ap-southeast-1|r5a.24xlarge": 6.528000, + "ap-southeast-1|r5a.2xlarge": 0.544000, + "ap-southeast-1|r5a.4xlarge": 1.088000, + "ap-southeast-1|r5a.8xlarge": 2.176000, + "ap-southeast-1|r5a.large": 0.136000, + "ap-southeast-1|r5a.xlarge": 0.272000, + "ap-southeast-1|r5ad.12xlarge": 3.816000, + "ap-southeast-1|r5ad.16xlarge": 5.088000, + "ap-southeast-1|r5ad.24xlarge": 7.632000, + "ap-southeast-1|r5ad.2xlarge": 0.636000, + "ap-southeast-1|r5ad.4xlarge": 1.272000, + "ap-southeast-1|r5ad.8xlarge": 2.544000, + "ap-southeast-1|r5ad.large": 0.159000, + "ap-southeast-1|r5ad.xlarge": 0.318000, + "ap-southeast-1|r5b.12xlarge": 4.272000, + "ap-southeast-1|r5b.16xlarge": 5.696000, + "ap-southeast-1|r5b.24xlarge": 8.544000, + "ap-southeast-1|r5b.2xlarge": 0.712000, + "ap-southeast-1|r5b.4xlarge": 1.424000, + "ap-southeast-1|r5b.8xlarge": 2.848000, + "ap-southeast-1|r5b.large": 0.178000, + "ap-southeast-1|r5b.metal": 8.544000, + "ap-southeast-1|r5b.xlarge": 0.356000, + "ap-southeast-1|r5d.12xlarge": 4.176000, + "ap-southeast-1|r5d.16xlarge": 5.568000, + "ap-southeast-1|r5d.24xlarge": 8.352000, + "ap-southeast-1|r5d.2xlarge": 0.696000, + "ap-southeast-1|r5d.4xlarge": 1.392000, + "ap-southeast-1|r5d.8xlarge": 2.784000, + "ap-southeast-1|r5d.large": 0.174000, + "ap-southeast-1|r5d.metal": 8.352000, + "ap-southeast-1|r5d.xlarge": 0.348000, + "ap-southeast-1|r5dn.12xlarge": 4.800000, + "ap-southeast-1|r5dn.16xlarge": 6.400000, + "ap-southeast-1|r5dn.24xlarge": 9.600000, + "ap-southeast-1|r5dn.2xlarge": 0.800000, + "ap-southeast-1|r5dn.4xlarge": 1.600000, + "ap-southeast-1|r5dn.8xlarge": 3.200000, + "ap-southeast-1|r5dn.large": 0.200000, + "ap-southeast-1|r5dn.metal": 9.600000, + "ap-southeast-1|r5dn.xlarge": 0.400000, + "ap-southeast-1|r5n.12xlarge": 4.272000, + "ap-southeast-1|r5n.16xlarge": 5.696000, + "ap-southeast-1|r5n.24xlarge": 8.544000, + "ap-southeast-1|r5n.2xlarge": 0.712000, + "ap-southeast-1|r5n.4xlarge": 1.424000, + "ap-southeast-1|r5n.8xlarge": 2.848000, + "ap-southeast-1|r5n.large": 0.178000, + "ap-southeast-1|r5n.metal": 8.544000, + "ap-southeast-1|r5n.xlarge": 0.356000, + "ap-southeast-1|r6a.12xlarge": 3.283200, + "ap-southeast-1|r6a.16xlarge": 4.377600, + "ap-southeast-1|r6a.24xlarge": 6.566400, + "ap-southeast-1|r6a.2xlarge": 0.547200, + "ap-southeast-1|r6a.32xlarge": 8.755200, + "ap-southeast-1|r6a.48xlarge": 13.132800, + "ap-southeast-1|r6a.4xlarge": 1.094400, + "ap-southeast-1|r6a.8xlarge": 2.188800, + "ap-southeast-1|r6a.large": 0.136800, + "ap-southeast-1|r6a.metal": 13.132800, + "ap-southeast-1|r6a.xlarge": 0.273600, + "ap-southeast-1|r6g.12xlarge": 2.918400, + "ap-southeast-1|r6g.16xlarge": 3.891200, + "ap-southeast-1|r6g.2xlarge": 0.486400, + "ap-southeast-1|r6g.4xlarge": 0.972800, + "ap-southeast-1|r6g.8xlarge": 1.945600, + "ap-southeast-1|r6g.large": 0.121600, + "ap-southeast-1|r6g.medium": 0.060800, + "ap-southeast-1|r6g.metal": 3.891200, + "ap-southeast-1|r6g.xlarge": 0.243200, + "ap-southeast-1|r6gd.12xlarge": 3.336000, + "ap-southeast-1|r6gd.16xlarge": 4.448000, + "ap-southeast-1|r6gd.2xlarge": 0.556000, + "ap-southeast-1|r6gd.4xlarge": 1.112000, + "ap-southeast-1|r6gd.8xlarge": 2.224000, + "ap-southeast-1|r6gd.large": 0.139000, + "ap-southeast-1|r6gd.medium": 0.069500, + "ap-southeast-1|r6gd.metal": 4.448000, + "ap-southeast-1|r6gd.xlarge": 0.278000, + "ap-southeast-1|r6i.12xlarge": 3.648000, + "ap-southeast-1|r6i.16xlarge": 4.864000, + "ap-southeast-1|r6i.24xlarge": 7.296000, + "ap-southeast-1|r6i.2xlarge": 0.608000, + "ap-southeast-1|r6i.32xlarge": 9.728000, + "ap-southeast-1|r6i.4xlarge": 1.216000, + "ap-southeast-1|r6i.8xlarge": 2.432000, + "ap-southeast-1|r6i.large": 0.152000, + "ap-southeast-1|r6i.metal": 9.728000, + "ap-southeast-1|r6i.xlarge": 0.304000, + "ap-southeast-1|r6id.12xlarge": 4.384800, + "ap-southeast-1|r6id.16xlarge": 5.846400, + "ap-southeast-1|r6id.24xlarge": 8.769600, + "ap-southeast-1|r6id.2xlarge": 0.730800, + "ap-southeast-1|r6id.32xlarge": 11.692800, + "ap-southeast-1|r6id.4xlarge": 1.461600, + "ap-southeast-1|r6id.8xlarge": 2.923200, + "ap-southeast-1|r6id.large": 0.182700, + "ap-southeast-1|r6id.metal": 11.692800, + "ap-southeast-1|r6id.xlarge": 0.365400, + "ap-southeast-1|r6idn.12xlarge": 5.616000, + "ap-southeast-1|r6idn.16xlarge": 7.488000, + "ap-southeast-1|r6idn.24xlarge": 11.232000, + "ap-southeast-1|r6idn.2xlarge": 0.936000, + "ap-southeast-1|r6idn.32xlarge": 14.976000, + "ap-southeast-1|r6idn.4xlarge": 1.872000, + "ap-southeast-1|r6idn.8xlarge": 3.744000, + "ap-southeast-1|r6idn.large": 0.234000, + "ap-southeast-1|r6idn.metal": 14.976000, + "ap-southeast-1|r6idn.xlarge": 0.468000, + "ap-southeast-1|r6in.12xlarge": 4.998240, + "ap-southeast-1|r6in.16xlarge": 6.664320, + "ap-southeast-1|r6in.24xlarge": 9.996480, + "ap-southeast-1|r6in.2xlarge": 0.833040, + "ap-southeast-1|r6in.32xlarge": 13.328640, + "ap-southeast-1|r6in.4xlarge": 1.666080, + "ap-southeast-1|r6in.8xlarge": 3.332160, + "ap-southeast-1|r6in.large": 0.208260, + "ap-southeast-1|r6in.metal": 13.328640, + "ap-southeast-1|r6in.xlarge": 0.416520, + "ap-southeast-1|r7g.12xlarge": 3.100800, + "ap-southeast-1|r7g.16xlarge": 4.134400, + "ap-southeast-1|r7g.2xlarge": 0.516800, + "ap-southeast-1|r7g.4xlarge": 1.033600, + "ap-southeast-1|r7g.8xlarge": 2.067200, + "ap-southeast-1|r7g.large": 0.129200, + "ap-southeast-1|r7g.medium": 0.064600, + "ap-southeast-1|r7g.metal": 4.134400, + "ap-southeast-1|r7g.xlarge": 0.258400, + "ap-southeast-1|r7gd.12xlarge": 3.946300, + "ap-southeast-1|r7gd.16xlarge": 5.261800, + "ap-southeast-1|r7gd.2xlarge": 0.657700, + "ap-southeast-1|r7gd.4xlarge": 1.315400, + "ap-southeast-1|r7gd.8xlarge": 2.630900, + "ap-southeast-1|r7gd.large": 0.164400, + "ap-southeast-1|r7gd.medium": 0.082200, + "ap-southeast-1|r7gd.metal": 5.261800, + "ap-southeast-1|r7gd.xlarge": 0.328900, + "ap-southeast-1|r7i.12xlarge": 3.830400, + "ap-southeast-1|r7i.16xlarge": 5.107200, + "ap-southeast-1|r7i.24xlarge": 7.660800, + "ap-southeast-1|r7i.2xlarge": 0.638400, + "ap-southeast-1|r7i.48xlarge": 15.321600, + "ap-southeast-1|r7i.4xlarge": 1.276800, + "ap-southeast-1|r7i.8xlarge": 2.553600, + "ap-southeast-1|r7i.large": 0.159600, + "ap-southeast-1|r7i.metal-24xl": 7.660800, + "ap-southeast-1|r7i.metal-48xl": 15.321600, + "ap-southeast-1|r7i.xlarge": 0.319200, + "ap-southeast-1|r8g.12xlarge": 3.410880, + "ap-southeast-1|r8g.16xlarge": 4.547840, + "ap-southeast-1|r8g.24xlarge": 6.821760, + "ap-southeast-1|r8g.2xlarge": 0.568480, + "ap-southeast-1|r8g.48xlarge": 13.643520, + "ap-southeast-1|r8g.4xlarge": 1.136960, + "ap-southeast-1|r8g.8xlarge": 2.273920, + "ap-southeast-1|r8g.large": 0.142120, + "ap-southeast-1|r8g.medium": 0.071060, + "ap-southeast-1|r8g.metal-24xl": 6.821760, + "ap-southeast-1|r8g.metal-48xl": 13.643520, + "ap-southeast-1|r8g.xlarge": 0.284240, + "ap-southeast-1|r8i-flex.12xlarge": 3.820800, + "ap-southeast-1|r8i-flex.16xlarge": 5.094400, + "ap-southeast-1|r8i-flex.2xlarge": 0.636800, + "ap-southeast-1|r8i-flex.4xlarge": 1.273600, + "ap-southeast-1|r8i-flex.8xlarge": 2.547200, + "ap-southeast-1|r8i-flex.large": 0.159200, + "ap-southeast-1|r8i-flex.xlarge": 0.318400, + "ap-southeast-1|r8i.12xlarge": 4.021920, + "ap-southeast-1|r8i.16xlarge": 5.362560, + "ap-southeast-1|r8i.24xlarge": 8.043840, + "ap-southeast-1|r8i.2xlarge": 0.670320, + "ap-southeast-1|r8i.32xlarge": 10.725120, + "ap-southeast-1|r8i.48xlarge": 16.087680, + "ap-southeast-1|r8i.4xlarge": 1.340640, + "ap-southeast-1|r8i.8xlarge": 2.681280, + "ap-southeast-1|r8i.96xlarge": 32.175360, + "ap-southeast-1|r8i.large": 0.167580, + "ap-southeast-1|r8i.metal-48xl": 16.087680, + "ap-southeast-1|r8i.metal-96xl": 32.175360, + "ap-southeast-1|r8i.xlarge": 0.335160, + "ap-southeast-1|t1.micro": 0.020000, + "ap-southeast-1|t2.2xlarge": 0.467200, + "ap-southeast-1|t2.large": 0.116800, + "ap-southeast-1|t2.medium": 0.058400, + "ap-southeast-1|t2.micro": 0.014600, + "ap-southeast-1|t2.nano": 0.007300, + "ap-southeast-1|t2.small": 0.029200, + "ap-southeast-1|t2.xlarge": 0.233600, + "ap-southeast-1|t3.2xlarge": 0.422400, + "ap-southeast-1|t3.large": 0.105600, + "ap-southeast-1|t3.medium": 0.052800, + "ap-southeast-1|t3.micro": 0.013200, + "ap-southeast-1|t3.nano": 0.006600, + "ap-southeast-1|t3.small": 0.026400, + "ap-southeast-1|t3.xlarge": 0.211200, + "ap-southeast-1|t3a.2xlarge": 0.377600, + "ap-southeast-1|t3a.large": 0.094400, + "ap-southeast-1|t3a.medium": 0.047200, + "ap-southeast-1|t3a.micro": 0.011800, + "ap-southeast-1|t3a.nano": 0.005900, + "ap-southeast-1|t3a.small": 0.023600, + "ap-southeast-1|t3a.xlarge": 0.188800, + "ap-southeast-1|t4g.2xlarge": 0.339200, + "ap-southeast-1|t4g.large": 0.084800, + "ap-southeast-1|t4g.medium": 0.042400, + "ap-southeast-1|t4g.micro": 0.010600, + "ap-southeast-1|t4g.nano": 0.005300, + "ap-southeast-1|t4g.small": 0.021200, + "ap-southeast-1|t4g.xlarge": 0.169600, + "ap-southeast-1|u-12tb1.112xlarge": 131.733000, + "ap-southeast-1|u-3tb1.56xlarge": 32.930000, + "ap-southeast-1|u-6tb1.112xlarge": 65.867000, + "ap-southeast-1|u-6tb1.56xlarge": 55.979600, + "ap-southeast-1|u-9tb1.112xlarge": 98.800000, + "ap-southeast-1|u7in-16tb.224xlarge": 217.716380, + "ap-southeast-1|x1.16xlarge": 9.671000, + "ap-southeast-1|x1.32xlarge": 19.341000, + "ap-southeast-1|x1e.16xlarge": 19.344000, + "ap-southeast-1|x1e.2xlarge": 2.418000, + "ap-southeast-1|x1e.32xlarge": 38.688000, + "ap-southeast-1|x1e.4xlarge": 4.836000, + "ap-southeast-1|x1e.8xlarge": 9.672000, + "ap-southeast-1|x1e.xlarge": 1.209000, + "ap-southeast-1|x2idn.16xlarge": 9.670500, + "ap-southeast-1|x2idn.24xlarge": 14.505750, + "ap-southeast-1|x2idn.32xlarge": 19.341000, + "ap-southeast-1|x2idn.metal": 19.341000, + "ap-southeast-1|x2iedn.16xlarge": 19.341000, + "ap-southeast-1|x2iedn.24xlarge": 29.011500, + "ap-southeast-1|x2iedn.2xlarge": 2.417630, + "ap-southeast-1|x2iedn.32xlarge": 38.682000, + "ap-southeast-1|x2iedn.4xlarge": 4.835250, + "ap-southeast-1|x2iedn.8xlarge": 9.670500, + "ap-southeast-1|x2iedn.metal": 38.682000, + "ap-southeast-1|x2iedn.xlarge": 1.208810, + "ap-southeast-1|z1d.12xlarge": 5.424000, + "ap-southeast-1|z1d.2xlarge": 0.904000, + "ap-southeast-1|z1d.3xlarge": 1.356000, + "ap-southeast-1|z1d.6xlarge": 2.712000, + "ap-southeast-1|z1d.large": 0.226000, + "ap-southeast-1|z1d.metal": 5.424000, + "ap-southeast-1|z1d.xlarge": 0.452000, + "ap-southeast-2|a1.2xlarge": 0.266400, + "ap-southeast-2|a1.4xlarge": 0.532800, + "ap-southeast-2|a1.large": 0.066600, + "ap-southeast-2|a1.medium": 0.033300, + "ap-southeast-2|a1.metal": 0.533000, + "ap-southeast-2|a1.xlarge": 0.133200, + "ap-southeast-2|c1.medium": 0.164000, + "ap-southeast-2|c1.xlarge": 0.655000, + "ap-southeast-2|c3.2xlarge": 0.529000, + "ap-southeast-2|c3.4xlarge": 1.058000, + "ap-southeast-2|c3.8xlarge": 2.117000, + "ap-southeast-2|c3.large": 0.132000, + "ap-southeast-2|c3.xlarge": 0.265000, + "ap-southeast-2|c4.2xlarge": 0.522000, + "ap-southeast-2|c4.4xlarge": 1.042000, + "ap-southeast-2|c4.8xlarge": 2.085000, + "ap-southeast-2|c4.large": 0.130000, + "ap-southeast-2|c4.xlarge": 0.261000, + "ap-southeast-2|c5.12xlarge": 2.664000, + "ap-southeast-2|c5.18xlarge": 3.996000, + "ap-southeast-2|c5.24xlarge": 5.328000, + "ap-southeast-2|c5.2xlarge": 0.444000, + "ap-southeast-2|c5.4xlarge": 0.888000, + "ap-southeast-2|c5.9xlarge": 1.998000, + "ap-southeast-2|c5.large": 0.111000, + "ap-southeast-2|c5.metal": 5.328000, + "ap-southeast-2|c5.xlarge": 0.222000, + "ap-southeast-2|c5a.12xlarge": 2.400000, + "ap-southeast-2|c5a.16xlarge": 3.200000, + "ap-southeast-2|c5a.24xlarge": 4.800000, + "ap-southeast-2|c5a.2xlarge": 0.400000, + "ap-southeast-2|c5a.4xlarge": 0.800000, + "ap-southeast-2|c5a.8xlarge": 1.600000, + "ap-southeast-2|c5a.large": 0.100000, + "ap-southeast-2|c5a.xlarge": 0.200000, + "ap-southeast-2|c5ad.12xlarge": 2.712000, + "ap-southeast-2|c5ad.16xlarge": 3.616000, + "ap-southeast-2|c5ad.24xlarge": 5.424000, + "ap-southeast-2|c5ad.2xlarge": 0.452000, + "ap-southeast-2|c5ad.4xlarge": 0.904000, + "ap-southeast-2|c5ad.8xlarge": 1.808000, + "ap-southeast-2|c5ad.large": 0.113000, + "ap-southeast-2|c5ad.xlarge": 0.226000, + "ap-southeast-2|c5d.12xlarge": 3.024000, + "ap-southeast-2|c5d.18xlarge": 4.536000, + "ap-southeast-2|c5d.24xlarge": 6.048000, + "ap-southeast-2|c5d.2xlarge": 0.504000, + "ap-southeast-2|c5d.4xlarge": 1.008000, + "ap-southeast-2|c5d.9xlarge": 2.268000, + "ap-southeast-2|c5d.large": 0.126000, + "ap-southeast-2|c5d.metal": 6.048000, + "ap-southeast-2|c5d.xlarge": 0.252000, + "ap-southeast-2|c5n.18xlarge": 5.076000, + "ap-southeast-2|c5n.2xlarge": 0.564000, + "ap-southeast-2|c5n.4xlarge": 1.128000, + "ap-southeast-2|c5n.9xlarge": 2.538000, + "ap-southeast-2|c5n.large": 0.141000, + "ap-southeast-2|c5n.metal": 5.076000, + "ap-southeast-2|c5n.xlarge": 0.282000, + "ap-southeast-2|c6a.12xlarge": 2.397600, + "ap-southeast-2|c6a.16xlarge": 3.196800, + "ap-southeast-2|c6a.24xlarge": 4.795200, + "ap-southeast-2|c6a.2xlarge": 0.399600, + "ap-southeast-2|c6a.32xlarge": 6.393600, + "ap-southeast-2|c6a.48xlarge": 9.590400, + "ap-southeast-2|c6a.4xlarge": 0.799200, + "ap-southeast-2|c6a.8xlarge": 1.598400, + "ap-southeast-2|c6a.large": 0.099900, + "ap-southeast-2|c6a.metal": 9.590400, + "ap-southeast-2|c6a.xlarge": 0.199800, + "ap-southeast-2|c6g.12xlarge": 2.131200, + "ap-southeast-2|c6g.16xlarge": 2.841600, + "ap-southeast-2|c6g.2xlarge": 0.355200, + "ap-southeast-2|c6g.4xlarge": 0.710400, + "ap-southeast-2|c6g.8xlarge": 1.420800, + "ap-southeast-2|c6g.large": 0.088800, + "ap-southeast-2|c6g.medium": 0.044400, + "ap-southeast-2|c6g.metal": 2.841600, + "ap-southeast-2|c6g.xlarge": 0.177600, + "ap-southeast-2|c6gd.12xlarge": 2.424000, + "ap-southeast-2|c6gd.16xlarge": 3.232000, + "ap-southeast-2|c6gd.2xlarge": 0.404000, + "ap-southeast-2|c6gd.4xlarge": 0.808000, + "ap-southeast-2|c6gd.8xlarge": 1.616000, + "ap-southeast-2|c6gd.large": 0.101000, + "ap-southeast-2|c6gd.medium": 0.050500, + "ap-southeast-2|c6gd.metal": 3.232000, + "ap-southeast-2|c6gd.xlarge": 0.202000, + "ap-southeast-2|c6gn.12xlarge": 2.712000, + "ap-southeast-2|c6gn.16xlarge": 3.616000, + "ap-southeast-2|c6gn.2xlarge": 0.452000, + "ap-southeast-2|c6gn.4xlarge": 0.904000, + "ap-southeast-2|c6gn.8xlarge": 1.808000, + "ap-southeast-2|c6gn.large": 0.113000, + "ap-southeast-2|c6gn.medium": 0.056500, + "ap-southeast-2|c6gn.xlarge": 0.226000, + "ap-southeast-2|c6i.12xlarge": 2.664000, + "ap-southeast-2|c6i.16xlarge": 3.552000, + "ap-southeast-2|c6i.24xlarge": 5.328000, + "ap-southeast-2|c6i.2xlarge": 0.444000, + "ap-southeast-2|c6i.32xlarge": 7.104000, + "ap-southeast-2|c6i.4xlarge": 0.888000, + "ap-southeast-2|c6i.8xlarge": 1.776000, + "ap-southeast-2|c6i.large": 0.111000, + "ap-southeast-2|c6i.metal": 7.104000, + "ap-southeast-2|c6i.xlarge": 0.222000, + "ap-southeast-2|c6id.12xlarge": 3.175200, + "ap-southeast-2|c6id.16xlarge": 4.233600, + "ap-southeast-2|c6id.24xlarge": 6.350400, + "ap-southeast-2|c6id.2xlarge": 0.529200, + "ap-southeast-2|c6id.32xlarge": 8.467200, + "ap-southeast-2|c6id.4xlarge": 1.058400, + "ap-southeast-2|c6id.8xlarge": 2.116800, + "ap-southeast-2|c6id.large": 0.132300, + "ap-southeast-2|c6id.metal": 8.467200, + "ap-southeast-2|c6id.xlarge": 0.264600, + "ap-southeast-2|c6in.12xlarge": 3.553200, + "ap-southeast-2|c6in.16xlarge": 4.737600, + "ap-southeast-2|c6in.24xlarge": 7.106400, + "ap-southeast-2|c6in.2xlarge": 0.592200, + "ap-southeast-2|c6in.32xlarge": 9.475200, + "ap-southeast-2|c6in.4xlarge": 1.184400, + "ap-southeast-2|c6in.8xlarge": 2.368800, + "ap-southeast-2|c6in.large": 0.148050, + "ap-southeast-2|c6in.metal": 9.475200, + "ap-southeast-2|c6in.xlarge": 0.296100, + "ap-southeast-2|c7g.12xlarge": 2.264600, + "ap-southeast-2|c7g.16xlarge": 3.019500, + "ap-southeast-2|c7g.2xlarge": 0.377400, + "ap-southeast-2|c7g.4xlarge": 0.754900, + "ap-southeast-2|c7g.8xlarge": 1.509800, + "ap-southeast-2|c7g.large": 0.094400, + "ap-southeast-2|c7g.medium": 0.047200, + "ap-southeast-2|c7g.metal": 3.019500, + "ap-southeast-2|c7g.xlarge": 0.188700, + "ap-southeast-2|c7gd.12xlarge": 2.857900, + "ap-southeast-2|c7gd.16xlarge": 3.810600, + "ap-southeast-2|c7gd.2xlarge": 0.476300, + "ap-southeast-2|c7gd.4xlarge": 0.952600, + "ap-southeast-2|c7gd.8xlarge": 1.905300, + "ap-southeast-2|c7gd.large": 0.119100, + "ap-southeast-2|c7gd.medium": 0.059500, + "ap-southeast-2|c7gd.metal": 3.810600, + "ap-southeast-2|c7gd.xlarge": 0.238200, + "ap-southeast-2|c7i-flex.12xlarge": 2.657340, + "ap-southeast-2|c7i-flex.16xlarge": 3.543120, + "ap-southeast-2|c7i-flex.2xlarge": 0.442890, + "ap-southeast-2|c7i-flex.4xlarge": 0.885780, + "ap-southeast-2|c7i-flex.8xlarge": 1.771560, + "ap-southeast-2|c7i-flex.large": 0.110720, + "ap-southeast-2|c7i-flex.xlarge": 0.221450, + "ap-southeast-2|c7i.12xlarge": 2.797200, + "ap-southeast-2|c7i.16xlarge": 3.729600, + "ap-southeast-2|c7i.24xlarge": 5.594400, + "ap-southeast-2|c7i.2xlarge": 0.466200, + "ap-southeast-2|c7i.48xlarge": 11.188800, + "ap-southeast-2|c7i.4xlarge": 0.932400, + "ap-southeast-2|c7i.8xlarge": 1.864800, + "ap-southeast-2|c7i.large": 0.116550, + "ap-southeast-2|c7i.metal-24xl": 5.594400, + "ap-southeast-2|c7i.metal-48xl": 11.188800, + "ap-southeast-2|c7i.xlarge": 0.233100, + "ap-southeast-2|c8g.12xlarge": 2.491200, + "ap-southeast-2|c8g.16xlarge": 3.321600, + "ap-southeast-2|c8g.24xlarge": 4.982400, + "ap-southeast-2|c8g.2xlarge": 0.415200, + "ap-southeast-2|c8g.48xlarge": 9.964800, + "ap-southeast-2|c8g.4xlarge": 0.830400, + "ap-southeast-2|c8g.8xlarge": 1.660800, + "ap-southeast-2|c8g.large": 0.103800, + "ap-southeast-2|c8g.medium": 0.051900, + "ap-southeast-2|c8g.metal-24xl": 4.982400, + "ap-southeast-2|c8g.metal-48xl": 9.964800, + "ap-southeast-2|c8g.xlarge": 0.207600, + "ap-southeast-2|c8gd.12xlarge": 3.086400, + "ap-southeast-2|c8gd.16xlarge": 4.115200, + "ap-southeast-2|c8gd.24xlarge": 6.172800, + "ap-southeast-2|c8gd.2xlarge": 0.514400, + "ap-southeast-2|c8gd.48xlarge": 12.345600, + "ap-southeast-2|c8gd.4xlarge": 1.028800, + "ap-southeast-2|c8gd.8xlarge": 2.057600, + "ap-southeast-2|c8gd.large": 0.128600, + "ap-southeast-2|c8gd.medium": 0.064300, + "ap-southeast-2|c8gd.metal-24xl": 6.172800, + "ap-southeast-2|c8gd.metal-48xl": 12.345600, + "ap-southeast-2|c8gd.xlarge": 0.257200, + "ap-southeast-2|c8gn.12xlarge": 3.713300, + "ap-southeast-2|c8gn.16xlarge": 4.951000, + "ap-southeast-2|c8gn.24xlarge": 7.426600, + "ap-southeast-2|c8gn.2xlarge": 0.618900, + "ap-southeast-2|c8gn.48xlarge": 14.853100, + "ap-southeast-2|c8gn.4xlarge": 1.237800, + "ap-southeast-2|c8gn.8xlarge": 2.475500, + "ap-southeast-2|c8gn.large": 0.154700, + "ap-southeast-2|c8gn.medium": 0.077400, + "ap-southeast-2|c8gn.xlarge": 0.309400, + "ap-southeast-2|d2.2xlarge": 1.740000, + "ap-southeast-2|d2.4xlarge": 3.480000, + "ap-southeast-2|d2.8xlarge": 6.960000, + "ap-southeast-2|d2.xlarge": 0.870000, + "ap-southeast-2|d3.2xlarge": 1.252000, + "ap-southeast-2|d3.4xlarge": 2.504000, + "ap-southeast-2|d3.8xlarge": 5.008080, + "ap-southeast-2|d3.xlarge": 0.626000, + "ap-southeast-2|d3en.12xlarge": 7.907520, + "ap-southeast-2|d3en.2xlarge": 1.318000, + "ap-southeast-2|d3en.4xlarge": 2.636000, + "ap-southeast-2|d3en.6xlarge": 3.954000, + "ap-southeast-2|d3en.8xlarge": 5.271680, + "ap-southeast-2|d3en.xlarge": 0.659000, + "ap-southeast-2|f1.16xlarge": 15.848000, + "ap-southeast-2|f1.2xlarge": 1.981000, + "ap-southeast-2|f1.4xlarge": 3.962000, + "ap-southeast-2|f2.12xlarge": 4.752000, + "ap-southeast-2|f2.48xlarge": 19.008000, + "ap-southeast-2|f2.6xlarge": 2.376000, + "ap-southeast-2|g2.2xlarge": 0.898000, + "ap-southeast-2|g2.8xlarge": 3.592000, + "ap-southeast-2|g3.16xlarge": 7.016000, + "ap-southeast-2|g3.4xlarge": 1.754000, + "ap-southeast-2|g3.8xlarge": 3.508000, + "ap-southeast-2|g3s.xlarge": 1.154000, + "ap-southeast-2|g4dn.12xlarge": 5.087000, + "ap-southeast-2|g4dn.16xlarge": 5.659000, + "ap-southeast-2|g4dn.2xlarge": 0.978000, + "ap-southeast-2|g4dn.4xlarge": 1.566000, + "ap-southeast-2|g4dn.8xlarge": 2.830000, + "ap-southeast-2|g4dn.metal": 10.174000, + "ap-southeast-2|g4dn.xlarge": 0.684000, + "ap-southeast-2|g5.12xlarge": 7.374730, + "ap-southeast-2|g5.16xlarge": 5.325610, + "ap-southeast-2|g5.24xlarge": 10.588820, + "ap-southeast-2|g5.2xlarge": 1.575840, + "ap-southeast-2|g5.48xlarge": 21.177640, + "ap-southeast-2|g5.4xlarge": 2.111520, + "ap-southeast-2|g5.8xlarge": 3.182890, + "ap-southeast-2|g5.xlarge": 1.308000, + "ap-southeast-2|g6.12xlarge": 5.982990, + "ap-southeast-2|g6.16xlarge": 4.416520, + "ap-southeast-2|g6.24xlarge": 8.679090, + "ap-southeast-2|g6.2xlarge": 1.271070, + "ap-southeast-2|g6.48xlarge": 17.358170, + "ap-southeast-2|g6.4xlarge": 1.720420, + "ap-southeast-2|g6.8xlarge": 2.619120, + "ap-southeast-2|g6.xlarge": 1.046400, + "ap-southeast-2|g6f.2xlarge": 0.617590, + "ap-southeast-2|g6f.4xlarge": 1.235170, + "ap-southeast-2|g6f.large": 0.262640, + "ap-southeast-2|g6f.xlarge": 0.308790, + "ap-southeast-2|gr6.4xlarge": 2.001200, + "ap-southeast-2|gr6.8xlarge": 3.180700, + "ap-southeast-2|gr6f.4xlarge": 1.385970, + "ap-southeast-2|hpc6a.48xlarge": 3.760900, + "ap-southeast-2|i2.2xlarge": 2.035000, + "ap-southeast-2|i2.4xlarge": 4.070000, + "ap-southeast-2|i2.8xlarge": 8.140000, + "ap-southeast-2|i2.xlarge": 1.018000, + "ap-southeast-2|i3.16xlarge": 5.984000, + "ap-southeast-2|i3.2xlarge": 0.748000, + "ap-southeast-2|i3.4xlarge": 1.496000, + "ap-southeast-2|i3.8xlarge": 2.992000, + "ap-southeast-2|i3.large": 0.187000, + "ap-southeast-2|i3.metal": 5.984000, + "ap-southeast-2|i3.xlarge": 0.374000, + "ap-southeast-2|i3en.12xlarge": 6.504000, + "ap-southeast-2|i3en.24xlarge": 13.008000, + "ap-southeast-2|i3en.2xlarge": 1.084000, + "ap-southeast-2|i3en.3xlarge": 1.626000, + "ap-southeast-2|i3en.6xlarge": 3.252000, + "ap-southeast-2|i3en.large": 0.271000, + "ap-southeast-2|i3en.metal": 13.008000, + "ap-southeast-2|i3en.xlarge": 0.542000, + "ap-southeast-2|i4g.16xlarge": 5.924160, + "ap-southeast-2|i4g.2xlarge": 0.740520, + "ap-southeast-2|i4g.4xlarge": 1.481040, + "ap-southeast-2|i4g.8xlarge": 2.962080, + "ap-southeast-2|i4g.large": 0.185130, + "ap-southeast-2|i4g.xlarge": 0.370260, + "ap-southeast-2|i4i.12xlarge": 4.937000, + "ap-southeast-2|i4i.16xlarge": 6.582000, + "ap-southeast-2|i4i.24xlarge": 9.873600, + "ap-southeast-2|i4i.2xlarge": 0.823000, + "ap-southeast-2|i4i.32xlarge": 13.164800, + "ap-southeast-2|i4i.4xlarge": 1.646000, + "ap-southeast-2|i4i.8xlarge": 3.291000, + "ap-southeast-2|i4i.large": 0.206000, + "ap-southeast-2|i4i.metal": 13.165000, + "ap-southeast-2|i4i.xlarge": 0.411000, + "ap-southeast-2|i7i.12xlarge": 5.430500, + "ap-southeast-2|i7i.16xlarge": 7.240600, + "ap-southeast-2|i7i.24xlarge": 10.861000, + "ap-southeast-2|i7i.2xlarge": 0.905100, + "ap-southeast-2|i7i.48xlarge": 21.721900, + "ap-southeast-2|i7i.4xlarge": 1.810200, + "ap-southeast-2|i7i.8xlarge": 3.620300, + "ap-southeast-2|i7i.large": 0.226300, + "ap-southeast-2|i7i.metal-24xl": 10.861000, + "ap-southeast-2|i7i.metal-48xl": 21.721900, + "ap-southeast-2|i7i.xlarge": 0.452500, + "ap-southeast-2|i7ie.12xlarge": 7.479600, + "ap-southeast-2|i7ie.18xlarge": 11.219400, + "ap-southeast-2|i7ie.24xlarge": 14.959200, + "ap-southeast-2|i7ie.2xlarge": 1.246600, + "ap-southeast-2|i7ie.3xlarge": 1.869900, + "ap-southeast-2|i7ie.48xlarge": 29.918400, + "ap-southeast-2|i7ie.6xlarge": 3.739800, + "ap-southeast-2|i7ie.large": 0.311700, + "ap-southeast-2|i7ie.metal-24xl": 14.959200, + "ap-southeast-2|i7ie.metal-48xl": 29.918400, + "ap-southeast-2|i7ie.xlarge": 0.623300, + "ap-southeast-2|i8g.12xlarge": 4.936800, + "ap-southeast-2|i8g.16xlarge": 6.582400, + "ap-southeast-2|i8g.24xlarge": 9.873600, + "ap-southeast-2|i8g.2xlarge": 0.822800, + "ap-southeast-2|i8g.48xlarge": 19.747200, + "ap-southeast-2|i8g.4xlarge": 1.645600, + "ap-southeast-2|i8g.8xlarge": 3.291200, + "ap-southeast-2|i8g.large": 0.205700, + "ap-southeast-2|i8g.metal-24xl": 9.873600, + "ap-southeast-2|i8g.xlarge": 0.411400, + "ap-southeast-2|im4gn.16xlarge": 6.977340, + "ap-southeast-2|im4gn.2xlarge": 0.872170, + "ap-southeast-2|im4gn.4xlarge": 1.744340, + "ap-southeast-2|im4gn.8xlarge": 3.488670, + "ap-southeast-2|im4gn.large": 0.218040, + "ap-southeast-2|im4gn.xlarge": 0.436080, + "ap-southeast-2|inf1.24xlarge": 5.902000, + "ap-southeast-2|inf1.2xlarge": 0.453000, + "ap-southeast-2|inf1.6xlarge": 1.475000, + "ap-southeast-2|inf1.xlarge": 0.285000, + "ap-southeast-2|inf2.24xlarge": 8.437820, + "ap-southeast-2|inf2.48xlarge": 16.875650, + "ap-southeast-2|inf2.8xlarge": 2.558220, + "ap-southeast-2|inf2.xlarge": 0.985660, + "ap-southeast-2|is4gen.2xlarge": 1.382100, + "ap-southeast-2|is4gen.4xlarge": 2.764210, + "ap-southeast-2|is4gen.8xlarge": 5.528420, + "ap-southeast-2|is4gen.large": 0.345530, + "ap-southeast-2|is4gen.medium": 0.172760, + "ap-southeast-2|is4gen.xlarge": 0.691050, + "ap-southeast-2|m1.large": 0.233000, + "ap-southeast-2|m1.medium": 0.117000, + "ap-southeast-2|m1.small": 0.058000, + "ap-southeast-2|m1.xlarge": 0.467000, + "ap-southeast-2|m2.2xlarge": 0.592000, + "ap-southeast-2|m2.4xlarge": 1.183000, + "ap-southeast-2|m2.xlarge": 0.296000, + "ap-southeast-2|m3.2xlarge": 0.745000, + "ap-southeast-2|m3.large": 0.186000, + "ap-southeast-2|m3.medium": 0.093000, + "ap-southeast-2|m3.xlarge": 0.372000, + "ap-southeast-2|m4.10xlarge": 2.500000, + "ap-southeast-2|m4.16xlarge": 4.000000, + "ap-southeast-2|m4.2xlarge": 0.500000, + "ap-southeast-2|m4.4xlarge": 1.000000, + "ap-southeast-2|m4.large": 0.125000, + "ap-southeast-2|m4.xlarge": 0.250000, + "ap-southeast-2|m5.12xlarge": 2.880000, + "ap-southeast-2|m5.16xlarge": 3.840000, + "ap-southeast-2|m5.24xlarge": 5.760000, + "ap-southeast-2|m5.2xlarge": 0.480000, + "ap-southeast-2|m5.4xlarge": 0.960000, + "ap-southeast-2|m5.8xlarge": 1.920000, + "ap-southeast-2|m5.large": 0.120000, + "ap-southeast-2|m5.metal": 5.760000, + "ap-southeast-2|m5.xlarge": 0.240000, + "ap-southeast-2|m5a.12xlarge": 2.592000, + "ap-southeast-2|m5a.16xlarge": 3.456000, + "ap-southeast-2|m5a.24xlarge": 5.184000, + "ap-southeast-2|m5a.2xlarge": 0.432000, + "ap-southeast-2|m5a.4xlarge": 0.864000, + "ap-southeast-2|m5a.8xlarge": 1.728000, + "ap-southeast-2|m5a.large": 0.108000, + "ap-southeast-2|m5a.xlarge": 0.216000, + "ap-southeast-2|m5ad.12xlarge": 3.120000, + "ap-southeast-2|m5ad.16xlarge": 4.160000, + "ap-southeast-2|m5ad.24xlarge": 6.240000, + "ap-southeast-2|m5ad.2xlarge": 0.520000, + "ap-southeast-2|m5ad.4xlarge": 1.040000, + "ap-southeast-2|m5ad.8xlarge": 2.080000, + "ap-southeast-2|m5ad.large": 0.130000, + "ap-southeast-2|m5ad.xlarge": 0.260000, + "ap-southeast-2|m5d.12xlarge": 3.408000, + "ap-southeast-2|m5d.16xlarge": 4.544000, + "ap-southeast-2|m5d.24xlarge": 6.816000, + "ap-southeast-2|m5d.2xlarge": 0.568000, + "ap-southeast-2|m5d.4xlarge": 1.136000, + "ap-southeast-2|m5d.8xlarge": 2.272000, + "ap-southeast-2|m5d.large": 0.142000, + "ap-southeast-2|m5d.metal": 6.816000, + "ap-southeast-2|m5d.xlarge": 0.284000, + "ap-southeast-2|m5zn.12xlarge": 4.956000, + "ap-southeast-2|m5zn.2xlarge": 0.826000, + "ap-southeast-2|m5zn.3xlarge": 1.239000, + "ap-southeast-2|m5zn.6xlarge": 2.478000, + "ap-southeast-2|m5zn.large": 0.206500, + "ap-southeast-2|m5zn.metal": 4.956000, + "ap-southeast-2|m5zn.xlarge": 0.413000, + "ap-southeast-2|m6a.12xlarge": 2.592000, + "ap-southeast-2|m6a.16xlarge": 3.456000, + "ap-southeast-2|m6a.24xlarge": 5.184000, + "ap-southeast-2|m6a.2xlarge": 0.432000, + "ap-southeast-2|m6a.32xlarge": 6.912000, + "ap-southeast-2|m6a.48xlarge": 10.368000, + "ap-southeast-2|m6a.4xlarge": 0.864000, + "ap-southeast-2|m6a.8xlarge": 1.728000, + "ap-southeast-2|m6a.large": 0.108000, + "ap-southeast-2|m6a.metal": 10.368000, + "ap-southeast-2|m6a.xlarge": 0.216000, + "ap-southeast-2|m6g.12xlarge": 2.304000, + "ap-southeast-2|m6g.16xlarge": 3.072000, + "ap-southeast-2|m6g.2xlarge": 0.384000, + "ap-southeast-2|m6g.4xlarge": 0.768000, + "ap-southeast-2|m6g.8xlarge": 1.536000, + "ap-southeast-2|m6g.large": 0.096000, + "ap-southeast-2|m6g.medium": 0.048000, + "ap-southeast-2|m6g.metal": 3.072000, + "ap-southeast-2|m6g.xlarge": 0.192000, + "ap-southeast-2|m6gd.12xlarge": 2.736000, + "ap-southeast-2|m6gd.16xlarge": 3.648000, + "ap-southeast-2|m6gd.2xlarge": 0.456000, + "ap-southeast-2|m6gd.4xlarge": 0.912000, + "ap-southeast-2|m6gd.8xlarge": 1.824000, + "ap-southeast-2|m6gd.large": 0.114000, + "ap-southeast-2|m6gd.medium": 0.057000, + "ap-southeast-2|m6gd.metal": 3.648000, + "ap-southeast-2|m6gd.xlarge": 0.228000, + "ap-southeast-2|m6i.12xlarge": 2.880000, + "ap-southeast-2|m6i.16xlarge": 3.840000, + "ap-southeast-2|m6i.24xlarge": 5.760000, + "ap-southeast-2|m6i.2xlarge": 0.480000, + "ap-southeast-2|m6i.32xlarge": 7.680000, + "ap-southeast-2|m6i.4xlarge": 0.960000, + "ap-southeast-2|m6i.8xlarge": 1.920000, + "ap-southeast-2|m6i.large": 0.120000, + "ap-southeast-2|m6i.metal": 7.680000, + "ap-southeast-2|m6i.xlarge": 0.240000, + "ap-southeast-2|m6id.12xlarge": 3.578400, + "ap-southeast-2|m6id.16xlarge": 4.771200, + "ap-southeast-2|m6id.24xlarge": 7.156800, + "ap-southeast-2|m6id.2xlarge": 0.596400, + "ap-southeast-2|m6id.32xlarge": 9.542400, + "ap-southeast-2|m6id.4xlarge": 1.192800, + "ap-southeast-2|m6id.8xlarge": 2.385600, + "ap-southeast-2|m6id.large": 0.149100, + "ap-southeast-2|m6id.metal": 9.542400, + "ap-southeast-2|m6id.xlarge": 0.298200, + "ap-southeast-2|m6idn.12xlarge": 4.829760, + "ap-southeast-2|m6idn.16xlarge": 6.439680, + "ap-southeast-2|m6idn.24xlarge": 9.659520, + "ap-southeast-2|m6idn.2xlarge": 0.804960, + "ap-southeast-2|m6idn.32xlarge": 12.879360, + "ap-southeast-2|m6idn.4xlarge": 1.609920, + "ap-southeast-2|m6idn.8xlarge": 3.219840, + "ap-southeast-2|m6idn.large": 0.201240, + "ap-southeast-2|m6idn.metal": 12.879360, + "ap-southeast-2|m6idn.xlarge": 0.402480, + "ap-southeast-2|m6in.12xlarge": 4.212000, + "ap-southeast-2|m6in.16xlarge": 5.616000, + "ap-southeast-2|m6in.24xlarge": 8.424000, + "ap-southeast-2|m6in.2xlarge": 0.702000, + "ap-southeast-2|m6in.32xlarge": 11.232000, + "ap-southeast-2|m6in.4xlarge": 1.404000, + "ap-southeast-2|m6in.8xlarge": 2.808000, + "ap-southeast-2|m6in.large": 0.175500, + "ap-southeast-2|m6in.metal": 11.232000, + "ap-southeast-2|m6in.xlarge": 0.351000, + "ap-southeast-2|m7a.12xlarge": 3.477600, + "ap-southeast-2|m7a.16xlarge": 4.636800, + "ap-southeast-2|m7a.24xlarge": 6.955200, + "ap-southeast-2|m7a.2xlarge": 0.579600, + "ap-southeast-2|m7a.32xlarge": 9.273600, + "ap-southeast-2|m7a.48xlarge": 13.910400, + "ap-southeast-2|m7a.4xlarge": 1.159200, + "ap-southeast-2|m7a.8xlarge": 2.318400, + "ap-southeast-2|m7a.large": 0.144900, + "ap-southeast-2|m7a.medium": 0.072450, + "ap-southeast-2|m7a.metal-48xl": 13.910400, + "ap-southeast-2|m7a.xlarge": 0.289800, + "ap-southeast-2|m7g.12xlarge": 2.448000, + "ap-southeast-2|m7g.16xlarge": 3.264000, + "ap-southeast-2|m7g.2xlarge": 0.408000, + "ap-southeast-2|m7g.4xlarge": 0.816000, + "ap-southeast-2|m7g.8xlarge": 1.632000, + "ap-southeast-2|m7g.large": 0.102000, + "ap-southeast-2|m7g.medium": 0.051000, + "ap-southeast-2|m7g.metal": 3.264000, + "ap-southeast-2|m7g.xlarge": 0.204000, + "ap-southeast-2|m7gd.12xlarge": 3.220600, + "ap-southeast-2|m7gd.16xlarge": 4.294100, + "ap-southeast-2|m7gd.2xlarge": 0.536800, + "ap-southeast-2|m7gd.4xlarge": 1.073500, + "ap-southeast-2|m7gd.8xlarge": 2.147000, + "ap-southeast-2|m7gd.large": 0.134200, + "ap-southeast-2|m7gd.medium": 0.067100, + "ap-southeast-2|m7gd.metal": 4.294100, + "ap-southeast-2|m7gd.xlarge": 0.268400, + "ap-southeast-2|m7i-flex.12xlarge": 2.872800, + "ap-southeast-2|m7i-flex.16xlarge": 3.830400, + "ap-southeast-2|m7i-flex.2xlarge": 0.478800, + "ap-southeast-2|m7i-flex.4xlarge": 0.957600, + "ap-southeast-2|m7i-flex.8xlarge": 1.915200, + "ap-southeast-2|m7i-flex.large": 0.119700, + "ap-southeast-2|m7i-flex.xlarge": 0.239400, + "ap-southeast-2|m7i.12xlarge": 3.024000, + "ap-southeast-2|m7i.16xlarge": 4.032000, + "ap-southeast-2|m7i.24xlarge": 6.048000, + "ap-southeast-2|m7i.2xlarge": 0.504000, + "ap-southeast-2|m7i.48xlarge": 12.096000, + "ap-southeast-2|m7i.4xlarge": 1.008000, + "ap-southeast-2|m7i.8xlarge": 2.016000, + "ap-southeast-2|m7i.large": 0.126000, + "ap-southeast-2|m7i.metal-24xl": 6.048000, + "ap-southeast-2|m7i.metal-48xl": 12.096000, + "ap-southeast-2|m7i.xlarge": 0.252000, + "ap-southeast-2|m8g.12xlarge": 2.692800, + "ap-southeast-2|m8g.16xlarge": 3.590400, + "ap-southeast-2|m8g.24xlarge": 5.385600, + "ap-southeast-2|m8g.2xlarge": 0.448800, + "ap-southeast-2|m8g.48xlarge": 10.771200, + "ap-southeast-2|m8g.4xlarge": 0.897600, + "ap-southeast-2|m8g.8xlarge": 1.795200, + "ap-southeast-2|m8g.large": 0.112200, + "ap-southeast-2|m8g.medium": 0.056100, + "ap-southeast-2|m8g.metal-24xl": 5.385600, + "ap-southeast-2|m8g.metal-48xl": 10.771200, + "ap-southeast-2|m8g.xlarge": 0.224400, + "ap-southeast-2|m8gd.12xlarge": 3.478080, + "ap-southeast-2|m8gd.16xlarge": 4.637440, + "ap-southeast-2|m8gd.24xlarge": 6.956160, + "ap-southeast-2|m8gd.2xlarge": 0.579680, + "ap-southeast-2|m8gd.48xlarge": 13.912320, + "ap-southeast-2|m8gd.4xlarge": 1.159360, + "ap-southeast-2|m8gd.8xlarge": 2.318720, + "ap-southeast-2|m8gd.large": 0.144920, + "ap-southeast-2|m8gd.medium": 0.072460, + "ap-southeast-2|m8gd.metal-24xl": 6.956160, + "ap-southeast-2|m8gd.metal-48xl": 13.912320, + "ap-southeast-2|m8gd.xlarge": 0.289840, + "ap-southeast-2|m8i-flex.12xlarge": 3.016560, + "ap-southeast-2|m8i-flex.16xlarge": 4.022080, + "ap-southeast-2|m8i-flex.2xlarge": 0.502760, + "ap-southeast-2|m8i-flex.4xlarge": 1.005520, + "ap-southeast-2|m8i-flex.8xlarge": 2.011040, + "ap-southeast-2|m8i-flex.large": 0.125690, + "ap-southeast-2|m8i-flex.xlarge": 0.251380, + "ap-southeast-2|m8i.12xlarge": 3.175200, + "ap-southeast-2|m8i.16xlarge": 4.233600, + "ap-southeast-2|m8i.24xlarge": 6.350400, + "ap-southeast-2|m8i.2xlarge": 0.529200, + "ap-southeast-2|m8i.32xlarge": 8.467200, + "ap-southeast-2|m8i.48xlarge": 12.700800, + "ap-southeast-2|m8i.4xlarge": 1.058400, + "ap-southeast-2|m8i.8xlarge": 2.116800, + "ap-southeast-2|m8i.96xlarge": 25.401600, + "ap-southeast-2|m8i.large": 0.132300, + "ap-southeast-2|m8i.metal-48xl": 12.700800, + "ap-southeast-2|m8i.metal-96xl": 25.401600, + "ap-southeast-2|m8i.xlarge": 0.264600, + "ap-southeast-2|p2.16xlarge": 24.672000, + "ap-southeast-2|p2.8xlarge": 12.336000, + "ap-southeast-2|p2.xlarge": 1.542000, + "ap-southeast-2|p3.16xlarge": 33.872000, + "ap-southeast-2|p3.2xlarge": 4.234000, + "ap-southeast-2|p3.8xlarge": 16.936000, + "ap-southeast-2|p4d.24xlarge": 28.544930, + "ap-southeast-2|p5.48xlarge": 71.552000, + "ap-southeast-2|p5.4xlarge": 8.944000, + "ap-southeast-2|r3.2xlarge": 0.798000, + "ap-southeast-2|r3.4xlarge": 1.596000, + "ap-southeast-2|r3.8xlarge": 3.192000, + "ap-southeast-2|r3.large": 0.200000, + "ap-southeast-2|r3.xlarge": 0.399000, + "ap-southeast-2|r4.16xlarge": 5.107200, + "ap-southeast-2|r4.2xlarge": 0.638400, + "ap-southeast-2|r4.4xlarge": 1.276800, + "ap-southeast-2|r4.8xlarge": 2.553600, + "ap-southeast-2|r4.large": 0.159600, + "ap-southeast-2|r4.xlarge": 0.319200, + "ap-southeast-2|r5.12xlarge": 3.624000, + "ap-southeast-2|r5.16xlarge": 4.832000, + "ap-southeast-2|r5.24xlarge": 7.248000, + "ap-southeast-2|r5.2xlarge": 0.604000, + "ap-southeast-2|r5.4xlarge": 1.208000, + "ap-southeast-2|r5.8xlarge": 2.416000, + "ap-southeast-2|r5.large": 0.151000, + "ap-southeast-2|r5.metal": 7.248000, + "ap-southeast-2|r5.xlarge": 0.302000, + "ap-southeast-2|r5a.12xlarge": 3.264000, + "ap-southeast-2|r5a.16xlarge": 4.352000, + "ap-southeast-2|r5a.24xlarge": 6.528000, + "ap-southeast-2|r5a.2xlarge": 0.544000, + "ap-southeast-2|r5a.4xlarge": 1.088000, + "ap-southeast-2|r5a.8xlarge": 2.176000, + "ap-southeast-2|r5a.large": 0.136000, + "ap-southeast-2|r5a.xlarge": 0.272000, + "ap-southeast-2|r5ad.12xlarge": 3.816000, + "ap-southeast-2|r5ad.16xlarge": 5.088000, + "ap-southeast-2|r5ad.24xlarge": 7.632000, + "ap-southeast-2|r5ad.2xlarge": 0.636000, + "ap-southeast-2|r5ad.4xlarge": 1.272000, + "ap-southeast-2|r5ad.8xlarge": 2.544000, + "ap-southeast-2|r5ad.large": 0.159000, + "ap-southeast-2|r5ad.xlarge": 0.318000, + "ap-southeast-2|r5b.12xlarge": 4.344000, + "ap-southeast-2|r5b.16xlarge": 5.792000, + "ap-southeast-2|r5b.24xlarge": 8.688000, + "ap-southeast-2|r5b.2xlarge": 0.724000, + "ap-southeast-2|r5b.4xlarge": 1.448000, + "ap-southeast-2|r5b.8xlarge": 2.896000, + "ap-southeast-2|r5b.large": 0.181000, + "ap-southeast-2|r5b.metal": 8.688000, + "ap-southeast-2|r5b.xlarge": 0.362000, + "ap-southeast-2|r5d.12xlarge": 4.176000, + "ap-southeast-2|r5d.16xlarge": 5.568000, + "ap-southeast-2|r5d.24xlarge": 8.352000, + "ap-southeast-2|r5d.2xlarge": 0.696000, + "ap-southeast-2|r5d.4xlarge": 1.392000, + "ap-southeast-2|r5d.8xlarge": 2.784000, + "ap-southeast-2|r5d.large": 0.174000, + "ap-southeast-2|r5d.metal": 8.352000, + "ap-southeast-2|r5d.xlarge": 0.348000, + "ap-southeast-2|r5dn.12xlarge": 4.896000, + "ap-southeast-2|r5dn.16xlarge": 6.528000, + "ap-southeast-2|r5dn.24xlarge": 9.792000, + "ap-southeast-2|r5dn.2xlarge": 0.816000, + "ap-southeast-2|r5dn.4xlarge": 1.632000, + "ap-southeast-2|r5dn.8xlarge": 3.264000, + "ap-southeast-2|r5dn.large": 0.204000, + "ap-southeast-2|r5dn.metal": 9.792000, + "ap-southeast-2|r5dn.xlarge": 0.408000, + "ap-southeast-2|r5n.12xlarge": 4.344000, + "ap-southeast-2|r5n.16xlarge": 5.792000, + "ap-southeast-2|r5n.24xlarge": 8.688000, + "ap-southeast-2|r5n.2xlarge": 0.724000, + "ap-southeast-2|r5n.4xlarge": 1.448000, + "ap-southeast-2|r5n.8xlarge": 2.896000, + "ap-southeast-2|r5n.large": 0.181000, + "ap-southeast-2|r5n.metal": 8.688000, + "ap-southeast-2|r5n.xlarge": 0.362000, + "ap-southeast-2|r6a.12xlarge": 3.261600, + "ap-southeast-2|r6a.16xlarge": 4.348800, + "ap-southeast-2|r6a.24xlarge": 6.523200, + "ap-southeast-2|r6a.2xlarge": 0.543600, + "ap-southeast-2|r6a.32xlarge": 8.697600, + "ap-southeast-2|r6a.48xlarge": 13.046400, + "ap-southeast-2|r6a.4xlarge": 1.087200, + "ap-southeast-2|r6a.8xlarge": 2.174400, + "ap-southeast-2|r6a.large": 0.135900, + "ap-southeast-2|r6a.metal": 13.046400, + "ap-southeast-2|r6a.xlarge": 0.271800, + "ap-southeast-2|r6g.12xlarge": 2.899200, + "ap-southeast-2|r6g.16xlarge": 3.865600, + "ap-southeast-2|r6g.2xlarge": 0.483200, + "ap-southeast-2|r6g.4xlarge": 0.966400, + "ap-southeast-2|r6g.8xlarge": 1.932800, + "ap-southeast-2|r6g.large": 0.120800, + "ap-southeast-2|r6g.medium": 0.060400, + "ap-southeast-2|r6g.metal": 3.865600, + "ap-southeast-2|r6g.xlarge": 0.241600, + "ap-southeast-2|r6gd.12xlarge": 3.336000, + "ap-southeast-2|r6gd.16xlarge": 4.448000, + "ap-southeast-2|r6gd.2xlarge": 0.556000, + "ap-southeast-2|r6gd.4xlarge": 1.112000, + "ap-southeast-2|r6gd.8xlarge": 2.224000, + "ap-southeast-2|r6gd.large": 0.139000, + "ap-southeast-2|r6gd.medium": 0.069500, + "ap-southeast-2|r6gd.metal": 4.448000, + "ap-southeast-2|r6gd.xlarge": 0.278000, + "ap-southeast-2|r6i.12xlarge": 3.624000, + "ap-southeast-2|r6i.16xlarge": 4.832000, + "ap-southeast-2|r6i.24xlarge": 7.248000, + "ap-southeast-2|r6i.2xlarge": 0.604000, + "ap-southeast-2|r6i.32xlarge": 9.664000, + "ap-southeast-2|r6i.4xlarge": 1.208000, + "ap-southeast-2|r6i.8xlarge": 2.416000, + "ap-southeast-2|r6i.large": 0.151000, + "ap-southeast-2|r6i.metal": 9.664000, + "ap-southeast-2|r6i.xlarge": 0.302000, + "ap-southeast-2|r6id.12xlarge": 4.176000, + "ap-southeast-2|r6id.16xlarge": 5.568000, + "ap-southeast-2|r6id.24xlarge": 8.352000, + "ap-southeast-2|r6id.2xlarge": 0.696000, + "ap-southeast-2|r6id.32xlarge": 11.136000, + "ap-southeast-2|r6id.4xlarge": 1.392000, + "ap-southeast-2|r6id.8xlarge": 2.784000, + "ap-southeast-2|r6id.large": 0.174000, + "ap-southeast-2|r6id.metal": 11.136000, + "ap-southeast-2|r6id.xlarge": 0.348000, + "ap-southeast-2|r6idn.12xlarge": 5.728320, + "ap-southeast-2|r6idn.16xlarge": 7.637760, + "ap-southeast-2|r6idn.24xlarge": 11.456640, + "ap-southeast-2|r6idn.2xlarge": 0.954720, + "ap-southeast-2|r6idn.32xlarge": 15.275520, + "ap-southeast-2|r6idn.4xlarge": 1.909440, + "ap-southeast-2|r6idn.8xlarge": 3.818880, + "ap-southeast-2|r6idn.large": 0.238680, + "ap-southeast-2|r6idn.metal": 15.275520, + "ap-southeast-2|r6idn.xlarge": 0.477360, + "ap-southeast-2|r6in.12xlarge": 5.082480, + "ap-southeast-2|r6in.16xlarge": 6.776640, + "ap-southeast-2|r6in.24xlarge": 10.164960, + "ap-southeast-2|r6in.2xlarge": 0.847080, + "ap-southeast-2|r6in.32xlarge": 13.553280, + "ap-southeast-2|r6in.4xlarge": 1.694160, + "ap-southeast-2|r6in.8xlarge": 3.388320, + "ap-southeast-2|r6in.large": 0.211770, + "ap-southeast-2|r6in.metal": 13.553280, + "ap-southeast-2|r6in.xlarge": 0.423540, + "ap-southeast-2|r7g.12xlarge": 3.080600, + "ap-southeast-2|r7g.16xlarge": 4.107500, + "ap-southeast-2|r7g.2xlarge": 0.513400, + "ap-southeast-2|r7g.4xlarge": 1.026900, + "ap-southeast-2|r7g.8xlarge": 2.053800, + "ap-southeast-2|r7g.large": 0.128400, + "ap-southeast-2|r7g.medium": 0.064200, + "ap-southeast-2|r7g.metal": 4.107500, + "ap-southeast-2|r7g.xlarge": 0.256700, + "ap-southeast-2|r7gd.12xlarge": 3.758400, + "ap-southeast-2|r7gd.16xlarge": 5.011200, + "ap-southeast-2|r7gd.2xlarge": 0.626400, + "ap-southeast-2|r7gd.4xlarge": 1.252800, + "ap-southeast-2|r7gd.8xlarge": 2.505600, + "ap-southeast-2|r7gd.large": 0.156600, + "ap-southeast-2|r7gd.medium": 0.078300, + "ap-southeast-2|r7gd.metal": 5.011200, + "ap-southeast-2|r7gd.xlarge": 0.313200, + "ap-southeast-2|r7i.12xlarge": 3.805200, + "ap-southeast-2|r7i.16xlarge": 5.073600, + "ap-southeast-2|r7i.24xlarge": 7.610400, + "ap-southeast-2|r7i.2xlarge": 0.634200, + "ap-southeast-2|r7i.48xlarge": 15.220800, + "ap-southeast-2|r7i.4xlarge": 1.268400, + "ap-southeast-2|r7i.8xlarge": 2.536800, + "ap-southeast-2|r7i.large": 0.158550, + "ap-southeast-2|r7i.metal-24xl": 7.610400, + "ap-southeast-2|r7i.metal-48xl": 15.220800, + "ap-southeast-2|r7i.xlarge": 0.317100, + "ap-southeast-2|r8g.12xlarge": 3.388800, + "ap-southeast-2|r8g.16xlarge": 4.518400, + "ap-southeast-2|r8g.24xlarge": 6.777600, + "ap-southeast-2|r8g.2xlarge": 0.564800, + "ap-southeast-2|r8g.48xlarge": 13.555200, + "ap-southeast-2|r8g.4xlarge": 1.129600, + "ap-southeast-2|r8g.8xlarge": 2.259200, + "ap-southeast-2|r8g.large": 0.141200, + "ap-southeast-2|r8g.medium": 0.070600, + "ap-southeast-2|r8g.metal-24xl": 6.777600, + "ap-southeast-2|r8g.metal-48xl": 13.555200, + "ap-southeast-2|r8g.xlarge": 0.282400, + "ap-southeast-2|r8gd.12xlarge": 4.058880, + "ap-southeast-2|r8gd.16xlarge": 5.411840, + "ap-southeast-2|r8gd.24xlarge": 8.117760, + "ap-southeast-2|r8gd.2xlarge": 0.676480, + "ap-southeast-2|r8gd.48xlarge": 16.235520, + "ap-southeast-2|r8gd.4xlarge": 1.352960, + "ap-southeast-2|r8gd.8xlarge": 2.705920, + "ap-southeast-2|r8gd.large": 0.169120, + "ap-southeast-2|r8gd.medium": 0.084560, + "ap-southeast-2|r8gd.metal-24xl": 8.117760, + "ap-southeast-2|r8gd.metal-48xl": 16.235520, + "ap-southeast-2|r8gd.xlarge": 0.338240, + "ap-southeast-2|r8i-flex.12xlarge": 3.795840, + "ap-southeast-2|r8i-flex.16xlarge": 5.061120, + "ap-southeast-2|r8i-flex.2xlarge": 0.632640, + "ap-southeast-2|r8i-flex.4xlarge": 1.265280, + "ap-southeast-2|r8i-flex.8xlarge": 2.530560, + "ap-southeast-2|r8i-flex.large": 0.158160, + "ap-southeast-2|r8i-flex.xlarge": 0.316320, + "ap-southeast-2|r8i.12xlarge": 3.995520, + "ap-southeast-2|r8i.16xlarge": 5.327360, + "ap-southeast-2|r8i.24xlarge": 7.991040, + "ap-southeast-2|r8i.2xlarge": 0.665920, + "ap-southeast-2|r8i.32xlarge": 10.654720, + "ap-southeast-2|r8i.48xlarge": 15.982080, + "ap-southeast-2|r8i.4xlarge": 1.331840, + "ap-southeast-2|r8i.8xlarge": 2.663680, + "ap-southeast-2|r8i.96xlarge": 31.964160, + "ap-southeast-2|r8i.large": 0.166480, + "ap-southeast-2|r8i.metal-48xl": 15.982080, + "ap-southeast-2|r8i.metal-96xl": 31.964160, + "ap-southeast-2|r8i.xlarge": 0.332960, + "ap-southeast-2|t1.micro": 0.020000, + "ap-southeast-2|t2.2xlarge": 0.467200, + "ap-southeast-2|t2.large": 0.116800, + "ap-southeast-2|t2.medium": 0.058400, + "ap-southeast-2|t2.micro": 0.014600, + "ap-southeast-2|t2.nano": 0.007300, + "ap-southeast-2|t2.small": 0.029200, + "ap-southeast-2|t2.xlarge": 0.233600, + "ap-southeast-2|t3.2xlarge": 0.422400, + "ap-southeast-2|t3.large": 0.105600, + "ap-southeast-2|t3.medium": 0.052800, + "ap-southeast-2|t3.micro": 0.013200, + "ap-southeast-2|t3.nano": 0.006600, + "ap-southeast-2|t3.small": 0.026400, + "ap-southeast-2|t3.xlarge": 0.211200, + "ap-southeast-2|t3a.2xlarge": 0.380200, + "ap-southeast-2|t3a.large": 0.095000, + "ap-southeast-2|t3a.medium": 0.047500, + "ap-southeast-2|t3a.micro": 0.011900, + "ap-southeast-2|t3a.nano": 0.005900, + "ap-southeast-2|t3a.small": 0.023800, + "ap-southeast-2|t3a.xlarge": 0.190100, + "ap-southeast-2|t4g.2xlarge": 0.339200, + "ap-southeast-2|t4g.large": 0.084800, + "ap-southeast-2|t4g.medium": 0.042400, + "ap-southeast-2|t4g.micro": 0.010600, + "ap-southeast-2|t4g.nano": 0.005300, + "ap-southeast-2|t4g.small": 0.021200, + "ap-southeast-2|t4g.xlarge": 0.169600, + "ap-southeast-2|u-12tb1.112xlarge": 130.867000, + "ap-southeast-2|u-3tb1.56xlarge": 32.715000, + "ap-southeast-2|u-6tb1.112xlarge": 65.433000, + "ap-southeast-2|u-6tb1.56xlarge": 55.610750, + "ap-southeast-2|u7i-6tb.112xlarge": 75.247950, + "ap-southeast-2|u7in-16tb.224xlarge": 216.283840, + "ap-southeast-2|x1.16xlarge": 9.671000, + "ap-southeast-2|x1.32xlarge": 19.341000, + "ap-southeast-2|x1e.16xlarge": 19.344000, + "ap-southeast-2|x1e.2xlarge": 2.418000, + "ap-southeast-2|x1e.32xlarge": 38.688000, + "ap-southeast-2|x1e.4xlarge": 4.836000, + "ap-southeast-2|x1e.8xlarge": 9.672000, + "ap-southeast-2|x1e.xlarge": 1.209000, + "ap-southeast-2|x2idn.16xlarge": 9.670500, + "ap-southeast-2|x2idn.24xlarge": 14.505750, + "ap-southeast-2|x2idn.32xlarge": 19.341000, + "ap-southeast-2|x2idn.metal": 19.341000, + "ap-southeast-2|x2iedn.16xlarge": 19.341000, + "ap-southeast-2|x2iedn.24xlarge": 29.011500, + "ap-southeast-2|x2iedn.2xlarge": 2.417630, + "ap-southeast-2|x2iedn.32xlarge": 38.682000, + "ap-southeast-2|x2iedn.4xlarge": 4.835250, + "ap-southeast-2|x2iedn.8xlarge": 9.670500, + "ap-southeast-2|x2iedn.metal": 38.682000, + "ap-southeast-2|x2iedn.xlarge": 1.208810, + "ap-southeast-2|x8g.12xlarge": 5.627520, + "ap-southeast-2|x8g.16xlarge": 7.503360, + "ap-southeast-2|x8g.24xlarge": 11.255040, + "ap-southeast-2|x8g.2xlarge": 0.937920, + "ap-southeast-2|x8g.48xlarge": 22.510080, + "ap-southeast-2|x8g.4xlarge": 1.875840, + "ap-southeast-2|x8g.8xlarge": 3.751680, + "ap-southeast-2|x8g.large": 0.234480, + "ap-southeast-2|x8g.medium": 0.117240, + "ap-southeast-2|x8g.metal-24xl": 11.255040, + "ap-southeast-2|x8g.metal-48xl": 22.510080, + "ap-southeast-2|x8g.xlarge": 0.468960, + "ap-southeast-2|z1d.12xlarge": 5.424000, + "ap-southeast-2|z1d.2xlarge": 0.904000, + "ap-southeast-2|z1d.3xlarge": 1.356000, + "ap-southeast-2|z1d.6xlarge": 2.712000, + "ap-southeast-2|z1d.large": 0.226000, + "ap-southeast-2|z1d.metal": 5.424000, + "ap-southeast-2|z1d.xlarge": 0.452000, + "ca-central-1|c4.2xlarge": 0.438000, + "ca-central-1|c4.4xlarge": 0.876000, + "ca-central-1|c4.8xlarge": 1.750000, + "ca-central-1|c4.large": 0.110000, + "ca-central-1|c4.xlarge": 0.218000, + "ca-central-1|c5.12xlarge": 2.232000, + "ca-central-1|c5.18xlarge": 3.348000, + "ca-central-1|c5.24xlarge": 4.464000, + "ca-central-1|c5.2xlarge": 0.372000, + "ca-central-1|c5.4xlarge": 0.744000, + "ca-central-1|c5.9xlarge": 1.674000, + "ca-central-1|c5.large": 0.093000, + "ca-central-1|c5.metal": 4.464000, + "ca-central-1|c5.xlarge": 0.186000, + "ca-central-1|c5a.12xlarge": 2.016000, + "ca-central-1|c5a.16xlarge": 2.688000, + "ca-central-1|c5a.24xlarge": 4.032000, + "ca-central-1|c5a.2xlarge": 0.336000, + "ca-central-1|c5a.4xlarge": 0.672000, + "ca-central-1|c5a.8xlarge": 1.344000, + "ca-central-1|c5a.large": 0.084000, + "ca-central-1|c5a.xlarge": 0.168000, + "ca-central-1|c5d.12xlarge": 2.544000, + "ca-central-1|c5d.18xlarge": 3.816000, + "ca-central-1|c5d.24xlarge": 5.088000, + "ca-central-1|c5d.2xlarge": 0.424000, + "ca-central-1|c5d.4xlarge": 0.848000, + "ca-central-1|c5d.9xlarge": 1.908000, + "ca-central-1|c5d.large": 0.106000, + "ca-central-1|c5d.metal": 5.088000, + "ca-central-1|c5d.xlarge": 0.212000, + "ca-central-1|c5n.18xlarge": 4.248000, + "ca-central-1|c5n.2xlarge": 0.472000, + "ca-central-1|c5n.4xlarge": 0.944000, + "ca-central-1|c5n.9xlarge": 2.124000, + "ca-central-1|c5n.large": 0.118000, + "ca-central-1|c5n.metal": 4.248000, + "ca-central-1|c5n.xlarge": 0.236000, + "ca-central-1|c6a.12xlarge": 2.008800, + "ca-central-1|c6a.16xlarge": 2.678400, + "ca-central-1|c6a.24xlarge": 4.017600, + "ca-central-1|c6a.2xlarge": 0.334800, + "ca-central-1|c6a.32xlarge": 5.356800, + "ca-central-1|c6a.48xlarge": 8.035200, + "ca-central-1|c6a.4xlarge": 0.669600, + "ca-central-1|c6a.8xlarge": 1.339200, + "ca-central-1|c6a.large": 0.083700, + "ca-central-1|c6a.metal": 8.035200, + "ca-central-1|c6a.xlarge": 0.167400, + "ca-central-1|c6g.12xlarge": 1.785600, + "ca-central-1|c6g.16xlarge": 2.380800, + "ca-central-1|c6g.2xlarge": 0.297600, + "ca-central-1|c6g.4xlarge": 0.595200, + "ca-central-1|c6g.8xlarge": 1.190400, + "ca-central-1|c6g.large": 0.074400, + "ca-central-1|c6g.medium": 0.037200, + "ca-central-1|c6g.metal": 2.380800, + "ca-central-1|c6g.xlarge": 0.148800, + "ca-central-1|c6gd.12xlarge": 2.035200, + "ca-central-1|c6gd.16xlarge": 2.713600, + "ca-central-1|c6gd.2xlarge": 0.339200, + "ca-central-1|c6gd.4xlarge": 0.678400, + "ca-central-1|c6gd.8xlarge": 1.356800, + "ca-central-1|c6gd.large": 0.084800, + "ca-central-1|c6gd.medium": 0.042400, + "ca-central-1|c6gd.metal": 2.713600, + "ca-central-1|c6gd.xlarge": 0.169600, + "ca-central-1|c6gn.12xlarge": 2.270400, + "ca-central-1|c6gn.16xlarge": 3.027200, + "ca-central-1|c6gn.2xlarge": 0.378400, + "ca-central-1|c6gn.4xlarge": 0.756800, + "ca-central-1|c6gn.8xlarge": 1.513600, + "ca-central-1|c6gn.large": 0.094600, + "ca-central-1|c6gn.medium": 0.047300, + "ca-central-1|c6gn.metal": 3.027200, + "ca-central-1|c6gn.xlarge": 0.189200, + "ca-central-1|c6i.12xlarge": 2.232000, + "ca-central-1|c6i.16xlarge": 2.976000, + "ca-central-1|c6i.24xlarge": 4.464000, + "ca-central-1|c6i.2xlarge": 0.372000, + "ca-central-1|c6i.32xlarge": 5.952000, + "ca-central-1|c6i.4xlarge": 0.744000, + "ca-central-1|c6i.8xlarge": 1.488000, + "ca-central-1|c6i.large": 0.093000, + "ca-central-1|c6i.metal": 5.952000, + "ca-central-1|c6i.xlarge": 0.186000, + "ca-central-1|c6id.12xlarge": 2.671200, + "ca-central-1|c6id.16xlarge": 3.561600, + "ca-central-1|c6id.24xlarge": 5.342400, + "ca-central-1|c6id.2xlarge": 0.445200, + "ca-central-1|c6id.32xlarge": 7.123200, + "ca-central-1|c6id.4xlarge": 0.890400, + "ca-central-1|c6id.8xlarge": 1.780800, + "ca-central-1|c6id.large": 0.111300, + "ca-central-1|c6id.metal": 7.123200, + "ca-central-1|c6id.xlarge": 0.222600, + "ca-central-1|c6in.12xlarge": 2.973600, + "ca-central-1|c6in.16xlarge": 3.964800, + "ca-central-1|c6in.24xlarge": 5.947200, + "ca-central-1|c6in.2xlarge": 0.495600, + "ca-central-1|c6in.32xlarge": 7.929600, + "ca-central-1|c6in.4xlarge": 0.991200, + "ca-central-1|c6in.8xlarge": 1.982400, + "ca-central-1|c6in.large": 0.123900, + "ca-central-1|c6in.metal": 7.929600, + "ca-central-1|c6in.xlarge": 0.247800, + "ca-central-1|c7g.12xlarge": 1.897400, + "ca-central-1|c7g.16xlarge": 2.529900, + "ca-central-1|c7g.2xlarge": 0.316200, + "ca-central-1|c7g.4xlarge": 0.632500, + "ca-central-1|c7g.8xlarge": 1.265000, + "ca-central-1|c7g.large": 0.079100, + "ca-central-1|c7g.medium": 0.039500, + "ca-central-1|c7g.metal": 2.529900, + "ca-central-1|c7g.xlarge": 0.158100, + "ca-central-1|c7gd.12xlarge": 2.403800, + "ca-central-1|c7gd.16xlarge": 3.205100, + "ca-central-1|c7gd.2xlarge": 0.400600, + "ca-central-1|c7gd.4xlarge": 0.801300, + "ca-central-1|c7gd.8xlarge": 1.602600, + "ca-central-1|c7gd.large": 0.100200, + "ca-central-1|c7gd.medium": 0.050100, + "ca-central-1|c7gd.metal": 3.205100, + "ca-central-1|c7gd.xlarge": 0.200300, + "ca-central-1|c7i-flex.12xlarge": 2.226420, + "ca-central-1|c7i-flex.16xlarge": 2.968560, + "ca-central-1|c7i-flex.2xlarge": 0.371070, + "ca-central-1|c7i-flex.4xlarge": 0.742140, + "ca-central-1|c7i-flex.8xlarge": 1.484280, + "ca-central-1|c7i-flex.large": 0.092770, + "ca-central-1|c7i-flex.xlarge": 0.185540, + "ca-central-1|c7i.12xlarge": 2.343600, + "ca-central-1|c7i.16xlarge": 3.124800, + "ca-central-1|c7i.24xlarge": 4.687200, + "ca-central-1|c7i.2xlarge": 0.390600, + "ca-central-1|c7i.48xlarge": 9.374400, + "ca-central-1|c7i.4xlarge": 0.781200, + "ca-central-1|c7i.8xlarge": 1.562400, + "ca-central-1|c7i.large": 0.097650, + "ca-central-1|c7i.metal-24xl": 4.687200, + "ca-central-1|c7i.metal-48xl": 9.374400, + "ca-central-1|c7i.xlarge": 0.195300, + "ca-central-1|c8g.12xlarge": 2.087040, + "ca-central-1|c8g.16xlarge": 2.782720, + "ca-central-1|c8g.24xlarge": 4.174080, + "ca-central-1|c8g.2xlarge": 0.347840, + "ca-central-1|c8g.48xlarge": 8.348160, + "ca-central-1|c8g.4xlarge": 0.695680, + "ca-central-1|c8g.8xlarge": 1.391360, + "ca-central-1|c8g.large": 0.086960, + "ca-central-1|c8g.medium": 0.043480, + "ca-central-1|c8g.metal-24xl": 4.174080, + "ca-central-1|c8g.metal-48xl": 8.348160, + "ca-central-1|c8g.xlarge": 0.173920, + "ca-central-1|c8gd.12xlarge": 2.596320, + "ca-central-1|c8gd.16xlarge": 3.461760, + "ca-central-1|c8gd.24xlarge": 5.192640, + "ca-central-1|c8gd.2xlarge": 0.432720, + "ca-central-1|c8gd.48xlarge": 10.385280, + "ca-central-1|c8gd.4xlarge": 0.865440, + "ca-central-1|c8gd.8xlarge": 1.730880, + "ca-central-1|c8gd.large": 0.108180, + "ca-central-1|c8gd.medium": 0.054090, + "ca-central-1|c8gd.metal-24xl": 5.192640, + "ca-central-1|c8gd.metal-48xl": 10.385280, + "ca-central-1|c8gd.xlarge": 0.216360, + "ca-central-1|d2.2xlarge": 1.518000, + "ca-central-1|d2.4xlarge": 3.036000, + "ca-central-1|d2.8xlarge": 6.072000, + "ca-central-1|d2.xlarge": 0.759000, + "ca-central-1|d3.2xlarge": 1.100000, + "ca-central-1|d3.4xlarge": 2.201000, + "ca-central-1|d3.8xlarge": 4.401120, + "ca-central-1|d3.xlarge": 0.550000, + "ca-central-1|f2.12xlarge": 4.356000, + "ca-central-1|f2.48xlarge": 17.424000, + "ca-central-1|f2.6xlarge": 2.178000, + "ca-central-1|g3.16xlarge": 5.664000, + "ca-central-1|g3.4xlarge": 1.416000, + "ca-central-1|g3.8xlarge": 2.832000, + "ca-central-1|g4ad.16xlarge": 3.872000, + "ca-central-1|g4ad.2xlarge": 0.604210, + "ca-central-1|g4ad.4xlarge": 0.968000, + "ca-central-1|g4ad.8xlarge": 1.936000, + "ca-central-1|g4ad.xlarge": 0.422630, + "ca-central-1|g4dn.12xlarge": 4.343000, + "ca-central-1|g4dn.16xlarge": 4.832000, + "ca-central-1|g4dn.2xlarge": 0.835000, + "ca-central-1|g4dn.4xlarge": 1.337000, + "ca-central-1|g4dn.8xlarge": 2.416000, + "ca-central-1|g4dn.metal": 8.687000, + "ca-central-1|g4dn.xlarge": 0.584000, + "ca-central-1|g5.12xlarge": 6.297840, + "ca-central-1|g5.16xlarge": 4.547940, + "ca-central-1|g5.24xlarge": 9.042590, + "ca-central-1|g5.2xlarge": 1.345730, + "ca-central-1|g5.48xlarge": 18.085180, + "ca-central-1|g5.4xlarge": 1.803190, + "ca-central-1|g5.8xlarge": 2.718110, + "ca-central-1|g5.xlarge": 1.117000, + "ca-central-1|g6.12xlarge": 5.109330, + "ca-central-1|g6.16xlarge": 3.771600, + "ca-central-1|g6.24xlarge": 7.411730, + "ca-central-1|g6.2xlarge": 1.085470, + "ca-central-1|g6.48xlarge": 14.823460, + "ca-central-1|g6.4xlarge": 1.469200, + "ca-central-1|g6.8xlarge": 2.236660, + "ca-central-1|g6.xlarge": 0.893600, + "ca-central-1|g6f.2xlarge": 0.527410, + "ca-central-1|g6f.4xlarge": 1.054820, + "ca-central-1|g6f.large": 0.224290, + "ca-central-1|g6f.xlarge": 0.263710, + "ca-central-1|gr6.4xlarge": 1.709000, + "ca-central-1|gr6.8xlarge": 2.716280, + "ca-central-1|gr6f.4xlarge": 1.183600, + "ca-central-1|i3.16xlarge": 5.504000, + "ca-central-1|i3.2xlarge": 0.688000, + "ca-central-1|i3.4xlarge": 1.376000, + "ca-central-1|i3.8xlarge": 2.752000, + "ca-central-1|i3.large": 0.172000, + "ca-central-1|i3.metal": 5.504000, + "ca-central-1|i3.xlarge": 0.344000, + "ca-central-1|i3en.12xlarge": 6.000000, + "ca-central-1|i3en.24xlarge": 12.000000, + "ca-central-1|i3en.2xlarge": 1.000000, + "ca-central-1|i3en.3xlarge": 1.500000, + "ca-central-1|i3en.6xlarge": 3.000000, + "ca-central-1|i3en.large": 0.250000, + "ca-central-1|i3en.metal": 12.000000, + "ca-central-1|i3en.xlarge": 0.500000, + "ca-central-1|i4g.16xlarge": 5.446370, + "ca-central-1|i4g.2xlarge": 0.680800, + "ca-central-1|i4g.4xlarge": 1.361590, + "ca-central-1|i4g.8xlarge": 2.723190, + "ca-central-1|i4g.large": 0.170200, + "ca-central-1|i4g.xlarge": 0.340400, + "ca-central-1|i4i.12xlarge": 4.541000, + "ca-central-1|i4i.16xlarge": 6.054000, + "ca-central-1|i4i.24xlarge": 9.081600, + "ca-central-1|i4i.2xlarge": 0.757000, + "ca-central-1|i4i.32xlarge": 12.108800, + "ca-central-1|i4i.4xlarge": 1.514000, + "ca-central-1|i4i.8xlarge": 3.027000, + "ca-central-1|i4i.large": 0.189000, + "ca-central-1|i4i.metal": 12.109000, + "ca-central-1|i4i.xlarge": 0.378000, + "ca-central-1|i7i.12xlarge": 4.994900, + "ca-central-1|i7i.16xlarge": 6.659800, + "ca-central-1|i7i.24xlarge": 9.989800, + "ca-central-1|i7i.2xlarge": 0.832500, + "ca-central-1|i7i.48xlarge": 19.979500, + "ca-central-1|i7i.4xlarge": 1.665000, + "ca-central-1|i7i.8xlarge": 3.329900, + "ca-central-1|i7i.large": 0.208100, + "ca-central-1|i7i.metal-24xl": 9.989800, + "ca-central-1|i7i.metal-48xl": 19.979500, + "ca-central-1|i7i.xlarge": 0.416200, + "ca-central-1|i8g.12xlarge": 4.538400, + "ca-central-1|i8g.16xlarge": 6.051200, + "ca-central-1|i8g.24xlarge": 9.076800, + "ca-central-1|i8g.2xlarge": 0.756400, + "ca-central-1|i8g.48xlarge": 18.153600, + "ca-central-1|i8g.4xlarge": 1.512800, + "ca-central-1|i8g.8xlarge": 3.025600, + "ca-central-1|i8g.large": 0.189100, + "ca-central-1|i8g.metal-24xl": 9.076800, + "ca-central-1|i8g.xlarge": 0.378200, + "ca-central-1|im4gn.16xlarge": 6.417660, + "ca-central-1|im4gn.2xlarge": 0.802210, + "ca-central-1|im4gn.4xlarge": 1.604420, + "ca-central-1|im4gn.8xlarge": 3.208830, + "ca-central-1|im4gn.large": 0.200550, + "ca-central-1|im4gn.xlarge": 0.401100, + "ca-central-1|inf1.24xlarge": 5.260000, + "ca-central-1|inf1.2xlarge": 0.403000, + "ca-central-1|inf1.6xlarge": 1.315000, + "ca-central-1|inf1.xlarge": 0.254000, + "ca-central-1|is4gen.2xlarge": 1.275000, + "ca-central-1|is4gen.4xlarge": 2.550000, + "ca-central-1|is4gen.8xlarge": 5.100000, + "ca-central-1|is4gen.large": 0.318750, + "ca-central-1|is4gen.medium": 0.159380, + "ca-central-1|is4gen.xlarge": 0.637500, + "ca-central-1|m4.10xlarge": 2.220000, + "ca-central-1|m4.16xlarge": 3.552000, + "ca-central-1|m4.2xlarge": 0.444000, + "ca-central-1|m4.4xlarge": 0.888000, + "ca-central-1|m4.large": 0.111000, + "ca-central-1|m4.xlarge": 0.222000, + "ca-central-1|m5.12xlarge": 2.568000, + "ca-central-1|m5.16xlarge": 3.424000, + "ca-central-1|m5.24xlarge": 5.136000, + "ca-central-1|m5.2xlarge": 0.428000, + "ca-central-1|m5.4xlarge": 0.856000, + "ca-central-1|m5.8xlarge": 1.712000, + "ca-central-1|m5.large": 0.107000, + "ca-central-1|m5.metal": 5.136000, + "ca-central-1|m5.xlarge": 0.214000, + "ca-central-1|m5a.12xlarge": 2.304000, + "ca-central-1|m5a.16xlarge": 3.072000, + "ca-central-1|m5a.24xlarge": 4.608000, + "ca-central-1|m5a.2xlarge": 0.384000, + "ca-central-1|m5a.4xlarge": 0.768000, + "ca-central-1|m5a.8xlarge": 1.536000, + "ca-central-1|m5a.large": 0.096000, + "ca-central-1|m5a.xlarge": 0.192000, + "ca-central-1|m5ad.12xlarge": 2.760000, + "ca-central-1|m5ad.16xlarge": 3.680000, + "ca-central-1|m5ad.24xlarge": 5.520000, + "ca-central-1|m5ad.2xlarge": 0.460000, + "ca-central-1|m5ad.4xlarge": 0.920000, + "ca-central-1|m5ad.8xlarge": 1.840000, + "ca-central-1|m5ad.large": 0.115000, + "ca-central-1|m5ad.xlarge": 0.230000, + "ca-central-1|m5d.12xlarge": 3.024000, + "ca-central-1|m5d.16xlarge": 4.032000, + "ca-central-1|m5d.24xlarge": 6.048000, + "ca-central-1|m5d.2xlarge": 0.504000, + "ca-central-1|m5d.4xlarge": 1.008000, + "ca-central-1|m5d.8xlarge": 2.016000, + "ca-central-1|m5d.large": 0.126000, + "ca-central-1|m5d.metal": 6.048000, + "ca-central-1|m5d.xlarge": 0.252000, + "ca-central-1|m6a.12xlarge": 2.311200, + "ca-central-1|m6a.16xlarge": 3.081600, + "ca-central-1|m6a.24xlarge": 4.622400, + "ca-central-1|m6a.2xlarge": 0.385200, + "ca-central-1|m6a.32xlarge": 6.163200, + "ca-central-1|m6a.48xlarge": 9.244800, + "ca-central-1|m6a.4xlarge": 0.770400, + "ca-central-1|m6a.8xlarge": 1.540800, + "ca-central-1|m6a.large": 0.096300, + "ca-central-1|m6a.metal": 9.244800, + "ca-central-1|m6a.xlarge": 0.192600, + "ca-central-1|m6g.12xlarge": 2.054400, + "ca-central-1|m6g.16xlarge": 2.739200, + "ca-central-1|m6g.2xlarge": 0.342400, + "ca-central-1|m6g.4xlarge": 0.684800, + "ca-central-1|m6g.8xlarge": 1.369600, + "ca-central-1|m6g.large": 0.085600, + "ca-central-1|m6g.medium": 0.042800, + "ca-central-1|m6g.metal": 2.739200, + "ca-central-1|m6g.xlarge": 0.171200, + "ca-central-1|m6gd.12xlarge": 2.419200, + "ca-central-1|m6gd.16xlarge": 3.225600, + "ca-central-1|m6gd.2xlarge": 0.403200, + "ca-central-1|m6gd.4xlarge": 0.806400, + "ca-central-1|m6gd.8xlarge": 1.612800, + "ca-central-1|m6gd.large": 0.100800, + "ca-central-1|m6gd.medium": 0.050400, + "ca-central-1|m6gd.metal": 3.225600, + "ca-central-1|m6gd.xlarge": 0.201600, + "ca-central-1|m6i.12xlarge": 2.568000, + "ca-central-1|m6i.16xlarge": 3.424000, + "ca-central-1|m6i.24xlarge": 5.136000, + "ca-central-1|m6i.2xlarge": 0.428000, + "ca-central-1|m6i.32xlarge": 6.848000, + "ca-central-1|m6i.4xlarge": 0.856000, + "ca-central-1|m6i.8xlarge": 1.712000, + "ca-central-1|m6i.large": 0.107000, + "ca-central-1|m6i.metal": 6.848000, + "ca-central-1|m6i.xlarge": 0.214000, + "ca-central-1|m6id.12xlarge": 3.175200, + "ca-central-1|m6id.16xlarge": 4.233600, + "ca-central-1|m6id.24xlarge": 6.350400, + "ca-central-1|m6id.2xlarge": 0.529200, + "ca-central-1|m6id.32xlarge": 8.467200, + "ca-central-1|m6id.4xlarge": 1.058400, + "ca-central-1|m6id.8xlarge": 2.116800, + "ca-central-1|m6id.large": 0.132300, + "ca-central-1|m6id.metal": 8.467200, + "ca-central-1|m6id.xlarge": 0.264600, + "ca-central-1|m6idn.12xlarge": 4.180320, + "ca-central-1|m6idn.16xlarge": 5.573760, + "ca-central-1|m6idn.24xlarge": 8.360640, + "ca-central-1|m6idn.2xlarge": 0.696720, + "ca-central-1|m6idn.32xlarge": 11.147520, + "ca-central-1|m6idn.4xlarge": 1.393440, + "ca-central-1|m6idn.8xlarge": 2.786880, + "ca-central-1|m6idn.large": 0.174180, + "ca-central-1|m6idn.metal": 11.147520, + "ca-central-1|m6idn.xlarge": 0.348360, + "ca-central-1|m6in.12xlarge": 3.724320, + "ca-central-1|m6in.16xlarge": 4.965760, + "ca-central-1|m6in.24xlarge": 7.448640, + "ca-central-1|m6in.2xlarge": 0.620720, + "ca-central-1|m6in.32xlarge": 9.931520, + "ca-central-1|m6in.4xlarge": 1.241440, + "ca-central-1|m6in.8xlarge": 2.482880, + "ca-central-1|m6in.large": 0.155180, + "ca-central-1|m6in.metal": 9.931520, + "ca-central-1|m6in.xlarge": 0.310360, + "ca-central-1|m7g.12xlarge": 2.183000, + "ca-central-1|m7g.16xlarge": 2.910700, + "ca-central-1|m7g.2xlarge": 0.363800, + "ca-central-1|m7g.4xlarge": 0.727700, + "ca-central-1|m7g.8xlarge": 1.455400, + "ca-central-1|m7g.large": 0.091000, + "ca-central-1|m7g.medium": 0.045500, + "ca-central-1|m7g.metal": 2.910700, + "ca-central-1|m7g.xlarge": 0.181900, + "ca-central-1|m7i-flex.12xlarge": 2.561520, + "ca-central-1|m7i-flex.16xlarge": 3.415360, + "ca-central-1|m7i-flex.2xlarge": 0.426920, + "ca-central-1|m7i-flex.4xlarge": 0.853840, + "ca-central-1|m7i-flex.8xlarge": 1.707680, + "ca-central-1|m7i-flex.large": 0.106730, + "ca-central-1|m7i-flex.xlarge": 0.213460, + "ca-central-1|m7i.12xlarge": 2.696400, + "ca-central-1|m7i.16xlarge": 3.595200, + "ca-central-1|m7i.24xlarge": 5.392800, + "ca-central-1|m7i.2xlarge": 0.449400, + "ca-central-1|m7i.48xlarge": 10.785600, + "ca-central-1|m7i.4xlarge": 0.898800, + "ca-central-1|m7i.8xlarge": 1.797600, + "ca-central-1|m7i.large": 0.112350, + "ca-central-1|m7i.metal-24xl": 5.392800, + "ca-central-1|m7i.metal-48xl": 10.785600, + "ca-central-1|m7i.xlarge": 0.224700, + "ca-central-1|m8g.12xlarge": 2.401440, + "ca-central-1|m8g.16xlarge": 3.201920, + "ca-central-1|m8g.24xlarge": 4.802880, + "ca-central-1|m8g.2xlarge": 0.400240, + "ca-central-1|m8g.48xlarge": 9.605760, + "ca-central-1|m8g.4xlarge": 0.800480, + "ca-central-1|m8g.8xlarge": 1.600960, + "ca-central-1|m8g.large": 0.100060, + "ca-central-1|m8g.medium": 0.050030, + "ca-central-1|m8g.metal-24xl": 4.802880, + "ca-central-1|m8g.metal-48xl": 9.605760, + "ca-central-1|m8g.xlarge": 0.200120, + "ca-central-1|m8gd.12xlarge": 3.086400, + "ca-central-1|m8gd.16xlarge": 4.115200, + "ca-central-1|m8gd.24xlarge": 6.172800, + "ca-central-1|m8gd.2xlarge": 0.514400, + "ca-central-1|m8gd.48xlarge": 12.345600, + "ca-central-1|m8gd.4xlarge": 1.028800, + "ca-central-1|m8gd.8xlarge": 2.057600, + "ca-central-1|m8gd.large": 0.128600, + "ca-central-1|m8gd.medium": 0.064300, + "ca-central-1|m8gd.metal-24xl": 6.172800, + "ca-central-1|m8gd.metal-48xl": 12.345600, + "ca-central-1|m8gd.xlarge": 0.257200, + "ca-central-1|m8i.12xlarge": 2.831280, + "ca-central-1|m8i.16xlarge": 3.775040, + "ca-central-1|m8i.24xlarge": 5.662560, + "ca-central-1|m8i.2xlarge": 0.471880, + "ca-central-1|m8i.32xlarge": 7.550080, + "ca-central-1|m8i.48xlarge": 11.325120, + "ca-central-1|m8i.4xlarge": 0.943760, + "ca-central-1|m8i.8xlarge": 1.887520, + "ca-central-1|m8i.96xlarge": 22.650240, + "ca-central-1|m8i.large": 0.117970, + "ca-central-1|m8i.metal-48xl": 11.325120, + "ca-central-1|m8i.metal-96xl": 22.650240, + "ca-central-1|m8i.xlarge": 0.235940, + "ca-central-1|p3.16xlarge": 26.928000, + "ca-central-1|p3.2xlarge": 3.366000, + "ca-central-1|p3.8xlarge": 13.464000, + "ca-central-1|p4d.24xlarge": 25.251740, + "ca-central-1|p5.48xlarge": 63.296000, + "ca-central-1|r4.16xlarge": 4.672000, + "ca-central-1|r4.2xlarge": 0.584000, + "ca-central-1|r4.4xlarge": 1.168000, + "ca-central-1|r4.8xlarge": 2.336000, + "ca-central-1|r4.large": 0.146000, + "ca-central-1|r4.xlarge": 0.292000, + "ca-central-1|r5.12xlarge": 3.312000, + "ca-central-1|r5.16xlarge": 4.416000, + "ca-central-1|r5.24xlarge": 6.624000, + "ca-central-1|r5.2xlarge": 0.552000, + "ca-central-1|r5.4xlarge": 1.104000, + "ca-central-1|r5.8xlarge": 2.208000, + "ca-central-1|r5.large": 0.138000, + "ca-central-1|r5.metal": 6.624000, + "ca-central-1|r5.xlarge": 0.276000, + "ca-central-1|r5a.12xlarge": 2.976000, + "ca-central-1|r5a.16xlarge": 3.968000, + "ca-central-1|r5a.24xlarge": 5.952000, + "ca-central-1|r5a.2xlarge": 0.496000, + "ca-central-1|r5a.4xlarge": 0.992000, + "ca-central-1|r5a.8xlarge": 1.984000, + "ca-central-1|r5a.large": 0.124000, + "ca-central-1|r5a.xlarge": 0.248000, + "ca-central-1|r5ad.12xlarge": 3.456000, + "ca-central-1|r5ad.16xlarge": 4.608000, + "ca-central-1|r5ad.24xlarge": 6.912000, + "ca-central-1|r5ad.2xlarge": 0.576000, + "ca-central-1|r5ad.4xlarge": 1.152000, + "ca-central-1|r5ad.8xlarge": 2.304000, + "ca-central-1|r5ad.large": 0.144000, + "ca-central-1|r5ad.xlarge": 0.288000, + "ca-central-1|r5b.12xlarge": 3.912000, + "ca-central-1|r5b.16xlarge": 5.216000, + "ca-central-1|r5b.24xlarge": 7.824000, + "ca-central-1|r5b.2xlarge": 0.652000, + "ca-central-1|r5b.4xlarge": 1.304000, + "ca-central-1|r5b.8xlarge": 2.608000, + "ca-central-1|r5b.large": 0.163000, + "ca-central-1|r5b.metal": 7.824000, + "ca-central-1|r5b.xlarge": 0.326000, + "ca-central-1|r5d.12xlarge": 3.792000, + "ca-central-1|r5d.16xlarge": 5.056000, + "ca-central-1|r5d.24xlarge": 7.584000, + "ca-central-1|r5d.2xlarge": 0.632000, + "ca-central-1|r5d.4xlarge": 1.264000, + "ca-central-1|r5d.8xlarge": 2.528000, + "ca-central-1|r5d.large": 0.158000, + "ca-central-1|r5d.metal": 7.584000, + "ca-central-1|r5d.xlarge": 0.316000, + "ca-central-1|r5n.12xlarge": 3.912000, + "ca-central-1|r5n.16xlarge": 5.216000, + "ca-central-1|r5n.24xlarge": 7.824000, + "ca-central-1|r5n.2xlarge": 0.652000, + "ca-central-1|r5n.4xlarge": 1.304000, + "ca-central-1|r5n.8xlarge": 2.608000, + "ca-central-1|r5n.large": 0.163000, + "ca-central-1|r5n.metal": 7.824000, + "ca-central-1|r5n.xlarge": 0.326000, + "ca-central-1|r6a.12xlarge": 2.980800, + "ca-central-1|r6a.16xlarge": 3.974400, + "ca-central-1|r6a.24xlarge": 5.961600, + "ca-central-1|r6a.2xlarge": 0.496800, + "ca-central-1|r6a.32xlarge": 7.948800, + "ca-central-1|r6a.48xlarge": 11.923200, + "ca-central-1|r6a.4xlarge": 0.993600, + "ca-central-1|r6a.8xlarge": 1.987200, + "ca-central-1|r6a.large": 0.124200, + "ca-central-1|r6a.metal": 11.923200, + "ca-central-1|r6a.xlarge": 0.248400, + "ca-central-1|r6g.12xlarge": 2.649600, + "ca-central-1|r6g.16xlarge": 3.532800, + "ca-central-1|r6g.2xlarge": 0.441600, + "ca-central-1|r6g.4xlarge": 0.883200, + "ca-central-1|r6g.8xlarge": 1.766400, + "ca-central-1|r6g.large": 0.110400, + "ca-central-1|r6g.medium": 0.055200, + "ca-central-1|r6g.metal": 3.532800, + "ca-central-1|r6g.xlarge": 0.220800, + "ca-central-1|r6gd.12xlarge": 3.033600, + "ca-central-1|r6gd.16xlarge": 4.044800, + "ca-central-1|r6gd.2xlarge": 0.505600, + "ca-central-1|r6gd.4xlarge": 1.011200, + "ca-central-1|r6gd.8xlarge": 2.022400, + "ca-central-1|r6gd.large": 0.126400, + "ca-central-1|r6gd.medium": 0.063200, + "ca-central-1|r6gd.metal": 4.044800, + "ca-central-1|r6gd.xlarge": 0.252800, + "ca-central-1|r6i.12xlarge": 3.312000, + "ca-central-1|r6i.16xlarge": 4.416000, + "ca-central-1|r6i.24xlarge": 6.624000, + "ca-central-1|r6i.2xlarge": 0.552000, + "ca-central-1|r6i.32xlarge": 8.832000, + "ca-central-1|r6i.4xlarge": 1.104000, + "ca-central-1|r6i.8xlarge": 2.208000, + "ca-central-1|r6i.large": 0.138000, + "ca-central-1|r6i.metal": 8.832000, + "ca-central-1|r6i.xlarge": 0.276000, + "ca-central-1|r7g.12xlarge": 2.815200, + "ca-central-1|r7g.16xlarge": 3.753600, + "ca-central-1|r7g.2xlarge": 0.469200, + "ca-central-1|r7g.4xlarge": 0.938400, + "ca-central-1|r7g.8xlarge": 1.876800, + "ca-central-1|r7g.large": 0.117300, + "ca-central-1|r7g.medium": 0.058700, + "ca-central-1|r7g.metal": 3.753600, + "ca-central-1|r7g.xlarge": 0.234600, + "ca-central-1|r7i.12xlarge": 3.477600, + "ca-central-1|r7i.16xlarge": 4.636800, + "ca-central-1|r7i.24xlarge": 6.955200, + "ca-central-1|r7i.2xlarge": 0.579600, + "ca-central-1|r7i.48xlarge": 13.910400, + "ca-central-1|r7i.4xlarge": 1.159200, + "ca-central-1|r7i.8xlarge": 2.318400, + "ca-central-1|r7i.large": 0.144900, + "ca-central-1|r7i.metal-24xl": 6.955200, + "ca-central-1|r7i.metal-48xl": 13.910400, + "ca-central-1|r7i.xlarge": 0.289800, + "ca-central-1|r8g.12xlarge": 3.096960, + "ca-central-1|r8g.16xlarge": 4.129280, + "ca-central-1|r8g.24xlarge": 6.193920, + "ca-central-1|r8g.2xlarge": 0.516160, + "ca-central-1|r8g.48xlarge": 12.387840, + "ca-central-1|r8g.4xlarge": 1.032320, + "ca-central-1|r8g.8xlarge": 2.064640, + "ca-central-1|r8g.large": 0.129040, + "ca-central-1|r8g.medium": 0.064520, + "ca-central-1|r8g.metal-24xl": 6.193920, + "ca-central-1|r8g.metal-48xl": 12.387840, + "ca-central-1|r8g.xlarge": 0.258080, + "ca-central-1|r8gd.12xlarge": 3.869760, + "ca-central-1|r8gd.16xlarge": 5.159680, + "ca-central-1|r8gd.24xlarge": 7.739520, + "ca-central-1|r8gd.2xlarge": 0.644960, + "ca-central-1|r8gd.48xlarge": 15.479040, + "ca-central-1|r8gd.4xlarge": 1.289920, + "ca-central-1|r8gd.8xlarge": 2.579840, + "ca-central-1|r8gd.large": 0.161240, + "ca-central-1|r8gd.medium": 0.080620, + "ca-central-1|r8gd.metal-24xl": 7.739520, + "ca-central-1|r8gd.metal-48xl": 15.479040, + "ca-central-1|r8gd.xlarge": 0.322480, + "ca-central-1|r8i-flex.12xlarge": 3.468960, + "ca-central-1|r8i-flex.16xlarge": 4.625280, + "ca-central-1|r8i-flex.2xlarge": 0.578160, + "ca-central-1|r8i-flex.4xlarge": 1.156320, + "ca-central-1|r8i-flex.8xlarge": 2.312640, + "ca-central-1|r8i-flex.large": 0.144540, + "ca-central-1|r8i-flex.xlarge": 0.289080, + "ca-central-1|r8i.12xlarge": 3.651600, + "ca-central-1|r8i.16xlarge": 4.868800, + "ca-central-1|r8i.24xlarge": 7.303200, + "ca-central-1|r8i.2xlarge": 0.608600, + "ca-central-1|r8i.32xlarge": 9.737600, + "ca-central-1|r8i.48xlarge": 14.606400, + "ca-central-1|r8i.4xlarge": 1.217200, + "ca-central-1|r8i.8xlarge": 2.434400, + "ca-central-1|r8i.96xlarge": 29.212800, + "ca-central-1|r8i.large": 0.152150, + "ca-central-1|r8i.metal-48xl": 14.606400, + "ca-central-1|r8i.metal-96xl": 29.212800, + "ca-central-1|r8i.xlarge": 0.304300, + "ca-central-1|t2.2xlarge": 0.409600, + "ca-central-1|t2.large": 0.102400, + "ca-central-1|t2.medium": 0.051200, + "ca-central-1|t2.micro": 0.012800, + "ca-central-1|t2.nano": 0.006400, + "ca-central-1|t2.small": 0.025600, + "ca-central-1|t2.xlarge": 0.204800, + "ca-central-1|t3.2xlarge": 0.371200, + "ca-central-1|t3.large": 0.092800, + "ca-central-1|t3.medium": 0.046400, + "ca-central-1|t3.micro": 0.011600, + "ca-central-1|t3.nano": 0.005800, + "ca-central-1|t3.small": 0.023200, + "ca-central-1|t3.xlarge": 0.185600, + "ca-central-1|t3a.2xlarge": 0.334100, + "ca-central-1|t3a.large": 0.083500, + "ca-central-1|t3a.medium": 0.041800, + "ca-central-1|t3a.micro": 0.010400, + "ca-central-1|t3a.nano": 0.005200, + "ca-central-1|t3a.small": 0.020900, + "ca-central-1|t3a.xlarge": 0.167000, + "ca-central-1|t4g.2xlarge": 0.294400, + "ca-central-1|t4g.large": 0.073600, + "ca-central-1|t4g.medium": 0.036800, + "ca-central-1|t4g.micro": 0.009200, + "ca-central-1|t4g.nano": 0.004600, + "ca-central-1|t4g.small": 0.018400, + "ca-central-1|t4g.xlarge": 0.147200, + "ca-central-1|u-3tb1.56xlarge": 29.900000, + "ca-central-1|u-6tb1.112xlarge": 59.800000, + "ca-central-1|u-6tb1.56xlarge": 50.823330, + "ca-central-1|x1.16xlarge": 7.336000, + "ca-central-1|x1.32xlarge": 14.672000, + "ca-central-1|x1e.16xlarge": 14.669000, + "ca-central-1|x1e.2xlarge": 1.834000, + "ca-central-1|x1e.32xlarge": 29.338000, + "ca-central-1|x1e.4xlarge": 3.667000, + "ca-central-1|x1e.8xlarge": 7.334000, + "ca-central-1|x1e.xlarge": 0.917000, + "ca-central-1|x2idn.16xlarge": 7.336000, + "ca-central-1|x2idn.24xlarge": 11.004000, + "ca-central-1|x2idn.32xlarge": 14.672000, + "ca-central-1|x2idn.metal": 14.672000, + "ca-central-1|x2iedn.16xlarge": 14.672000, + "ca-central-1|x2iedn.24xlarge": 22.008000, + "ca-central-1|x2iedn.2xlarge": 1.834000, + "ca-central-1|x2iedn.32xlarge": 29.344000, + "ca-central-1|x2iedn.4xlarge": 3.668000, + "ca-central-1|x2iedn.8xlarge": 7.336000, + "ca-central-1|x2iedn.metal": 29.344000, + "ca-central-1|x2iedn.xlarge": 0.917000, + "eu-central-1|a1.2xlarge": 0.232800, + "eu-central-1|a1.4xlarge": 0.465600, + "eu-central-1|a1.large": 0.058200, + "eu-central-1|a1.medium": 0.029100, + "eu-central-1|a1.metal": 0.466000, + "eu-central-1|a1.xlarge": 0.116400, + "eu-central-1|c3.2xlarge": 0.516000, + "eu-central-1|c3.4xlarge": 1.032000, + "eu-central-1|c3.8xlarge": 2.064000, + "eu-central-1|c3.large": 0.129000, + "eu-central-1|c3.xlarge": 0.258000, + "eu-central-1|c4.2xlarge": 0.454000, + "eu-central-1|c4.4xlarge": 0.909000, + "eu-central-1|c4.8xlarge": 1.817000, + "eu-central-1|c4.large": 0.114000, + "eu-central-1|c4.xlarge": 0.227000, + "eu-central-1|c5.12xlarge": 2.328000, + "eu-central-1|c5.18xlarge": 3.492000, + "eu-central-1|c5.24xlarge": 4.656000, + "eu-central-1|c5.2xlarge": 0.388000, + "eu-central-1|c5.4xlarge": 0.776000, + "eu-central-1|c5.9xlarge": 1.746000, + "eu-central-1|c5.large": 0.097000, + "eu-central-1|c5.metal": 4.656000, + "eu-central-1|c5.xlarge": 0.194000, + "eu-central-1|c5a.12xlarge": 2.088000, + "eu-central-1|c5a.16xlarge": 2.784000, + "eu-central-1|c5a.24xlarge": 4.176000, + "eu-central-1|c5a.2xlarge": 0.348000, + "eu-central-1|c5a.4xlarge": 0.696000, + "eu-central-1|c5a.8xlarge": 1.392000, + "eu-central-1|c5a.large": 0.087000, + "eu-central-1|c5a.xlarge": 0.174000, + "eu-central-1|c5ad.12xlarge": 2.400000, + "eu-central-1|c5ad.16xlarge": 3.200000, + "eu-central-1|c5ad.24xlarge": 4.800000, + "eu-central-1|c5ad.2xlarge": 0.400000, + "eu-central-1|c5ad.4xlarge": 0.800000, + "eu-central-1|c5ad.8xlarge": 1.600000, + "eu-central-1|c5ad.large": 0.100000, + "eu-central-1|c5ad.xlarge": 0.200000, + "eu-central-1|c5d.12xlarge": 2.664000, + "eu-central-1|c5d.18xlarge": 3.996000, + "eu-central-1|c5d.24xlarge": 5.328000, + "eu-central-1|c5d.2xlarge": 0.444000, + "eu-central-1|c5d.4xlarge": 0.888000, + "eu-central-1|c5d.9xlarge": 1.998000, + "eu-central-1|c5d.large": 0.111000, + "eu-central-1|c5d.metal": 5.328000, + "eu-central-1|c5d.xlarge": 0.222000, + "eu-central-1|c5n.18xlarge": 4.428000, + "eu-central-1|c5n.2xlarge": 0.492000, + "eu-central-1|c5n.4xlarge": 0.984000, + "eu-central-1|c5n.9xlarge": 2.214000, + "eu-central-1|c5n.large": 0.123000, + "eu-central-1|c5n.metal": 4.428000, + "eu-central-1|c5n.xlarge": 0.246000, + "eu-central-1|c6a.12xlarge": 2.095200, + "eu-central-1|c6a.16xlarge": 2.793600, + "eu-central-1|c6a.24xlarge": 4.190400, + "eu-central-1|c6a.2xlarge": 0.349200, + "eu-central-1|c6a.32xlarge": 5.587200, + "eu-central-1|c6a.48xlarge": 8.380800, + "eu-central-1|c6a.4xlarge": 0.698400, + "eu-central-1|c6a.8xlarge": 1.396800, + "eu-central-1|c6a.large": 0.087300, + "eu-central-1|c6a.metal": 8.380800, + "eu-central-1|c6a.xlarge": 0.174600, + "eu-central-1|c6g.12xlarge": 1.862400, + "eu-central-1|c6g.16xlarge": 2.483200, + "eu-central-1|c6g.2xlarge": 0.310400, + "eu-central-1|c6g.4xlarge": 0.620800, + "eu-central-1|c6g.8xlarge": 1.241600, + "eu-central-1|c6g.large": 0.077600, + "eu-central-1|c6g.medium": 0.038800, + "eu-central-1|c6g.metal": 2.483200, + "eu-central-1|c6g.xlarge": 0.155200, + "eu-central-1|c6gd.12xlarge": 2.136000, + "eu-central-1|c6gd.16xlarge": 2.848000, + "eu-central-1|c6gd.2xlarge": 0.356000, + "eu-central-1|c6gd.4xlarge": 0.712000, + "eu-central-1|c6gd.8xlarge": 1.424000, + "eu-central-1|c6gd.large": 0.089000, + "eu-central-1|c6gd.medium": 0.044500, + "eu-central-1|c6gd.metal": 2.848000, + "eu-central-1|c6gd.xlarge": 0.178000, + "eu-central-1|c6gn.12xlarge": 2.366400, + "eu-central-1|c6gn.16xlarge": 3.155200, + "eu-central-1|c6gn.2xlarge": 0.394400, + "eu-central-1|c6gn.4xlarge": 0.788800, + "eu-central-1|c6gn.8xlarge": 1.577600, + "eu-central-1|c6gn.large": 0.098600, + "eu-central-1|c6gn.medium": 0.049300, + "eu-central-1|c6gn.xlarge": 0.197200, + "eu-central-1|c6i.12xlarge": 2.328000, + "eu-central-1|c6i.16xlarge": 3.104000, + "eu-central-1|c6i.24xlarge": 4.656000, + "eu-central-1|c6i.2xlarge": 0.388000, + "eu-central-1|c6i.32xlarge": 6.208000, + "eu-central-1|c6i.4xlarge": 0.776000, + "eu-central-1|c6i.8xlarge": 1.552000, + "eu-central-1|c6i.large": 0.097000, + "eu-central-1|c6i.metal": 6.208000, + "eu-central-1|c6i.xlarge": 0.194000, + "eu-central-1|c6id.12xlarge": 2.797200, + "eu-central-1|c6id.16xlarge": 3.729600, + "eu-central-1|c6id.24xlarge": 5.594400, + "eu-central-1|c6id.2xlarge": 0.466200, + "eu-central-1|c6id.32xlarge": 7.459200, + "eu-central-1|c6id.4xlarge": 0.932400, + "eu-central-1|c6id.8xlarge": 1.864800, + "eu-central-1|c6id.large": 0.116550, + "eu-central-1|c6id.metal": 7.459200, + "eu-central-1|c6id.xlarge": 0.233100, + "eu-central-1|c6in.12xlarge": 3.099600, + "eu-central-1|c6in.16xlarge": 4.132800, + "eu-central-1|c6in.24xlarge": 6.199200, + "eu-central-1|c6in.2xlarge": 0.516600, + "eu-central-1|c6in.32xlarge": 8.265600, + "eu-central-1|c6in.4xlarge": 1.033200, + "eu-central-1|c6in.8xlarge": 2.066400, + "eu-central-1|c6in.large": 0.129150, + "eu-central-1|c6in.metal": 8.265600, + "eu-central-1|c6in.xlarge": 0.258300, + "eu-central-1|c7a.12xlarge": 2.811120, + "eu-central-1|c7a.16xlarge": 3.748160, + "eu-central-1|c7a.24xlarge": 5.622240, + "eu-central-1|c7a.2xlarge": 0.468520, + "eu-central-1|c7a.32xlarge": 7.496320, + "eu-central-1|c7a.48xlarge": 11.244480, + "eu-central-1|c7a.4xlarge": 0.937040, + "eu-central-1|c7a.8xlarge": 1.874080, + "eu-central-1|c7a.large": 0.117130, + "eu-central-1|c7a.medium": 0.058570, + "eu-central-1|c7a.metal-48xl": 11.244480, + "eu-central-1|c7a.xlarge": 0.234260, + "eu-central-1|c7g.12xlarge": 1.978800, + "eu-central-1|c7g.16xlarge": 2.638400, + "eu-central-1|c7g.2xlarge": 0.329800, + "eu-central-1|c7g.4xlarge": 0.659600, + "eu-central-1|c7g.8xlarge": 1.319200, + "eu-central-1|c7g.large": 0.082500, + "eu-central-1|c7g.medium": 0.041200, + "eu-central-1|c7g.metal": 2.638400, + "eu-central-1|c7g.xlarge": 0.164900, + "eu-central-1|c7gd.12xlarge": 2.517600, + "eu-central-1|c7gd.16xlarge": 3.356800, + "eu-central-1|c7gd.2xlarge": 0.419600, + "eu-central-1|c7gd.4xlarge": 0.839200, + "eu-central-1|c7gd.8xlarge": 1.678400, + "eu-central-1|c7gd.large": 0.104900, + "eu-central-1|c7gd.medium": 0.052500, + "eu-central-1|c7gd.metal": 3.356800, + "eu-central-1|c7gd.xlarge": 0.209800, + "eu-central-1|c7i-flex.12xlarge": 2.322180, + "eu-central-1|c7i-flex.16xlarge": 3.096240, + "eu-central-1|c7i-flex.2xlarge": 0.387030, + "eu-central-1|c7i-flex.4xlarge": 0.774060, + "eu-central-1|c7i-flex.8xlarge": 1.548120, + "eu-central-1|c7i-flex.large": 0.096760, + "eu-central-1|c7i-flex.xlarge": 0.193520, + "eu-central-1|c7i.12xlarge": 2.444400, + "eu-central-1|c7i.16xlarge": 3.259200, + "eu-central-1|c7i.24xlarge": 4.888800, + "eu-central-1|c7i.2xlarge": 0.407400, + "eu-central-1|c7i.48xlarge": 9.777600, + "eu-central-1|c7i.4xlarge": 0.814800, + "eu-central-1|c7i.8xlarge": 1.629600, + "eu-central-1|c7i.large": 0.101850, + "eu-central-1|c7i.metal-24xl": 4.888800, + "eu-central-1|c7i.metal-48xl": 9.777600, + "eu-central-1|c7i.xlarge": 0.203700, + "eu-central-1|c8g.12xlarge": 2.176800, + "eu-central-1|c8g.16xlarge": 2.902400, + "eu-central-1|c8g.24xlarge": 4.353600, + "eu-central-1|c8g.2xlarge": 0.362800, + "eu-central-1|c8g.48xlarge": 8.707200, + "eu-central-1|c8g.4xlarge": 0.725600, + "eu-central-1|c8g.8xlarge": 1.451200, + "eu-central-1|c8g.large": 0.090700, + "eu-central-1|c8g.medium": 0.045350, + "eu-central-1|c8g.metal-24xl": 4.353600, + "eu-central-1|c8g.metal-48xl": 8.707200, + "eu-central-1|c8g.xlarge": 0.181400, + "eu-central-1|c8gd.12xlarge": 2.719200, + "eu-central-1|c8gd.16xlarge": 3.625600, + "eu-central-1|c8gd.24xlarge": 5.438400, + "eu-central-1|c8gd.2xlarge": 0.453200, + "eu-central-1|c8gd.48xlarge": 10.876800, + "eu-central-1|c8gd.4xlarge": 0.906400, + "eu-central-1|c8gd.8xlarge": 1.812800, + "eu-central-1|c8gd.large": 0.113300, + "eu-central-1|c8gd.medium": 0.056650, + "eu-central-1|c8gd.metal-24xl": 5.438400, + "eu-central-1|c8gd.metal-48xl": 10.876800, + "eu-central-1|c8gd.xlarge": 0.226600, + "eu-central-1|c8gn.12xlarge": 3.239000, + "eu-central-1|c8gn.16xlarge": 4.318700, + "eu-central-1|c8gn.24xlarge": 6.478100, + "eu-central-1|c8gn.2xlarge": 0.539800, + "eu-central-1|c8gn.48xlarge": 12.956200, + "eu-central-1|c8gn.4xlarge": 1.079700, + "eu-central-1|c8gn.8xlarge": 2.159400, + "eu-central-1|c8gn.large": 0.135000, + "eu-central-1|c8gn.medium": 0.067500, + "eu-central-1|c8gn.xlarge": 0.269900, + "eu-central-1|d2.2xlarge": 1.588000, + "eu-central-1|d2.4xlarge": 3.176000, + "eu-central-1|d2.8xlarge": 6.352000, + "eu-central-1|d2.xlarge": 0.794000, + "eu-central-1|d3.2xlarge": 1.316000, + "eu-central-1|d3.4xlarge": 2.632000, + "eu-central-1|d3.8xlarge": 5.264480, + "eu-central-1|d3.xlarge": 0.658000, + "eu-central-1|d3en.12xlarge": 8.312280, + "eu-central-1|d3en.2xlarge": 1.385000, + "eu-central-1|d3en.4xlarge": 2.771000, + "eu-central-1|d3en.6xlarge": 4.156000, + "eu-central-1|d3en.8xlarge": 5.541520, + "eu-central-1|d3en.xlarge": 0.693000, + "eu-central-1|dl2q.24xlarge": 11.595200, + "eu-central-1|f1.2xlarge": 1.734000, + "eu-central-1|f1.4xlarge": 3.468000, + "eu-central-1|f2.12xlarge": 4.950000, + "eu-central-1|f2.48xlarge": 19.800000, + "eu-central-1|f2.6xlarge": 2.475000, + "eu-central-1|g2.2xlarge": 0.772000, + "eu-central-1|g2.8xlarge": 3.088000, + "eu-central-1|g3.16xlarge": 5.700000, + "eu-central-1|g3.4xlarge": 1.425000, + "eu-central-1|g3.8xlarge": 2.850000, + "eu-central-1|g3s.xlarge": 0.938000, + "eu-central-1|g4ad.16xlarge": 4.336000, + "eu-central-1|g4ad.2xlarge": 0.676620, + "eu-central-1|g4ad.4xlarge": 1.084000, + "eu-central-1|g4ad.8xlarge": 2.168000, + "eu-central-1|g4ad.xlarge": 0.473270, + "eu-central-1|g4dn.12xlarge": 4.890000, + "eu-central-1|g4dn.16xlarge": 5.440000, + "eu-central-1|g4dn.2xlarge": 0.940000, + "eu-central-1|g4dn.4xlarge": 1.505000, + "eu-central-1|g4dn.8xlarge": 2.720000, + "eu-central-1|g4dn.metal": 9.780000, + "eu-central-1|g4dn.xlarge": 0.658000, + "eu-central-1|g5.12xlarge": 7.092820, + "eu-central-1|g5.16xlarge": 5.122040, + "eu-central-1|g5.24xlarge": 10.184050, + "eu-central-1|g5.2xlarge": 1.515600, + "eu-central-1|g5.48xlarge": 20.368100, + "eu-central-1|g5.4xlarge": 2.030810, + "eu-central-1|g5.8xlarge": 3.061220, + "eu-central-1|g5.xlarge": 1.258000, + "eu-central-1|g5g.16xlarge": 3.432600, + "eu-central-1|g5g.2xlarge": 0.695500, + "eu-central-1|g5g.4xlarge": 1.035800, + "eu-central-1|g5g.8xlarge": 1.716300, + "eu-central-1|g5g.metal": 3.432600, + "eu-central-1|g5g.xlarge": 0.525400, + "eu-central-1|g6.12xlarge": 5.754290, + "eu-central-1|g6.16xlarge": 4.247690, + "eu-central-1|g6.24xlarge": 8.347320, + "eu-central-1|g6.2xlarge": 1.222490, + "eu-central-1|g6.48xlarge": 16.694640, + "eu-central-1|g6.4xlarge": 1.654660, + "eu-central-1|g6.8xlarge": 2.519000, + "eu-central-1|g6.xlarge": 1.006400, + "eu-central-1|g6e.12xlarge": 13.120020, + "eu-central-1|g6e.16xlarge": 9.474540, + "eu-central-1|g6e.24xlarge": 18.838060, + "eu-central-1|g6e.2xlarge": 2.803500, + "eu-central-1|g6e.48xlarge": 37.676120, + "eu-central-1|g6e.4xlarge": 3.756510, + "eu-central-1|g6e.8xlarge": 5.662520, + "eu-central-1|g6e.xlarge": 2.327000, + "eu-central-1|g6f.2xlarge": 0.594000, + "eu-central-1|g6f.4xlarge": 1.188000, + "eu-central-1|g6f.large": 0.252610, + "eu-central-1|g6f.xlarge": 0.297000, + "eu-central-1|gr6.4xlarge": 1.924800, + "eu-central-1|gr6.8xlarge": 3.059270, + "eu-central-1|gr6f.4xlarge": 1.333050, + "eu-central-1|i2.2xlarge": 2.026000, + "eu-central-1|i2.4xlarge": 4.051000, + "eu-central-1|i2.8xlarge": 8.102000, + "eu-central-1|i2.xlarge": 1.013000, + "eu-central-1|i3.16xlarge": 5.952000, + "eu-central-1|i3.2xlarge": 0.744000, + "eu-central-1|i3.4xlarge": 1.488000, + "eu-central-1|i3.8xlarge": 2.976000, + "eu-central-1|i3.large": 0.186000, + "eu-central-1|i3.metal": 5.952000, + "eu-central-1|i3.xlarge": 0.372000, + "eu-central-1|i3en.12xlarge": 6.480000, + "eu-central-1|i3en.24xlarge": 12.960000, + "eu-central-1|i3en.2xlarge": 1.080000, + "eu-central-1|i3en.3xlarge": 1.620000, + "eu-central-1|i3en.6xlarge": 3.240000, + "eu-central-1|i3en.large": 0.270000, + "eu-central-1|i3en.metal": 12.960000, + "eu-central-1|i3en.xlarge": 0.540000, + "eu-central-1|i4i.12xlarge": 4.910000, + "eu-central-1|i4i.16xlarge": 6.547000, + "eu-central-1|i4i.24xlarge": 9.820800, + "eu-central-1|i4i.2xlarge": 0.818000, + "eu-central-1|i4i.32xlarge": 13.094400, + "eu-central-1|i4i.4xlarge": 1.637000, + "eu-central-1|i4i.8xlarge": 3.274000, + "eu-central-1|i4i.large": 0.205000, + "eu-central-1|i4i.metal": 13.094000, + "eu-central-1|i4i.xlarge": 0.409000, + "eu-central-1|i7i.12xlarge": 5.401400, + "eu-central-1|i7i.16xlarge": 7.201900, + "eu-central-1|i7i.24xlarge": 10.802900, + "eu-central-1|i7i.2xlarge": 0.900200, + "eu-central-1|i7i.48xlarge": 21.605800, + "eu-central-1|i7i.4xlarge": 1.800500, + "eu-central-1|i7i.8xlarge": 3.601000, + "eu-central-1|i7i.large": 0.225100, + "eu-central-1|i7i.metal-24xl": 10.802900, + "eu-central-1|i7i.metal-48xl": 21.605800, + "eu-central-1|i7i.xlarge": 0.450100, + "eu-central-1|i7ie.12xlarge": 7.452000, + "eu-central-1|i7ie.18xlarge": 11.178000, + "eu-central-1|i7ie.24xlarge": 14.904000, + "eu-central-1|i7ie.2xlarge": 1.242000, + "eu-central-1|i7ie.3xlarge": 1.863000, + "eu-central-1|i7ie.48xlarge": 29.808000, + "eu-central-1|i7ie.6xlarge": 3.726000, + "eu-central-1|i7ie.large": 0.310500, + "eu-central-1|i7ie.metal-24xl": 14.904000, + "eu-central-1|i7ie.metal-48xl": 29.808000, + "eu-central-1|i7ie.xlarge": 0.621000, + "eu-central-1|i8g.12xlarge": 4.910400, + "eu-central-1|i8g.16xlarge": 6.547200, + "eu-central-1|i8g.24xlarge": 9.820800, + "eu-central-1|i8g.2xlarge": 0.818400, + "eu-central-1|i8g.4xlarge": 1.636800, + "eu-central-1|i8g.8xlarge": 3.273600, + "eu-central-1|i8g.large": 0.204600, + "eu-central-1|i8g.metal-24xl": 9.820800, + "eu-central-1|i8g.xlarge": 0.409200, + "eu-central-1|i8ge.12xlarge": 6.804000, + "eu-central-1|i8ge.18xlarge": 10.206000, + "eu-central-1|i8ge.24xlarge": 13.608000, + "eu-central-1|i8ge.2xlarge": 1.134000, + "eu-central-1|i8ge.3xlarge": 1.701000, + "eu-central-1|i8ge.48xlarge": 27.216000, + "eu-central-1|i8ge.6xlarge": 3.402000, + "eu-central-1|i8ge.large": 0.283500, + "eu-central-1|i8ge.metal-24xl": 13.608000, + "eu-central-1|i8ge.metal-48xl": 27.216000, + "eu-central-1|i8ge.xlarge": 0.567000, + "eu-central-1|im4gn.16xlarge": 6.940030, + "eu-central-1|im4gn.2xlarge": 0.867500, + "eu-central-1|im4gn.4xlarge": 1.735010, + "eu-central-1|im4gn.8xlarge": 3.470020, + "eu-central-1|im4gn.large": 0.216880, + "eu-central-1|im4gn.xlarge": 0.433750, + "eu-central-1|inf1.24xlarge": 5.902000, + "eu-central-1|inf1.2xlarge": 0.453000, + "eu-central-1|inf1.6xlarge": 1.475000, + "eu-central-1|inf1.xlarge": 0.285000, + "eu-central-1|inf2.24xlarge": 9.735950, + "eu-central-1|inf2.48xlarge": 19.471900, + "eu-central-1|inf2.8xlarge": 2.951790, + "eu-central-1|inf2.xlarge": 1.137300, + "eu-central-1|is4gen.2xlarge": 1.377000, + "eu-central-1|is4gen.4xlarge": 2.754000, + "eu-central-1|is4gen.8xlarge": 5.508000, + "eu-central-1|is4gen.large": 0.344250, + "eu-central-1|is4gen.medium": 0.172130, + "eu-central-1|is4gen.xlarge": 0.688500, + "eu-central-1|m3.2xlarge": 0.632000, + "eu-central-1|m3.large": 0.158000, + "eu-central-1|m3.medium": 0.079000, + "eu-central-1|m3.xlarge": 0.315000, + "eu-central-1|m4.10xlarge": 2.400000, + "eu-central-1|m4.16xlarge": 3.840000, + "eu-central-1|m4.2xlarge": 0.480000, + "eu-central-1|m4.4xlarge": 0.960000, + "eu-central-1|m4.large": 0.120000, + "eu-central-1|m4.xlarge": 0.240000, + "eu-central-1|m5.12xlarge": 2.760000, + "eu-central-1|m5.16xlarge": 3.680000, + "eu-central-1|m5.24xlarge": 5.520000, + "eu-central-1|m5.2xlarge": 0.460000, + "eu-central-1|m5.4xlarge": 0.920000, + "eu-central-1|m5.8xlarge": 1.840000, + "eu-central-1|m5.large": 0.115000, + "eu-central-1|m5.metal": 5.520000, + "eu-central-1|m5.xlarge": 0.230000, + "eu-central-1|m5a.12xlarge": 2.496000, + "eu-central-1|m5a.16xlarge": 3.328000, + "eu-central-1|m5a.24xlarge": 4.992000, + "eu-central-1|m5a.2xlarge": 0.416000, + "eu-central-1|m5a.4xlarge": 0.832000, + "eu-central-1|m5a.8xlarge": 1.664000, + "eu-central-1|m5a.large": 0.104000, + "eu-central-1|m5a.xlarge": 0.208000, + "eu-central-1|m5ad.12xlarge": 3.000000, + "eu-central-1|m5ad.16xlarge": 4.000000, + "eu-central-1|m5ad.24xlarge": 6.000000, + "eu-central-1|m5ad.2xlarge": 0.500000, + "eu-central-1|m5ad.4xlarge": 1.000000, + "eu-central-1|m5ad.8xlarge": 2.000000, + "eu-central-1|m5ad.large": 0.125000, + "eu-central-1|m5ad.xlarge": 0.250000, + "eu-central-1|m5d.12xlarge": 3.264000, + "eu-central-1|m5d.16xlarge": 4.352000, + "eu-central-1|m5d.24xlarge": 6.528000, + "eu-central-1|m5d.2xlarge": 0.544000, + "eu-central-1|m5d.4xlarge": 1.088000, + "eu-central-1|m5d.8xlarge": 2.176000, + "eu-central-1|m5d.large": 0.136000, + "eu-central-1|m5d.metal": 6.528000, + "eu-central-1|m5d.xlarge": 0.272000, + "eu-central-1|m5dn.12xlarge": 3.888000, + "eu-central-1|m5dn.16xlarge": 5.184000, + "eu-central-1|m5dn.24xlarge": 7.776000, + "eu-central-1|m5dn.2xlarge": 0.648000, + "eu-central-1|m5dn.4xlarge": 1.296000, + "eu-central-1|m5dn.8xlarge": 2.592000, + "eu-central-1|m5dn.large": 0.162000, + "eu-central-1|m5dn.metal": 7.776000, + "eu-central-1|m5dn.xlarge": 0.324000, + "eu-central-1|m5n.12xlarge": 3.384000, + "eu-central-1|m5n.16xlarge": 4.512000, + "eu-central-1|m5n.24xlarge": 6.768000, + "eu-central-1|m5n.2xlarge": 0.564000, + "eu-central-1|m5n.4xlarge": 1.128000, + "eu-central-1|m5n.8xlarge": 2.256000, + "eu-central-1|m5n.large": 0.141000, + "eu-central-1|m5n.metal": 6.768000, + "eu-central-1|m5n.xlarge": 0.282000, + "eu-central-1|m5zn.12xlarge": 4.748600, + "eu-central-1|m5zn.2xlarge": 0.791400, + "eu-central-1|m5zn.3xlarge": 1.187200, + "eu-central-1|m5zn.6xlarge": 2.374300, + "eu-central-1|m5zn.large": 0.197900, + "eu-central-1|m5zn.metal": 4.748600, + "eu-central-1|m5zn.xlarge": 0.395700, + "eu-central-1|m6a.12xlarge": 2.484000, + "eu-central-1|m6a.16xlarge": 3.312000, + "eu-central-1|m6a.24xlarge": 4.968000, + "eu-central-1|m6a.2xlarge": 0.414000, + "eu-central-1|m6a.32xlarge": 6.624000, + "eu-central-1|m6a.48xlarge": 9.936000, + "eu-central-1|m6a.4xlarge": 0.828000, + "eu-central-1|m6a.8xlarge": 1.656000, + "eu-central-1|m6a.large": 0.103500, + "eu-central-1|m6a.metal": 9.936000, + "eu-central-1|m6a.xlarge": 0.207000, + "eu-central-1|m6g.12xlarge": 2.208000, + "eu-central-1|m6g.16xlarge": 2.944000, + "eu-central-1|m6g.2xlarge": 0.368000, + "eu-central-1|m6g.4xlarge": 0.736000, + "eu-central-1|m6g.8xlarge": 1.472000, + "eu-central-1|m6g.large": 0.092000, + "eu-central-1|m6g.medium": 0.046000, + "eu-central-1|m6g.metal": 2.944000, + "eu-central-1|m6g.xlarge": 0.184000, + "eu-central-1|m6gd.12xlarge": 2.616000, + "eu-central-1|m6gd.16xlarge": 3.488000, + "eu-central-1|m6gd.2xlarge": 0.436000, + "eu-central-1|m6gd.4xlarge": 0.872000, + "eu-central-1|m6gd.8xlarge": 1.744000, + "eu-central-1|m6gd.large": 0.109000, + "eu-central-1|m6gd.medium": 0.054500, + "eu-central-1|m6gd.metal": 3.488000, + "eu-central-1|m6gd.xlarge": 0.218000, + "eu-central-1|m6i.12xlarge": 2.760000, + "eu-central-1|m6i.16xlarge": 3.680000, + "eu-central-1|m6i.24xlarge": 5.520000, + "eu-central-1|m6i.2xlarge": 0.460000, + "eu-central-1|m6i.32xlarge": 7.360000, + "eu-central-1|m6i.4xlarge": 0.920000, + "eu-central-1|m6i.8xlarge": 1.840000, + "eu-central-1|m6i.large": 0.115000, + "eu-central-1|m6i.metal": 7.360000, + "eu-central-1|m6i.xlarge": 0.230000, + "eu-central-1|m6id.12xlarge": 3.427200, + "eu-central-1|m6id.16xlarge": 4.569600, + "eu-central-1|m6id.24xlarge": 6.854400, + "eu-central-1|m6id.2xlarge": 0.571200, + "eu-central-1|m6id.32xlarge": 9.139200, + "eu-central-1|m6id.4xlarge": 1.142400, + "eu-central-1|m6id.8xlarge": 2.284800, + "eu-central-1|m6id.large": 0.142800, + "eu-central-1|m6id.metal": 9.139200, + "eu-central-1|m6id.xlarge": 0.285600, + "eu-central-1|m6idn.12xlarge": 4.548960, + "eu-central-1|m6idn.16xlarge": 6.065280, + "eu-central-1|m6idn.24xlarge": 9.097920, + "eu-central-1|m6idn.2xlarge": 0.758160, + "eu-central-1|m6idn.32xlarge": 12.130560, + "eu-central-1|m6idn.4xlarge": 1.516320, + "eu-central-1|m6idn.8xlarge": 3.032640, + "eu-central-1|m6idn.large": 0.189540, + "eu-central-1|m6idn.metal": 12.130560, + "eu-central-1|m6idn.xlarge": 0.379080, + "eu-central-1|m6in.12xlarge": 3.959280, + "eu-central-1|m6in.16xlarge": 5.279040, + "eu-central-1|m6in.24xlarge": 7.918560, + "eu-central-1|m6in.2xlarge": 0.659880, + "eu-central-1|m6in.32xlarge": 10.558080, + "eu-central-1|m6in.4xlarge": 1.319760, + "eu-central-1|m6in.8xlarge": 2.639520, + "eu-central-1|m6in.large": 0.164970, + "eu-central-1|m6in.metal": 10.558080, + "eu-central-1|m6in.xlarge": 0.329940, + "eu-central-1|m7a.12xlarge": 3.332640, + "eu-central-1|m7a.16xlarge": 4.443520, + "eu-central-1|m7a.24xlarge": 6.665280, + "eu-central-1|m7a.2xlarge": 0.555440, + "eu-central-1|m7a.32xlarge": 8.887040, + "eu-central-1|m7a.48xlarge": 13.330560, + "eu-central-1|m7a.4xlarge": 1.110880, + "eu-central-1|m7a.8xlarge": 2.221760, + "eu-central-1|m7a.large": 0.138860, + "eu-central-1|m7a.medium": 0.069430, + "eu-central-1|m7a.metal-48xl": 13.330560, + "eu-central-1|m7a.xlarge": 0.277720, + "eu-central-1|m7g.12xlarge": 2.346200, + "eu-central-1|m7g.16xlarge": 3.128300, + "eu-central-1|m7g.2xlarge": 0.391000, + "eu-central-1|m7g.4xlarge": 0.782100, + "eu-central-1|m7g.8xlarge": 1.564200, + "eu-central-1|m7g.large": 0.097800, + "eu-central-1|m7g.medium": 0.048900, + "eu-central-1|m7g.metal": 3.128300, + "eu-central-1|m7g.xlarge": 0.195500, + "eu-central-1|m7gd.12xlarge": 3.084500, + "eu-central-1|m7gd.16xlarge": 4.112600, + "eu-central-1|m7gd.2xlarge": 0.514100, + "eu-central-1|m7gd.4xlarge": 1.028200, + "eu-central-1|m7gd.8xlarge": 2.056300, + "eu-central-1|m7gd.large": 0.128500, + "eu-central-1|m7gd.medium": 0.064300, + "eu-central-1|m7gd.metal": 4.112600, + "eu-central-1|m7gd.xlarge": 0.257000, + "eu-central-1|m7i-flex.12xlarge": 2.753040, + "eu-central-1|m7i-flex.16xlarge": 3.670720, + "eu-central-1|m7i-flex.2xlarge": 0.458840, + "eu-central-1|m7i-flex.4xlarge": 0.917680, + "eu-central-1|m7i-flex.8xlarge": 1.835360, + "eu-central-1|m7i-flex.large": 0.114710, + "eu-central-1|m7i-flex.xlarge": 0.229420, + "eu-central-1|m7i.12xlarge": 2.898000, + "eu-central-1|m7i.16xlarge": 3.864000, + "eu-central-1|m7i.24xlarge": 5.796000, + "eu-central-1|m7i.2xlarge": 0.483000, + "eu-central-1|m7i.48xlarge": 11.592000, + "eu-central-1|m7i.4xlarge": 0.966000, + "eu-central-1|m7i.8xlarge": 1.932000, + "eu-central-1|m7i.large": 0.120750, + "eu-central-1|m7i.metal-24xl": 5.796000, + "eu-central-1|m7i.metal-48xl": 11.592000, + "eu-central-1|m7i.xlarge": 0.241500, + "eu-central-1|m8g.12xlarge": 2.580960, + "eu-central-1|m8g.16xlarge": 3.441280, + "eu-central-1|m8g.24xlarge": 5.161920, + "eu-central-1|m8g.2xlarge": 0.430160, + "eu-central-1|m8g.48xlarge": 10.323840, + "eu-central-1|m8g.4xlarge": 0.860320, + "eu-central-1|m8g.8xlarge": 1.720640, + "eu-central-1|m8g.large": 0.107540, + "eu-central-1|m8g.medium": 0.053770, + "eu-central-1|m8g.metal-24xl": 5.161920, + "eu-central-1|m8g.metal-48xl": 10.323840, + "eu-central-1|m8g.xlarge": 0.215080, + "eu-central-1|m8gd.12xlarge": 3.331200, + "eu-central-1|m8gd.16xlarge": 4.441600, + "eu-central-1|m8gd.24xlarge": 6.662400, + "eu-central-1|m8gd.2xlarge": 0.555200, + "eu-central-1|m8gd.48xlarge": 13.324800, + "eu-central-1|m8gd.4xlarge": 1.110400, + "eu-central-1|m8gd.8xlarge": 2.220800, + "eu-central-1|m8gd.large": 0.138800, + "eu-central-1|m8gd.medium": 0.069400, + "eu-central-1|m8gd.metal-24xl": 6.662400, + "eu-central-1|m8gd.metal-48xl": 13.324800, + "eu-central-1|m8gd.xlarge": 0.277600, + "eu-central-1|m8i.12xlarge": 3.042960, + "eu-central-1|m8i.16xlarge": 4.057280, + "eu-central-1|m8i.24xlarge": 6.085920, + "eu-central-1|m8i.2xlarge": 0.507160, + "eu-central-1|m8i.32xlarge": 8.114560, + "eu-central-1|m8i.48xlarge": 12.171840, + "eu-central-1|m8i.4xlarge": 1.014320, + "eu-central-1|m8i.8xlarge": 2.028640, + "eu-central-1|m8i.96xlarge": 24.343680, + "eu-central-1|m8i.large": 0.126790, + "eu-central-1|m8i.metal-48xl": 12.171840, + "eu-central-1|m8i.metal-96xl": 24.343680, + "eu-central-1|m8i.xlarge": 0.253580, + "eu-central-1|p2.16xlarge": 21.216000, + "eu-central-1|p2.8xlarge": 10.608000, + "eu-central-1|p2.xlarge": 1.326000, + "eu-central-1|p3.16xlarge": 30.584000, + "eu-central-1|p3.2xlarge": 3.823000, + "eu-central-1|p3.8xlarge": 15.292000, + "eu-central-1|p4d.24xlarge": 27.432980, + "eu-central-1|p4de.24xlarge": 34.291220, + "eu-central-1|r3.2xlarge": 0.800000, + "eu-central-1|r3.4xlarge": 1.600000, + "eu-central-1|r3.8xlarge": 3.201000, + "eu-central-1|r3.large": 0.200000, + "eu-central-1|r3.xlarge": 0.400000, + "eu-central-1|r4.16xlarge": 5.121600, + "eu-central-1|r4.2xlarge": 0.640200, + "eu-central-1|r4.4xlarge": 1.280400, + "eu-central-1|r4.8xlarge": 2.560800, + "eu-central-1|r4.large": 0.160050, + "eu-central-1|r4.xlarge": 0.320100, + "eu-central-1|r5.12xlarge": 3.648000, + "eu-central-1|r5.16xlarge": 4.864000, + "eu-central-1|r5.24xlarge": 7.296000, + "eu-central-1|r5.2xlarge": 0.608000, + "eu-central-1|r5.4xlarge": 1.216000, + "eu-central-1|r5.8xlarge": 2.432000, + "eu-central-1|r5.large": 0.152000, + "eu-central-1|r5.metal": 7.296000, + "eu-central-1|r5.xlarge": 0.304000, + "eu-central-1|r5a.12xlarge": 3.288000, + "eu-central-1|r5a.16xlarge": 4.384000, + "eu-central-1|r5a.24xlarge": 6.576000, + "eu-central-1|r5a.2xlarge": 0.548000, + "eu-central-1|r5a.4xlarge": 1.096000, + "eu-central-1|r5a.8xlarge": 2.192000, + "eu-central-1|r5a.large": 0.137000, + "eu-central-1|r5a.xlarge": 0.274000, + "eu-central-1|r5ad.12xlarge": 3.792000, + "eu-central-1|r5ad.16xlarge": 5.056000, + "eu-central-1|r5ad.24xlarge": 7.584000, + "eu-central-1|r5ad.2xlarge": 0.632000, + "eu-central-1|r5ad.4xlarge": 1.264000, + "eu-central-1|r5ad.8xlarge": 2.528000, + "eu-central-1|r5ad.large": 0.158000, + "eu-central-1|r5ad.xlarge": 0.316000, + "eu-central-1|r5b.12xlarge": 4.272000, + "eu-central-1|r5b.16xlarge": 5.696000, + "eu-central-1|r5b.24xlarge": 8.544000, + "eu-central-1|r5b.2xlarge": 0.712000, + "eu-central-1|r5b.4xlarge": 1.424000, + "eu-central-1|r5b.8xlarge": 2.848000, + "eu-central-1|r5b.large": 0.178000, + "eu-central-1|r5b.metal": 8.544000, + "eu-central-1|r5b.xlarge": 0.356000, + "eu-central-1|r5d.12xlarge": 4.152000, + "eu-central-1|r5d.16xlarge": 5.536000, + "eu-central-1|r5d.24xlarge": 8.304000, + "eu-central-1|r5d.2xlarge": 0.692000, + "eu-central-1|r5d.4xlarge": 1.384000, + "eu-central-1|r5d.8xlarge": 2.768000, + "eu-central-1|r5d.large": 0.173000, + "eu-central-1|r5d.metal": 8.304000, + "eu-central-1|r5d.xlarge": 0.346000, + "eu-central-1|r5dn.12xlarge": 4.776000, + "eu-central-1|r5dn.16xlarge": 6.368000, + "eu-central-1|r5dn.24xlarge": 9.552000, + "eu-central-1|r5dn.2xlarge": 0.796000, + "eu-central-1|r5dn.4xlarge": 1.592000, + "eu-central-1|r5dn.8xlarge": 3.184000, + "eu-central-1|r5dn.large": 0.199000, + "eu-central-1|r5dn.metal": 9.552000, + "eu-central-1|r5dn.xlarge": 0.398000, + "eu-central-1|r5n.12xlarge": 4.272000, + "eu-central-1|r5n.16xlarge": 5.696000, + "eu-central-1|r5n.24xlarge": 8.544000, + "eu-central-1|r5n.2xlarge": 0.712000, + "eu-central-1|r5n.4xlarge": 1.424000, + "eu-central-1|r5n.8xlarge": 2.848000, + "eu-central-1|r5n.large": 0.178000, + "eu-central-1|r5n.metal": 8.544000, + "eu-central-1|r5n.xlarge": 0.356000, + "eu-central-1|r6a.12xlarge": 3.283200, + "eu-central-1|r6a.16xlarge": 4.377600, + "eu-central-1|r6a.24xlarge": 6.566400, + "eu-central-1|r6a.2xlarge": 0.547200, + "eu-central-1|r6a.32xlarge": 8.755200, + "eu-central-1|r6a.48xlarge": 13.132800, + "eu-central-1|r6a.4xlarge": 1.094400, + "eu-central-1|r6a.8xlarge": 2.188800, + "eu-central-1|r6a.large": 0.136800, + "eu-central-1|r6a.metal": 13.132800, + "eu-central-1|r6a.xlarge": 0.273600, + "eu-central-1|r6g.12xlarge": 2.918400, + "eu-central-1|r6g.16xlarge": 3.891200, + "eu-central-1|r6g.2xlarge": 0.486400, + "eu-central-1|r6g.4xlarge": 0.972800, + "eu-central-1|r6g.8xlarge": 1.945600, + "eu-central-1|r6g.large": 0.121600, + "eu-central-1|r6g.medium": 0.060800, + "eu-central-1|r6g.metal": 3.891200, + "eu-central-1|r6g.xlarge": 0.243200, + "eu-central-1|r6gd.12xlarge": 3.312000, + "eu-central-1|r6gd.16xlarge": 4.416000, + "eu-central-1|r6gd.2xlarge": 0.552000, + "eu-central-1|r6gd.4xlarge": 1.104000, + "eu-central-1|r6gd.8xlarge": 2.208000, + "eu-central-1|r6gd.large": 0.138000, + "eu-central-1|r6gd.medium": 0.069000, + "eu-central-1|r6gd.metal": 4.416000, + "eu-central-1|r6gd.xlarge": 0.276000, + "eu-central-1|r6i.12xlarge": 3.648000, + "eu-central-1|r6i.16xlarge": 4.864000, + "eu-central-1|r6i.24xlarge": 7.296000, + "eu-central-1|r6i.2xlarge": 0.608000, + "eu-central-1|r6i.32xlarge": 9.728000, + "eu-central-1|r6i.4xlarge": 1.216000, + "eu-central-1|r6i.8xlarge": 2.432000, + "eu-central-1|r6i.large": 0.152000, + "eu-central-1|r6i.metal": 9.728000, + "eu-central-1|r6i.xlarge": 0.304000, + "eu-central-1|r6id.12xlarge": 4.359600, + "eu-central-1|r6id.16xlarge": 5.812800, + "eu-central-1|r6id.24xlarge": 8.719200, + "eu-central-1|r6id.2xlarge": 0.726600, + "eu-central-1|r6id.32xlarge": 11.625600, + "eu-central-1|r6id.4xlarge": 1.453200, + "eu-central-1|r6id.8xlarge": 2.906400, + "eu-central-1|r6id.large": 0.181650, + "eu-central-1|r6id.metal": 11.625600, + "eu-central-1|r6id.xlarge": 0.363300, + "eu-central-1|r6idn.12xlarge": 5.587920, + "eu-central-1|r6idn.16xlarge": 7.450560, + "eu-central-1|r6idn.24xlarge": 11.175840, + "eu-central-1|r6idn.2xlarge": 0.931320, + "eu-central-1|r6idn.32xlarge": 14.901120, + "eu-central-1|r6idn.4xlarge": 1.862640, + "eu-central-1|r6idn.8xlarge": 3.725280, + "eu-central-1|r6idn.large": 0.232830, + "eu-central-1|r6idn.metal": 14.901120, + "eu-central-1|r6idn.xlarge": 0.465660, + "eu-central-1|r6in.12xlarge": 4.998240, + "eu-central-1|r6in.16xlarge": 6.664320, + "eu-central-1|r6in.24xlarge": 9.996480, + "eu-central-1|r6in.2xlarge": 0.833040, + "eu-central-1|r6in.32xlarge": 13.328640, + "eu-central-1|r6in.4xlarge": 1.666080, + "eu-central-1|r6in.8xlarge": 3.332160, + "eu-central-1|r6in.large": 0.208260, + "eu-central-1|r6in.metal": 13.328640, + "eu-central-1|r6in.xlarge": 0.416520, + "eu-central-1|r7a.12xlarge": 4.404960, + "eu-central-1|r7a.16xlarge": 5.873280, + "eu-central-1|r7a.24xlarge": 8.809920, + "eu-central-1|r7a.2xlarge": 0.734160, + "eu-central-1|r7a.32xlarge": 11.746560, + "eu-central-1|r7a.48xlarge": 17.619840, + "eu-central-1|r7a.4xlarge": 1.468320, + "eu-central-1|r7a.8xlarge": 2.936640, + "eu-central-1|r7a.large": 0.183540, + "eu-central-1|r7a.medium": 0.091770, + "eu-central-1|r7a.metal-48xl": 17.619840, + "eu-central-1|r7a.xlarge": 0.367080, + "eu-central-1|r7g.12xlarge": 3.100800, + "eu-central-1|r7g.16xlarge": 4.134400, + "eu-central-1|r7g.2xlarge": 0.516800, + "eu-central-1|r7g.4xlarge": 1.033600, + "eu-central-1|r7g.8xlarge": 2.067200, + "eu-central-1|r7g.large": 0.129200, + "eu-central-1|r7g.medium": 0.064600, + "eu-central-1|r7g.metal": 4.134400, + "eu-central-1|r7g.xlarge": 0.258400, + "eu-central-1|r7gd.12xlarge": 3.923600, + "eu-central-1|r7gd.16xlarge": 5.231500, + "eu-central-1|r7gd.2xlarge": 0.653900, + "eu-central-1|r7gd.4xlarge": 1.307900, + "eu-central-1|r7gd.8xlarge": 2.615800, + "eu-central-1|r7gd.large": 0.163500, + "eu-central-1|r7gd.medium": 0.081700, + "eu-central-1|r7gd.metal": 5.231500, + "eu-central-1|r7gd.xlarge": 0.327000, + "eu-central-1|r7i.12xlarge": 3.830400, + "eu-central-1|r7i.16xlarge": 5.107200, + "eu-central-1|r7i.24xlarge": 7.660800, + "eu-central-1|r7i.2xlarge": 0.638400, + "eu-central-1|r7i.48xlarge": 15.321600, + "eu-central-1|r7i.4xlarge": 1.276800, + "eu-central-1|r7i.8xlarge": 2.553600, + "eu-central-1|r7i.large": 0.159600, + "eu-central-1|r7i.metal-24xl": 7.660800, + "eu-central-1|r7i.metal-48xl": 15.321600, + "eu-central-1|r7i.xlarge": 0.319200, + "eu-central-1|r7iz.12xlarge": 5.400000, + "eu-central-1|r7iz.16xlarge": 7.200000, + "eu-central-1|r7iz.2xlarge": 0.900000, + "eu-central-1|r7iz.32xlarge": 14.400000, + "eu-central-1|r7iz.4xlarge": 1.800000, + "eu-central-1|r7iz.8xlarge": 3.600000, + "eu-central-1|r7iz.large": 0.225000, + "eu-central-1|r7iz.metal-16xl": 7.200000, + "eu-central-1|r7iz.metal-32xl": 14.400000, + "eu-central-1|r7iz.xlarge": 0.450000, + "eu-central-1|r8g.12xlarge": 3.410880, + "eu-central-1|r8g.16xlarge": 4.547840, + "eu-central-1|r8g.24xlarge": 6.821760, + "eu-central-1|r8g.2xlarge": 0.568480, + "eu-central-1|r8g.48xlarge": 13.643520, + "eu-central-1|r8g.4xlarge": 1.136960, + "eu-central-1|r8g.8xlarge": 2.273920, + "eu-central-1|r8g.large": 0.142120, + "eu-central-1|r8g.medium": 0.071060, + "eu-central-1|r8g.metal-24xl": 6.821760, + "eu-central-1|r8g.metal-48xl": 13.643520, + "eu-central-1|r8g.xlarge": 0.284240, + "eu-central-1|r8gd.12xlarge": 4.237440, + "eu-central-1|r8gd.16xlarge": 5.649920, + "eu-central-1|r8gd.24xlarge": 8.474880, + "eu-central-1|r8gd.2xlarge": 0.706240, + "eu-central-1|r8gd.48xlarge": 16.949760, + "eu-central-1|r8gd.4xlarge": 1.412480, + "eu-central-1|r8gd.8xlarge": 2.824960, + "eu-central-1|r8gd.large": 0.176560, + "eu-central-1|r8gd.medium": 0.088280, + "eu-central-1|r8gd.metal-24xl": 8.474880, + "eu-central-1|r8gd.metal-48xl": 16.949760, + "eu-central-1|r8gd.xlarge": 0.353120, + "eu-central-1|r8i-flex.12xlarge": 3.820800, + "eu-central-1|r8i-flex.16xlarge": 5.094400, + "eu-central-1|r8i-flex.2xlarge": 0.636800, + "eu-central-1|r8i-flex.4xlarge": 1.273600, + "eu-central-1|r8i-flex.8xlarge": 2.547200, + "eu-central-1|r8i-flex.large": 0.159200, + "eu-central-1|r8i-flex.xlarge": 0.318400, + "eu-central-1|r8i.12xlarge": 4.021920, + "eu-central-1|r8i.16xlarge": 5.362560, + "eu-central-1|r8i.24xlarge": 8.043840, + "eu-central-1|r8i.2xlarge": 0.670320, + "eu-central-1|r8i.32xlarge": 10.725120, + "eu-central-1|r8i.48xlarge": 16.087680, + "eu-central-1|r8i.4xlarge": 1.340640, + "eu-central-1|r8i.8xlarge": 2.681280, + "eu-central-1|r8i.96xlarge": 32.175360, + "eu-central-1|r8i.large": 0.167580, + "eu-central-1|r8i.metal-48xl": 16.087680, + "eu-central-1|r8i.metal-96xl": 32.175360, + "eu-central-1|r8i.xlarge": 0.335160, + "eu-central-1|t2.2xlarge": 0.428800, + "eu-central-1|t2.large": 0.107200, + "eu-central-1|t2.medium": 0.053600, + "eu-central-1|t2.micro": 0.013400, + "eu-central-1|t2.nano": 0.006700, + "eu-central-1|t2.small": 0.026800, + "eu-central-1|t2.xlarge": 0.214400, + "eu-central-1|t3.2xlarge": 0.384000, + "eu-central-1|t3.large": 0.096000, + "eu-central-1|t3.medium": 0.048000, + "eu-central-1|t3.micro": 0.012000, + "eu-central-1|t3.nano": 0.006000, + "eu-central-1|t3.small": 0.024000, + "eu-central-1|t3.xlarge": 0.192000, + "eu-central-1|t3a.2xlarge": 0.345600, + "eu-central-1|t3a.large": 0.086400, + "eu-central-1|t3a.medium": 0.043200, + "eu-central-1|t3a.micro": 0.010800, + "eu-central-1|t3a.nano": 0.005400, + "eu-central-1|t3a.small": 0.021600, + "eu-central-1|t3a.xlarge": 0.172800, + "eu-central-1|t4g.2xlarge": 0.307200, + "eu-central-1|t4g.large": 0.076800, + "eu-central-1|t4g.medium": 0.038400, + "eu-central-1|t4g.micro": 0.009600, + "eu-central-1|t4g.nano": 0.004800, + "eu-central-1|t4g.small": 0.019200, + "eu-central-1|t4g.xlarge": 0.153600, + "eu-central-1|u-12tb1.112xlarge": 131.733000, + "eu-central-1|u-18tb1.112xlarge": 197.600000, + "eu-central-1|u-3tb1.56xlarge": 32.933500, + "eu-central-1|u-6tb1.112xlarge": 65.867000, + "eu-central-1|u-6tb1.56xlarge": 55.979600, + "eu-central-1|u-9tb1.112xlarge": 98.800000, + "eu-central-1|u7i-12tb.224xlarge": 151.497590, + "eu-central-1|u7i-6tb.112xlarge": 75.747050, + "eu-central-1|u7i-8tb.112xlarge": 100.995550, + "eu-central-1|u7in-16tb.224xlarge": 217.716570, + "eu-central-1|u7in-24tb.224xlarge": 326.600600, + "eu-central-1|x1.16xlarge": 9.337000, + "eu-central-1|x1.32xlarge": 18.674000, + "eu-central-1|x1e.16xlarge": 18.672000, + "eu-central-1|x1e.2xlarge": 2.334000, + "eu-central-1|x1e.32xlarge": 37.344000, + "eu-central-1|x1e.4xlarge": 4.668000, + "eu-central-1|x1e.8xlarge": 9.336000, + "eu-central-1|x1e.xlarge": 1.167000, + "eu-central-1|x2idn.16xlarge": 9.337000, + "eu-central-1|x2idn.24xlarge": 14.005500, + "eu-central-1|x2idn.32xlarge": 18.674000, + "eu-central-1|x2idn.metal": 18.674000, + "eu-central-1|x2iedn.16xlarge": 18.674000, + "eu-central-1|x2iedn.24xlarge": 28.011000, + "eu-central-1|x2iedn.2xlarge": 2.334250, + "eu-central-1|x2iedn.32xlarge": 37.348000, + "eu-central-1|x2iedn.4xlarge": 4.668500, + "eu-central-1|x2iedn.8xlarge": 9.337000, + "eu-central-1|x2iedn.metal": 37.348000, + "eu-central-1|x2iedn.xlarge": 1.167130, + "eu-central-1|x8g.12xlarge": 6.554400, + "eu-central-1|x8g.16xlarge": 8.739200, + "eu-central-1|x8g.24xlarge": 13.108800, + "eu-central-1|x8g.2xlarge": 1.092400, + "eu-central-1|x8g.48xlarge": 26.217600, + "eu-central-1|x8g.4xlarge": 2.184800, + "eu-central-1|x8g.8xlarge": 4.369600, + "eu-central-1|x8g.large": 0.273100, + "eu-central-1|x8g.medium": 0.136550, + "eu-central-1|x8g.metal-24xl": 13.108800, + "eu-central-1|x8g.metal-48xl": 26.217600, + "eu-central-1|x8g.xlarge": 0.546200, + "eu-central-1|z1d.12xlarge": 5.400000, + "eu-central-1|z1d.2xlarge": 0.900000, + "eu-central-1|z1d.3xlarge": 1.350000, + "eu-central-1|z1d.6xlarge": 2.700000, + "eu-central-1|z1d.large": 0.225000, + "eu-central-1|z1d.metal": 5.400000, + "eu-central-1|z1d.xlarge": 0.450000, + "eu-north-1|c5.12xlarge": 2.184000, + "eu-north-1|c5.18xlarge": 3.276000, + "eu-north-1|c5.24xlarge": 4.368000, + "eu-north-1|c5.2xlarge": 0.364000, + "eu-north-1|c5.4xlarge": 0.728000, + "eu-north-1|c5.9xlarge": 1.638000, + "eu-north-1|c5.large": 0.091000, + "eu-north-1|c5.metal": 4.368000, + "eu-north-1|c5.xlarge": 0.182000, + "eu-north-1|c5a.12xlarge": 1.968000, + "eu-north-1|c5a.16xlarge": 2.624000, + "eu-north-1|c5a.24xlarge": 3.936000, + "eu-north-1|c5a.2xlarge": 0.328000, + "eu-north-1|c5a.4xlarge": 0.656000, + "eu-north-1|c5a.8xlarge": 1.312000, + "eu-north-1|c5a.large": 0.082000, + "eu-north-1|c5a.xlarge": 0.164000, + "eu-north-1|c5d.12xlarge": 2.496000, + "eu-north-1|c5d.18xlarge": 3.744000, + "eu-north-1|c5d.24xlarge": 4.992000, + "eu-north-1|c5d.2xlarge": 0.416000, + "eu-north-1|c5d.4xlarge": 0.832000, + "eu-north-1|c5d.9xlarge": 1.872000, + "eu-north-1|c5d.large": 0.104000, + "eu-north-1|c5d.metal": 4.992000, + "eu-north-1|c5d.xlarge": 0.208000, + "eu-north-1|c5n.18xlarge": 4.176000, + "eu-north-1|c5n.2xlarge": 0.464000, + "eu-north-1|c5n.4xlarge": 0.928000, + "eu-north-1|c5n.9xlarge": 2.088000, + "eu-north-1|c5n.large": 0.116000, + "eu-north-1|c5n.metal": 4.176000, + "eu-north-1|c5n.xlarge": 0.232000, + "eu-north-1|c6g.12xlarge": 1.752000, + "eu-north-1|c6g.16xlarge": 2.336000, + "eu-north-1|c6g.2xlarge": 0.292000, + "eu-north-1|c6g.4xlarge": 0.584000, + "eu-north-1|c6g.8xlarge": 1.168000, + "eu-north-1|c6g.large": 0.073000, + "eu-north-1|c6g.medium": 0.036500, + "eu-north-1|c6g.metal": 2.336000, + "eu-north-1|c6g.xlarge": 0.146000, + "eu-north-1|c6gd.12xlarge": 1.996800, + "eu-north-1|c6gd.16xlarge": 2.662400, + "eu-north-1|c6gd.2xlarge": 0.332800, + "eu-north-1|c6gd.4xlarge": 0.665600, + "eu-north-1|c6gd.8xlarge": 1.331200, + "eu-north-1|c6gd.large": 0.083200, + "eu-north-1|c6gd.medium": 0.041600, + "eu-north-1|c6gd.metal": 2.662400, + "eu-north-1|c6gd.xlarge": 0.166400, + "eu-north-1|c6gn.12xlarge": 2.232000, + "eu-north-1|c6gn.16xlarge": 2.976000, + "eu-north-1|c6gn.2xlarge": 0.372000, + "eu-north-1|c6gn.4xlarge": 0.744000, + "eu-north-1|c6gn.8xlarge": 1.488000, + "eu-north-1|c6gn.large": 0.093000, + "eu-north-1|c6gn.medium": 0.046500, + "eu-north-1|c6gn.xlarge": 0.186000, + "eu-north-1|c6i.12xlarge": 2.184000, + "eu-north-1|c6i.16xlarge": 2.912000, + "eu-north-1|c6i.24xlarge": 4.368000, + "eu-north-1|c6i.2xlarge": 0.364000, + "eu-north-1|c6i.32xlarge": 5.824000, + "eu-north-1|c6i.4xlarge": 0.728000, + "eu-north-1|c6i.8xlarge": 1.456000, + "eu-north-1|c6i.large": 0.091000, + "eu-north-1|c6i.metal": 5.824000, + "eu-north-1|c6i.xlarge": 0.182000, + "eu-north-1|c6in.12xlarge": 2.923200, + "eu-north-1|c6in.16xlarge": 3.897600, + "eu-north-1|c6in.24xlarge": 5.846400, + "eu-north-1|c6in.2xlarge": 0.487200, + "eu-north-1|c6in.32xlarge": 7.795200, + "eu-north-1|c6in.4xlarge": 0.974400, + "eu-north-1|c6in.8xlarge": 1.948800, + "eu-north-1|c6in.large": 0.121800, + "eu-north-1|c6in.metal": 7.795200, + "eu-north-1|c6in.xlarge": 0.243600, + "eu-north-1|c7a.12xlarge": 2.637120, + "eu-north-1|c7a.16xlarge": 3.516160, + "eu-north-1|c7a.24xlarge": 5.274240, + "eu-north-1|c7a.2xlarge": 0.439520, + "eu-north-1|c7a.32xlarge": 7.032320, + "eu-north-1|c7a.48xlarge": 10.548480, + "eu-north-1|c7a.4xlarge": 0.879040, + "eu-north-1|c7a.8xlarge": 1.758080, + "eu-north-1|c7a.large": 0.109880, + "eu-north-1|c7a.medium": 0.054940, + "eu-north-1|c7a.metal-48xl": 10.548480, + "eu-north-1|c7a.xlarge": 0.219760, + "eu-north-1|c7g.12xlarge": 1.856600, + "eu-north-1|c7g.16xlarge": 2.475500, + "eu-north-1|c7g.2xlarge": 0.309400, + "eu-north-1|c7g.4xlarge": 0.618900, + "eu-north-1|c7g.8xlarge": 1.237800, + "eu-north-1|c7g.large": 0.077400, + "eu-north-1|c7g.medium": 0.038700, + "eu-north-1|c7g.metal": 2.475500, + "eu-north-1|c7g.xlarge": 0.154700, + "eu-north-1|c7gd.12xlarge": 2.358700, + "eu-north-1|c7gd.16xlarge": 3.145000, + "eu-north-1|c7gd.2xlarge": 0.393100, + "eu-north-1|c7gd.4xlarge": 0.786200, + "eu-north-1|c7gd.8xlarge": 1.572500, + "eu-north-1|c7gd.large": 0.098300, + "eu-north-1|c7gd.medium": 0.049100, + "eu-north-1|c7gd.metal": 3.145000, + "eu-north-1|c7gd.xlarge": 0.196600, + "eu-north-1|c7i-flex.12xlarge": 2.178540, + "eu-north-1|c7i-flex.16xlarge": 2.904720, + "eu-north-1|c7i-flex.2xlarge": 0.363090, + "eu-north-1|c7i-flex.4xlarge": 0.726180, + "eu-north-1|c7i-flex.8xlarge": 1.452360, + "eu-north-1|c7i-flex.large": 0.090770, + "eu-north-1|c7i-flex.xlarge": 0.181550, + "eu-north-1|c7i.12xlarge": 2.293200, + "eu-north-1|c7i.16xlarge": 3.057600, + "eu-north-1|c7i.24xlarge": 4.586400, + "eu-north-1|c7i.2xlarge": 0.382200, + "eu-north-1|c7i.48xlarge": 9.172800, + "eu-north-1|c7i.4xlarge": 0.764400, + "eu-north-1|c7i.8xlarge": 1.528800, + "eu-north-1|c7i.large": 0.095550, + "eu-north-1|c7i.metal-24xl": 4.586400, + "eu-north-1|c7i.metal-48xl": 9.172800, + "eu-north-1|c7i.xlarge": 0.191100, + "eu-north-1|c8g.12xlarge": 2.042400, + "eu-north-1|c8g.16xlarge": 2.723200, + "eu-north-1|c8g.24xlarge": 4.084800, + "eu-north-1|c8g.2xlarge": 0.340400, + "eu-north-1|c8g.48xlarge": 8.169600, + "eu-north-1|c8g.4xlarge": 0.680800, + "eu-north-1|c8g.8xlarge": 1.361600, + "eu-north-1|c8g.large": 0.085100, + "eu-north-1|c8g.medium": 0.042550, + "eu-north-1|c8g.metal-24xl": 4.084800, + "eu-north-1|c8g.metal-48xl": 8.169600, + "eu-north-1|c8g.xlarge": 0.170200, + "eu-north-1|c8gn.12xlarge": 3.054700, + "eu-north-1|c8gn.16xlarge": 4.073000, + "eu-north-1|c8gn.24xlarge": 6.109400, + "eu-north-1|c8gn.2xlarge": 0.509100, + "eu-north-1|c8gn.48xlarge": 12.218900, + "eu-north-1|c8gn.4xlarge": 1.018200, + "eu-north-1|c8gn.8xlarge": 2.036500, + "eu-north-1|c8gn.large": 0.127300, + "eu-north-1|c8gn.medium": 0.063600, + "eu-north-1|c8gn.xlarge": 0.254600, + "eu-north-1|d2.2xlarge": 1.396000, + "eu-north-1|d2.4xlarge": 2.792000, + "eu-north-1|d2.8xlarge": 5.584000, + "eu-north-1|d2.xlarge": 0.698000, + "eu-north-1|g4dn.12xlarge": 4.150000, + "eu-north-1|g4dn.16xlarge": 4.617000, + "eu-north-1|g4dn.2xlarge": 0.798000, + "eu-north-1|g4dn.4xlarge": 1.277000, + "eu-north-1|g4dn.8xlarge": 2.308000, + "eu-north-1|g4dn.metal": 8.300000, + "eu-north-1|g4dn.xlarge": 0.558000, + "eu-north-1|g5.12xlarge": 6.015930, + "eu-north-1|g5.16xlarge": 4.344370, + "eu-north-1|g5.24xlarge": 8.637820, + "eu-north-1|g5.2xlarge": 1.285490, + "eu-north-1|g5.48xlarge": 17.275640, + "eu-north-1|g5.4xlarge": 1.722470, + "eu-north-1|g5.8xlarge": 2.596440, + "eu-north-1|g5.xlarge": 1.067000, + "eu-north-1|g6.12xlarge": 4.880620, + "eu-north-1|g6.16xlarge": 3.602770, + "eu-north-1|g6.24xlarge": 7.079960, + "eu-north-1|g6.2xlarge": 1.036880, + "eu-north-1|g6.48xlarge": 14.159920, + "eu-north-1|g6.4xlarge": 1.403430, + "eu-north-1|g6.8xlarge": 2.136550, + "eu-north-1|g6.xlarge": 0.853600, + "eu-north-1|g6e.12xlarge": 11.129750, + "eu-north-1|g6e.16xlarge": 8.037280, + "eu-north-1|g6e.24xlarge": 15.980370, + "eu-north-1|g6e.2xlarge": 2.378220, + "eu-north-1|g6e.48xlarge": 31.960750, + "eu-north-1|g6e.4xlarge": 3.186660, + "eu-north-1|g6e.8xlarge": 4.803530, + "eu-north-1|g6e.xlarge": 1.974000, + "eu-north-1|g6f.2xlarge": 0.503790, + "eu-north-1|g6f.4xlarge": 1.007580, + "eu-north-1|g6f.large": 0.214240, + "eu-north-1|g6f.xlarge": 0.251900, + "eu-north-1|gr6.4xlarge": 1.632600, + "eu-north-1|gr6.8xlarge": 2.594850, + "eu-north-1|gr6f.4xlarge": 1.130690, + "eu-north-1|hpc6a.48xlarge": 3.093000, + "eu-north-1|hpc6id.32xlarge": 6.035200, + "eu-north-1|hpc7a.12xlarge": 7.725200, + "eu-north-1|hpc7a.24xlarge": 7.725200, + "eu-north-1|hpc7a.48xlarge": 7.725200, + "eu-north-1|hpc7a.96xlarge": 7.725200, + "eu-north-1|i3.16xlarge": 5.216000, + "eu-north-1|i3.2xlarge": 0.652000, + "eu-north-1|i3.4xlarge": 1.304000, + "eu-north-1|i3.8xlarge": 2.608000, + "eu-north-1|i3.large": 0.163000, + "eu-north-1|i3.metal": 5.216000, + "eu-north-1|i3.xlarge": 0.326000, + "eu-north-1|i3en.12xlarge": 5.688000, + "eu-north-1|i3en.24xlarge": 11.376000, + "eu-north-1|i3en.2xlarge": 0.948000, + "eu-north-1|i3en.3xlarge": 1.422000, + "eu-north-1|i3en.6xlarge": 2.844000, + "eu-north-1|i3en.large": 0.237000, + "eu-north-1|i3en.metal": 11.376000, + "eu-north-1|i3en.xlarge": 0.474000, + "eu-north-1|i4i.12xlarge": 4.303000, + "eu-north-1|i4i.16xlarge": 5.738000, + "eu-north-1|i4i.24xlarge": 8.606400, + "eu-north-1|i4i.2xlarge": 0.717000, + "eu-north-1|i4i.32xlarge": 11.475200, + "eu-north-1|i4i.4xlarge": 1.434000, + "eu-north-1|i4i.8xlarge": 2.869000, + "eu-north-1|i4i.large": 0.179000, + "eu-north-1|i4i.metal": 11.475000, + "eu-north-1|i4i.xlarge": 0.359000, + "eu-north-1|i7i.12xlarge": 4.733500, + "eu-north-1|i7i.16xlarge": 6.311400, + "eu-north-1|i7i.24xlarge": 9.467000, + "eu-north-1|i7i.2xlarge": 0.788900, + "eu-north-1|i7i.48xlarge": 18.934100, + "eu-north-1|i7i.4xlarge": 1.577800, + "eu-north-1|i7i.8xlarge": 3.155700, + "eu-north-1|i7i.large": 0.197200, + "eu-north-1|i7i.metal-24xl": 9.467000, + "eu-north-1|i7i.metal-48xl": 18.934100, + "eu-north-1|i7i.xlarge": 0.394500, + "eu-north-1|i7ie.12xlarge": 6.541200, + "eu-north-1|i7ie.18xlarge": 9.811800, + "eu-north-1|i7ie.24xlarge": 13.082400, + "eu-north-1|i7ie.2xlarge": 1.090200, + "eu-north-1|i7ie.3xlarge": 1.635300, + "eu-north-1|i7ie.48xlarge": 26.164800, + "eu-north-1|i7ie.6xlarge": 3.270600, + "eu-north-1|i7ie.large": 0.272600, + "eu-north-1|i7ie.metal-24xl": 13.082400, + "eu-north-1|i7ie.metal-48xl": 26.164800, + "eu-north-1|i7ie.xlarge": 0.545100, + "eu-north-1|i8g.12xlarge": 4.305600, + "eu-north-1|i8g.16xlarge": 5.740800, + "eu-north-1|i8g.24xlarge": 8.611200, + "eu-north-1|i8g.2xlarge": 0.717600, + "eu-north-1|i8g.48xlarge": 17.222400, + "eu-north-1|i8g.4xlarge": 1.435200, + "eu-north-1|i8g.8xlarge": 2.870400, + "eu-north-1|i8g.large": 0.179400, + "eu-north-1|i8g.metal-24xl": 8.611200, + "eu-north-1|i8g.xlarge": 0.358800, + "eu-north-1|inf1.24xlarge": 5.016000, + "eu-north-1|inf1.2xlarge": 0.385000, + "eu-north-1|inf1.6xlarge": 1.254000, + "eu-north-1|inf1.xlarge": 0.242000, + "eu-north-1|inf2.24xlarge": 7.139700, + "eu-north-1|inf2.48xlarge": 14.279390, + "eu-north-1|inf2.8xlarge": 2.164650, + "eu-north-1|inf2.xlarge": 0.834020, + "eu-north-1|m5.12xlarge": 2.448000, + "eu-north-1|m5.16xlarge": 3.264000, + "eu-north-1|m5.24xlarge": 4.896000, + "eu-north-1|m5.2xlarge": 0.408000, + "eu-north-1|m5.4xlarge": 0.816000, + "eu-north-1|m5.8xlarge": 1.632000, + "eu-north-1|m5.large": 0.102000, + "eu-north-1|m5.metal": 4.896000, + "eu-north-1|m5.xlarge": 0.204000, + "eu-north-1|m5d.12xlarge": 2.880000, + "eu-north-1|m5d.16xlarge": 3.840000, + "eu-north-1|m5d.24xlarge": 5.760000, + "eu-north-1|m5d.2xlarge": 0.480000, + "eu-north-1|m5d.4xlarge": 0.960000, + "eu-north-1|m5d.8xlarge": 1.920000, + "eu-north-1|m5d.large": 0.120000, + "eu-north-1|m5d.metal": 5.760000, + "eu-north-1|m5d.xlarge": 0.240000, + "eu-north-1|m6g.12xlarge": 1.968000, + "eu-north-1|m6g.16xlarge": 2.624000, + "eu-north-1|m6g.2xlarge": 0.328000, + "eu-north-1|m6g.4xlarge": 0.656000, + "eu-north-1|m6g.8xlarge": 1.312000, + "eu-north-1|m6g.large": 0.082000, + "eu-north-1|m6g.medium": 0.041000, + "eu-north-1|m6g.metal": 2.624000, + "eu-north-1|m6g.xlarge": 0.164000, + "eu-north-1|m6gd.12xlarge": 2.304000, + "eu-north-1|m6gd.16xlarge": 3.072000, + "eu-north-1|m6gd.2xlarge": 0.384000, + "eu-north-1|m6gd.4xlarge": 0.768000, + "eu-north-1|m6gd.8xlarge": 1.536000, + "eu-north-1|m6gd.large": 0.096000, + "eu-north-1|m6gd.medium": 0.048000, + "eu-north-1|m6gd.metal": 3.072000, + "eu-north-1|m6gd.xlarge": 0.192000, + "eu-north-1|m6i.12xlarge": 2.448000, + "eu-north-1|m6i.16xlarge": 3.264000, + "eu-north-1|m6i.24xlarge": 4.896000, + "eu-north-1|m6i.2xlarge": 0.408000, + "eu-north-1|m6i.32xlarge": 6.528000, + "eu-north-1|m6i.4xlarge": 0.816000, + "eu-north-1|m6i.8xlarge": 1.632000, + "eu-north-1|m6i.large": 0.102000, + "eu-north-1|m6i.metal": 6.528000, + "eu-north-1|m6i.xlarge": 0.204000, + "eu-north-1|m6idn.12xlarge": 3.984000, + "eu-north-1|m6idn.16xlarge": 5.312000, + "eu-north-1|m6idn.24xlarge": 7.968000, + "eu-north-1|m6idn.2xlarge": 0.664000, + "eu-north-1|m6idn.32xlarge": 10.624000, + "eu-north-1|m6idn.4xlarge": 1.328000, + "eu-north-1|m6idn.8xlarge": 2.656000, + "eu-north-1|m6idn.large": 0.166000, + "eu-north-1|m6idn.metal": 10.624000, + "eu-north-1|m6idn.xlarge": 0.332000, + "eu-north-1|m6in.12xlarge": 3.552000, + "eu-north-1|m6in.16xlarge": 4.736000, + "eu-north-1|m6in.24xlarge": 7.104000, + "eu-north-1|m6in.2xlarge": 0.592000, + "eu-north-1|m6in.32xlarge": 9.472000, + "eu-north-1|m6in.4xlarge": 1.184000, + "eu-north-1|m6in.8xlarge": 2.368000, + "eu-north-1|m6in.large": 0.148000, + "eu-north-1|m6in.metal": 9.472000, + "eu-north-1|m6in.xlarge": 0.296000, + "eu-north-1|m7a.12xlarge": 2.955840, + "eu-north-1|m7a.16xlarge": 3.941120, + "eu-north-1|m7a.24xlarge": 5.911680, + "eu-north-1|m7a.2xlarge": 0.492640, + "eu-north-1|m7a.32xlarge": 7.882240, + "eu-north-1|m7a.48xlarge": 11.823360, + "eu-north-1|m7a.4xlarge": 0.985280, + "eu-north-1|m7a.8xlarge": 1.970560, + "eu-north-1|m7a.large": 0.123160, + "eu-north-1|m7a.medium": 0.061580, + "eu-north-1|m7a.metal-48xl": 11.823360, + "eu-north-1|m7a.xlarge": 0.246320, + "eu-north-1|m7g.12xlarge": 2.080800, + "eu-north-1|m7g.16xlarge": 2.774400, + "eu-north-1|m7g.2xlarge": 0.346800, + "eu-north-1|m7g.4xlarge": 0.693600, + "eu-north-1|m7g.8xlarge": 1.387200, + "eu-north-1|m7g.large": 0.086700, + "eu-north-1|m7g.medium": 0.043400, + "eu-north-1|m7g.metal": 2.774400, + "eu-north-1|m7g.xlarge": 0.173400, + "eu-north-1|m7gd.12xlarge": 2.721600, + "eu-north-1|m7gd.16xlarge": 3.628800, + "eu-north-1|m7gd.2xlarge": 0.453600, + "eu-north-1|m7gd.4xlarge": 0.907200, + "eu-north-1|m7gd.8xlarge": 1.814400, + "eu-north-1|m7gd.large": 0.113400, + "eu-north-1|m7gd.medium": 0.056700, + "eu-north-1|m7gd.metal": 3.628800, + "eu-north-1|m7gd.xlarge": 0.226800, + "eu-north-1|m7i-flex.12xlarge": 2.442000, + "eu-north-1|m7i-flex.16xlarge": 3.256000, + "eu-north-1|m7i-flex.2xlarge": 0.407000, + "eu-north-1|m7i-flex.4xlarge": 0.814000, + "eu-north-1|m7i-flex.8xlarge": 1.628000, + "eu-north-1|m7i-flex.large": 0.101750, + "eu-north-1|m7i-flex.xlarge": 0.203500, + "eu-north-1|m7i.12xlarge": 2.570400, + "eu-north-1|m7i.16xlarge": 3.427200, + "eu-north-1|m7i.24xlarge": 5.140800, + "eu-north-1|m7i.2xlarge": 0.428400, + "eu-north-1|m7i.48xlarge": 10.281600, + "eu-north-1|m7i.4xlarge": 0.856800, + "eu-north-1|m7i.8xlarge": 1.713600, + "eu-north-1|m7i.large": 0.107100, + "eu-north-1|m7i.metal-24xl": 5.140800, + "eu-north-1|m7i.metal-48xl": 10.281600, + "eu-north-1|m7i.xlarge": 0.214200, + "eu-north-1|m8g.12xlarge": 2.289120, + "eu-north-1|m8g.16xlarge": 3.052160, + "eu-north-1|m8g.24xlarge": 4.578240, + "eu-north-1|m8g.2xlarge": 0.381520, + "eu-north-1|m8g.48xlarge": 9.156480, + "eu-north-1|m8g.4xlarge": 0.763040, + "eu-north-1|m8g.8xlarge": 1.526080, + "eu-north-1|m8g.large": 0.095380, + "eu-north-1|m8g.medium": 0.047690, + "eu-north-1|m8g.metal-24xl": 4.578240, + "eu-north-1|m8g.metal-48xl": 9.156480, + "eu-north-1|m8g.xlarge": 0.190760, + "eu-north-1|p4d.24xlarge": 23.715690, + "eu-north-1|p5.48xlarge": 58.892800, + "eu-north-1|p5en.48xlarge": 67.726720, + "eu-north-1|r5.12xlarge": 3.216000, + "eu-north-1|r5.16xlarge": 4.288000, + "eu-north-1|r5.24xlarge": 6.432000, + "eu-north-1|r5.2xlarge": 0.536000, + "eu-north-1|r5.4xlarge": 1.072000, + "eu-north-1|r5.8xlarge": 2.144000, + "eu-north-1|r5.large": 0.134000, + "eu-north-1|r5.metal": 6.432000, + "eu-north-1|r5.xlarge": 0.268000, + "eu-north-1|r5b.12xlarge": 3.790560, + "eu-north-1|r5b.16xlarge": 5.054080, + "eu-north-1|r5b.24xlarge": 7.581120, + "eu-north-1|r5b.2xlarge": 0.631760, + "eu-north-1|r5b.4xlarge": 1.263520, + "eu-north-1|r5b.8xlarge": 2.527040, + "eu-north-1|r5b.large": 0.157940, + "eu-north-1|r5b.metal": 7.581120, + "eu-north-1|r5b.xlarge": 0.315880, + "eu-north-1|r5d.12xlarge": 3.648000, + "eu-north-1|r5d.16xlarge": 4.864000, + "eu-north-1|r5d.24xlarge": 7.296000, + "eu-north-1|r5d.2xlarge": 0.608000, + "eu-north-1|r5d.4xlarge": 1.216000, + "eu-north-1|r5d.8xlarge": 2.432000, + "eu-north-1|r5d.large": 0.152000, + "eu-north-1|r5d.metal": 7.296000, + "eu-north-1|r5d.xlarge": 0.304000, + "eu-north-1|r5dn.12xlarge": 4.248000, + "eu-north-1|r5dn.16xlarge": 5.664000, + "eu-north-1|r5dn.24xlarge": 8.496000, + "eu-north-1|r5dn.2xlarge": 0.708000, + "eu-north-1|r5dn.4xlarge": 1.416000, + "eu-north-1|r5dn.8xlarge": 2.832000, + "eu-north-1|r5dn.large": 0.177000, + "eu-north-1|r5dn.metal": 8.496000, + "eu-north-1|r5dn.xlarge": 0.354000, + "eu-north-1|r5n.12xlarge": 3.816000, + "eu-north-1|r5n.16xlarge": 5.088000, + "eu-north-1|r5n.24xlarge": 7.632000, + "eu-north-1|r5n.2xlarge": 0.636000, + "eu-north-1|r5n.4xlarge": 1.272000, + "eu-north-1|r5n.8xlarge": 2.544000, + "eu-north-1|r5n.large": 0.159000, + "eu-north-1|r5n.metal": 7.632000, + "eu-north-1|r5n.xlarge": 0.318000, + "eu-north-1|r6g.12xlarge": 2.568000, + "eu-north-1|r6g.16xlarge": 3.424000, + "eu-north-1|r6g.2xlarge": 0.428000, + "eu-north-1|r6g.4xlarge": 0.856000, + "eu-north-1|r6g.8xlarge": 1.712000, + "eu-north-1|r6g.large": 0.107000, + "eu-north-1|r6g.medium": 0.053500, + "eu-north-1|r6g.metal": 3.424000, + "eu-north-1|r6g.xlarge": 0.214000, + "eu-north-1|r6gd.12xlarge": 2.918400, + "eu-north-1|r6gd.16xlarge": 3.891200, + "eu-north-1|r6gd.2xlarge": 0.486400, + "eu-north-1|r6gd.4xlarge": 0.972800, + "eu-north-1|r6gd.8xlarge": 1.945600, + "eu-north-1|r6gd.large": 0.121600, + "eu-north-1|r6gd.medium": 0.060800, + "eu-north-1|r6gd.metal": 3.891200, + "eu-north-1|r6gd.xlarge": 0.243200, + "eu-north-1|r6i.12xlarge": 3.216000, + "eu-north-1|r6i.16xlarge": 4.288000, + "eu-north-1|r6i.24xlarge": 6.432000, + "eu-north-1|r6i.2xlarge": 0.536000, + "eu-north-1|r6i.32xlarge": 8.576000, + "eu-north-1|r6i.4xlarge": 1.072000, + "eu-north-1|r6i.8xlarge": 2.144000, + "eu-north-1|r6i.large": 0.134000, + "eu-north-1|r6i.metal": 8.576000, + "eu-north-1|r6i.xlarge": 0.268000, + "eu-north-1|r6idn.12xlarge": 4.970160, + "eu-north-1|r6idn.16xlarge": 6.626880, + "eu-north-1|r6idn.24xlarge": 9.940320, + "eu-north-1|r6idn.2xlarge": 0.828360, + "eu-north-1|r6idn.32xlarge": 13.253760, + "eu-north-1|r6idn.4xlarge": 1.656720, + "eu-north-1|r6idn.8xlarge": 3.313440, + "eu-north-1|r6idn.large": 0.207090, + "eu-north-1|r6idn.metal": 13.253760, + "eu-north-1|r6idn.xlarge": 0.414180, + "eu-north-1|r6in.12xlarge": 4.464720, + "eu-north-1|r6in.16xlarge": 5.952960, + "eu-north-1|r6in.24xlarge": 8.929440, + "eu-north-1|r6in.2xlarge": 0.744120, + "eu-north-1|r6in.32xlarge": 11.905920, + "eu-north-1|r6in.4xlarge": 1.488240, + "eu-north-1|r6in.8xlarge": 2.976480, + "eu-north-1|r6in.large": 0.186030, + "eu-north-1|r6in.metal": 11.905920, + "eu-north-1|r6in.xlarge": 0.372060, + "eu-north-1|r7a.12xlarge": 3.883200, + "eu-north-1|r7a.16xlarge": 5.177600, + "eu-north-1|r7a.24xlarge": 7.766400, + "eu-north-1|r7a.2xlarge": 0.647200, + "eu-north-1|r7a.32xlarge": 10.355200, + "eu-north-1|r7a.48xlarge": 15.532800, + "eu-north-1|r7a.4xlarge": 1.294400, + "eu-north-1|r7a.8xlarge": 2.588800, + "eu-north-1|r7a.large": 0.161800, + "eu-north-1|r7a.medium": 0.080900, + "eu-north-1|r7a.metal-48xl": 15.532800, + "eu-north-1|r7a.xlarge": 0.323600, + "eu-north-1|r7g.12xlarge": 2.733600, + "eu-north-1|r7g.16xlarge": 3.644800, + "eu-north-1|r7g.2xlarge": 0.455600, + "eu-north-1|r7g.4xlarge": 0.911200, + "eu-north-1|r7g.8xlarge": 1.822400, + "eu-north-1|r7g.large": 0.113900, + "eu-north-1|r7g.medium": 0.057000, + "eu-north-1|r7g.metal": 3.644800, + "eu-north-1|r7g.xlarge": 0.227800, + "eu-north-1|r7gd.12xlarge": 3.447400, + "eu-north-1|r7gd.16xlarge": 4.596500, + "eu-north-1|r7gd.2xlarge": 0.574600, + "eu-north-1|r7gd.4xlarge": 1.149100, + "eu-north-1|r7gd.8xlarge": 2.298200, + "eu-north-1|r7gd.large": 0.143600, + "eu-north-1|r7gd.medium": 0.071800, + "eu-north-1|r7gd.metal": 4.596500, + "eu-north-1|r7gd.xlarge": 0.287300, + "eu-north-1|r7i.12xlarge": 3.376800, + "eu-north-1|r7i.16xlarge": 4.502400, + "eu-north-1|r7i.24xlarge": 6.753600, + "eu-north-1|r7i.2xlarge": 0.562800, + "eu-north-1|r7i.48xlarge": 13.507200, + "eu-north-1|r7i.4xlarge": 1.125600, + "eu-north-1|r7i.8xlarge": 2.251200, + "eu-north-1|r7i.large": 0.140700, + "eu-north-1|r7i.metal-24xl": 6.753600, + "eu-north-1|r7i.metal-48xl": 13.507200, + "eu-north-1|r7i.xlarge": 0.281400, + "eu-north-1|r8g.12xlarge": 3.006960, + "eu-north-1|r8g.16xlarge": 4.009280, + "eu-north-1|r8g.24xlarge": 6.013920, + "eu-north-1|r8g.2xlarge": 0.501160, + "eu-north-1|r8g.48xlarge": 12.027840, + "eu-north-1|r8g.4xlarge": 1.002320, + "eu-north-1|r8g.8xlarge": 2.004640, + "eu-north-1|r8g.large": 0.125290, + "eu-north-1|r8g.medium": 0.062650, + "eu-north-1|r8g.metal-24xl": 6.013920, + "eu-north-1|r8g.metal-48xl": 12.027840, + "eu-north-1|r8g.xlarge": 0.250580, + "eu-north-1|t3.2xlarge": 0.345600, + "eu-north-1|t3.large": 0.086400, + "eu-north-1|t3.medium": 0.043200, + "eu-north-1|t3.micro": 0.010800, + "eu-north-1|t3.nano": 0.005400, + "eu-north-1|t3.small": 0.021600, + "eu-north-1|t3.xlarge": 0.172800, + "eu-north-1|t4g.2xlarge": 0.275200, + "eu-north-1|t4g.large": 0.068800, + "eu-north-1|t4g.medium": 0.034400, + "eu-north-1|t4g.micro": 0.008600, + "eu-north-1|t4g.nano": 0.004300, + "eu-north-1|t4g.small": 0.017200, + "eu-north-1|t4g.xlarge": 0.137600, + "eu-north-1|u-6tb1.112xlarge": 58.045000, + "eu-north-1|u-6tb1.56xlarge": 49.331770, + "eu-north-1|u-9tb1.112xlarge": 91.650000, + "eu-north-1|u7i-12tb.224xlarge": 140.532190, + "eu-north-1|u7i-6tb.112xlarge": 66.751750, + "eu-north-1|x2idn.16xlarge": 7.605500, + "eu-north-1|x2idn.24xlarge": 11.408250, + "eu-north-1|x2idn.32xlarge": 15.211000, + "eu-north-1|x2idn.metal": 15.211000, + "eu-north-1|x2iedn.16xlarge": 15.211500, + "eu-north-1|x2iedn.24xlarge": 22.817250, + "eu-north-1|x2iedn.2xlarge": 1.901440, + "eu-north-1|x2iedn.32xlarge": 30.423000, + "eu-north-1|x2iedn.4xlarge": 3.802880, + "eu-north-1|x2iedn.8xlarge": 7.605750, + "eu-north-1|x2iedn.metal": 30.423000, + "eu-north-1|x2iedn.xlarge": 0.950720, + "eu-north-1|x8g.12xlarge": 5.339040, + "eu-north-1|x8g.16xlarge": 7.118720, + "eu-north-1|x8g.24xlarge": 10.678080, + "eu-north-1|x8g.2xlarge": 0.889840, + "eu-north-1|x8g.48xlarge": 21.356160, + "eu-north-1|x8g.4xlarge": 1.779680, + "eu-north-1|x8g.8xlarge": 3.559360, + "eu-north-1|x8g.large": 0.222460, + "eu-north-1|x8g.medium": 0.111230, + "eu-north-1|x8g.metal-24xl": 10.678080, + "eu-north-1|x8g.metal-48xl": 21.356160, + "eu-north-1|x8g.xlarge": 0.444920, + "eu-south-1|c5.12xlarge": 2.424000, + "eu-south-1|c5.18xlarge": 3.636000, + "eu-south-1|c5.24xlarge": 4.848000, + "eu-south-1|c5.2xlarge": 0.404000, + "eu-south-1|c5.4xlarge": 0.808000, + "eu-south-1|c5.9xlarge": 1.818000, + "eu-south-1|c5.large": 0.101000, + "eu-south-1|c5.metal": 4.848000, + "eu-south-1|c5.xlarge": 0.202000, + "eu-south-1|c5a.12xlarge": 2.184000, + "eu-south-1|c5a.16xlarge": 2.912000, + "eu-south-1|c5a.24xlarge": 4.368000, + "eu-south-1|c5a.2xlarge": 0.364000, + "eu-south-1|c5a.4xlarge": 0.728000, + "eu-south-1|c5a.8xlarge": 1.456000, + "eu-south-1|c5a.large": 0.091000, + "eu-south-1|c5a.xlarge": 0.182000, + "eu-south-1|c5ad.12xlarge": 2.472000, + "eu-south-1|c5ad.16xlarge": 3.296000, + "eu-south-1|c5ad.24xlarge": 4.944000, + "eu-south-1|c5ad.2xlarge": 0.412000, + "eu-south-1|c5ad.4xlarge": 0.824000, + "eu-south-1|c5ad.8xlarge": 1.648000, + "eu-south-1|c5ad.large": 0.103000, + "eu-south-1|c5ad.xlarge": 0.206000, + "eu-south-1|c5d.12xlarge": 2.736000, + "eu-south-1|c5d.18xlarge": 4.104000, + "eu-south-1|c5d.24xlarge": 5.472000, + "eu-south-1|c5d.2xlarge": 0.456000, + "eu-south-1|c5d.4xlarge": 0.912000, + "eu-south-1|c5d.9xlarge": 2.052000, + "eu-south-1|c5d.large": 0.114000, + "eu-south-1|c5d.metal": 5.472000, + "eu-south-1|c5d.xlarge": 0.228000, + "eu-south-1|c5n.18xlarge": 4.644000, + "eu-south-1|c5n.2xlarge": 0.516000, + "eu-south-1|c5n.4xlarge": 1.032000, + "eu-south-1|c5n.9xlarge": 2.322000, + "eu-south-1|c5n.large": 0.129000, + "eu-south-1|c5n.metal": 4.644000, + "eu-south-1|c5n.xlarge": 0.258000, + "eu-south-1|c6g.12xlarge": 1.939200, + "eu-south-1|c6g.16xlarge": 2.585600, + "eu-south-1|c6g.2xlarge": 0.323200, + "eu-south-1|c6g.4xlarge": 0.646400, + "eu-south-1|c6g.8xlarge": 1.292800, + "eu-south-1|c6g.large": 0.080800, + "eu-south-1|c6g.medium": 0.040400, + "eu-south-1|c6g.metal": 2.585600, + "eu-south-1|c6g.xlarge": 0.161600, + "eu-south-1|c6gn.12xlarge": 2.476800, + "eu-south-1|c6gn.16xlarge": 3.302400, + "eu-south-1|c6gn.2xlarge": 0.412800, + "eu-south-1|c6gn.4xlarge": 0.825600, + "eu-south-1|c6gn.8xlarge": 1.651200, + "eu-south-1|c6gn.large": 0.103200, + "eu-south-1|c6gn.medium": 0.051600, + "eu-south-1|c6gn.xlarge": 0.206400, + "eu-south-1|c6i.12xlarge": 2.424000, + "eu-south-1|c6i.16xlarge": 3.232000, + "eu-south-1|c6i.24xlarge": 4.848000, + "eu-south-1|c6i.2xlarge": 0.404000, + "eu-south-1|c6i.32xlarge": 6.464000, + "eu-south-1|c6i.4xlarge": 0.808000, + "eu-south-1|c6i.8xlarge": 1.616000, + "eu-south-1|c6i.large": 0.101000, + "eu-south-1|c6i.metal": 6.464000, + "eu-south-1|c6i.xlarge": 0.202000, + "eu-south-1|c6id.12xlarge": 2.872800, + "eu-south-1|c6id.16xlarge": 3.830400, + "eu-south-1|c6id.24xlarge": 5.745600, + "eu-south-1|c6id.2xlarge": 0.478800, + "eu-south-1|c6id.32xlarge": 7.660800, + "eu-south-1|c6id.4xlarge": 0.957600, + "eu-south-1|c6id.8xlarge": 1.915200, + "eu-south-1|c6id.large": 0.119700, + "eu-south-1|c6id.metal": 7.660800, + "eu-south-1|c6id.xlarge": 0.239400, + "eu-south-1|c6in.12xlarge": 3.250800, + "eu-south-1|c6in.16xlarge": 4.334400, + "eu-south-1|c6in.24xlarge": 6.501600, + "eu-south-1|c6in.2xlarge": 0.541800, + "eu-south-1|c6in.32xlarge": 8.668800, + "eu-south-1|c6in.4xlarge": 1.083600, + "eu-south-1|c6in.8xlarge": 2.167200, + "eu-south-1|c6in.large": 0.135450, + "eu-south-1|c6in.metal": 8.668800, + "eu-south-1|c6in.xlarge": 0.270900, + "eu-south-1|c7g.12xlarge": 2.055600, + "eu-south-1|c7g.16xlarge": 2.740700, + "eu-south-1|c7g.2xlarge": 0.342600, + "eu-south-1|c7g.4xlarge": 0.685200, + "eu-south-1|c7g.8xlarge": 1.370400, + "eu-south-1|c7g.large": 0.085600, + "eu-south-1|c7g.medium": 0.042800, + "eu-south-1|c7g.metal": 2.740700, + "eu-south-1|c7g.xlarge": 0.171300, + "eu-south-1|c8g.12xlarge": 2.261280, + "eu-south-1|c8g.16xlarge": 3.015040, + "eu-south-1|c8g.24xlarge": 4.522560, + "eu-south-1|c8g.2xlarge": 0.376880, + "eu-south-1|c8g.48xlarge": 9.045120, + "eu-south-1|c8g.4xlarge": 0.753760, + "eu-south-1|c8g.8xlarge": 1.507520, + "eu-south-1|c8g.large": 0.094220, + "eu-south-1|c8g.medium": 0.047110, + "eu-south-1|c8g.metal-24xl": 4.522560, + "eu-south-1|c8g.metal-48xl": 9.045120, + "eu-south-1|c8g.xlarge": 0.188440, + "eu-south-1|d2.2xlarge": 1.544000, + "eu-south-1|d2.4xlarge": 3.088000, + "eu-south-1|d2.8xlarge": 6.176000, + "eu-south-1|d2.xlarge": 0.772000, + "eu-south-1|g4dn.12xlarge": 4.580000, + "eu-south-1|g4dn.16xlarge": 5.095000, + "eu-south-1|g4dn.2xlarge": 0.880000, + "eu-south-1|g4dn.4xlarge": 1.410000, + "eu-south-1|g4dn.8xlarge": 2.547000, + "eu-south-1|g4dn.metal": 9.160000, + "eu-south-1|g4dn.xlarge": 0.616000, + "eu-south-1|i3.16xlarge": 5.792000, + "eu-south-1|i3.2xlarge": 0.724000, + "eu-south-1|i3.4xlarge": 1.448000, + "eu-south-1|i3.8xlarge": 2.896000, + "eu-south-1|i3.large": 0.181000, + "eu-south-1|i3.metal": 5.792000, + "eu-south-1|i3.xlarge": 0.362000, + "eu-south-1|i3en.12xlarge": 6.293000, + "eu-south-1|i3en.24xlarge": 12.586000, + "eu-south-1|i3en.2xlarge": 1.049000, + "eu-south-1|i3en.3xlarge": 1.573000, + "eu-south-1|i3en.6xlarge": 3.146000, + "eu-south-1|i3en.large": 0.262000, + "eu-south-1|i3en.metal": 12.586000, + "eu-south-1|i3en.xlarge": 0.524000, + "eu-south-1|i4i.12xlarge": 4.778000, + "eu-south-1|i4i.16xlarge": 6.371000, + "eu-south-1|i4i.24xlarge": 9.556800, + "eu-south-1|i4i.2xlarge": 0.796000, + "eu-south-1|i4i.32xlarge": 12.742400, + "eu-south-1|i4i.4xlarge": 1.593000, + "eu-south-1|i4i.8xlarge": 3.186000, + "eu-south-1|i4i.large": 0.199000, + "eu-south-1|i4i.metal": 12.742000, + "eu-south-1|i4i.xlarge": 0.398000, + "eu-south-1|i7i.12xlarge": 5.256200, + "eu-south-1|i7i.16xlarge": 7.008300, + "eu-south-1|i7i.24xlarge": 10.512500, + "eu-south-1|i7i.2xlarge": 0.876000, + "eu-south-1|i7i.48xlarge": 21.025000, + "eu-south-1|i7i.4xlarge": 1.752100, + "eu-south-1|i7i.8xlarge": 3.504200, + "eu-south-1|i7i.large": 0.219000, + "eu-south-1|i7i.metal-24xl": 10.512500, + "eu-south-1|i7i.metal-48xl": 21.025000, + "eu-south-1|i7i.xlarge": 0.438000, + "eu-south-1|im4gn.16xlarge": 6.752000, + "eu-south-1|im4gn.2xlarge": 0.844000, + "eu-south-1|im4gn.4xlarge": 1.688000, + "eu-south-1|im4gn.8xlarge": 3.376000, + "eu-south-1|im4gn.large": 0.211000, + "eu-south-1|im4gn.xlarge": 0.422000, + "eu-south-1|inf1.24xlarge": 5.530000, + "eu-south-1|inf1.2xlarge": 0.424000, + "eu-south-1|inf1.6xlarge": 1.382000, + "eu-south-1|inf1.xlarge": 0.267000, + "eu-south-1|m5.12xlarge": 2.688000, + "eu-south-1|m5.16xlarge": 3.584000, + "eu-south-1|m5.24xlarge": 5.376000, + "eu-south-1|m5.2xlarge": 0.448000, + "eu-south-1|m5.4xlarge": 0.896000, + "eu-south-1|m5.8xlarge": 1.792000, + "eu-south-1|m5.large": 0.112000, + "eu-south-1|m5.metal": 5.376000, + "eu-south-1|m5.xlarge": 0.224000, + "eu-south-1|m5a.12xlarge": 2.424000, + "eu-south-1|m5a.16xlarge": 3.232000, + "eu-south-1|m5a.24xlarge": 4.848000, + "eu-south-1|m5a.2xlarge": 0.404000, + "eu-south-1|m5a.4xlarge": 0.808000, + "eu-south-1|m5a.8xlarge": 1.616000, + "eu-south-1|m5a.large": 0.101000, + "eu-south-1|m5a.xlarge": 0.202000, + "eu-south-1|m5d.12xlarge": 3.168000, + "eu-south-1|m5d.16xlarge": 4.224000, + "eu-south-1|m5d.24xlarge": 6.336000, + "eu-south-1|m5d.2xlarge": 0.528000, + "eu-south-1|m5d.4xlarge": 1.056000, + "eu-south-1|m5d.8xlarge": 2.112000, + "eu-south-1|m5d.large": 0.132000, + "eu-south-1|m5d.metal": 6.336000, + "eu-south-1|m5d.xlarge": 0.264000, + "eu-south-1|m6a.12xlarge": 2.419200, + "eu-south-1|m6a.16xlarge": 3.225600, + "eu-south-1|m6a.24xlarge": 4.838400, + "eu-south-1|m6a.2xlarge": 0.403200, + "eu-south-1|m6a.32xlarge": 6.451200, + "eu-south-1|m6a.48xlarge": 9.676800, + "eu-south-1|m6a.4xlarge": 0.806400, + "eu-south-1|m6a.8xlarge": 1.612800, + "eu-south-1|m6a.large": 0.100800, + "eu-south-1|m6a.metal": 9.676800, + "eu-south-1|m6a.xlarge": 0.201600, + "eu-south-1|m6g.12xlarge": 2.150400, + "eu-south-1|m6g.16xlarge": 2.867200, + "eu-south-1|m6g.2xlarge": 0.358400, + "eu-south-1|m6g.4xlarge": 0.716800, + "eu-south-1|m6g.8xlarge": 1.433600, + "eu-south-1|m6g.large": 0.089600, + "eu-south-1|m6g.medium": 0.044800, + "eu-south-1|m6g.metal": 2.867200, + "eu-south-1|m6g.xlarge": 0.179200, + "eu-south-1|m6gd.12xlarge": 2.534400, + "eu-south-1|m6gd.16xlarge": 3.379200, + "eu-south-1|m6gd.2xlarge": 0.422400, + "eu-south-1|m6gd.4xlarge": 0.844800, + "eu-south-1|m6gd.8xlarge": 1.689600, + "eu-south-1|m6gd.large": 0.105600, + "eu-south-1|m6gd.medium": 0.052800, + "eu-south-1|m6gd.metal": 3.379200, + "eu-south-1|m6gd.xlarge": 0.211200, + "eu-south-1|m6i.12xlarge": 2.688000, + "eu-south-1|m6i.16xlarge": 3.584000, + "eu-south-1|m6i.24xlarge": 5.376000, + "eu-south-1|m6i.2xlarge": 0.448000, + "eu-south-1|m6i.32xlarge": 7.168000, + "eu-south-1|m6i.4xlarge": 0.896000, + "eu-south-1|m6i.8xlarge": 1.792000, + "eu-south-1|m6i.large": 0.112000, + "eu-south-1|m6i.metal": 7.168000, + "eu-south-1|m6i.xlarge": 0.224000, + "eu-south-1|m7i.12xlarge": 2.822400, + "eu-south-1|m7i.16xlarge": 3.763200, + "eu-south-1|m7i.24xlarge": 5.644800, + "eu-south-1|m7i.2xlarge": 0.470400, + "eu-south-1|m7i.48xlarge": 11.289600, + "eu-south-1|m7i.4xlarge": 0.940800, + "eu-south-1|m7i.8xlarge": 1.881600, + "eu-south-1|m7i.large": 0.117600, + "eu-south-1|m7i.metal-24xl": 5.644800, + "eu-south-1|m7i.metal-48xl": 11.289600, + "eu-south-1|m7i.xlarge": 0.235200, + "eu-south-1|r5.12xlarge": 3.552000, + "eu-south-1|r5.16xlarge": 4.736000, + "eu-south-1|r5.24xlarge": 7.104000, + "eu-south-1|r5.2xlarge": 0.592000, + "eu-south-1|r5.4xlarge": 1.184000, + "eu-south-1|r5.8xlarge": 2.368000, + "eu-south-1|r5.large": 0.148000, + "eu-south-1|r5.metal": 7.104000, + "eu-south-1|r5.xlarge": 0.296000, + "eu-south-1|r5a.12xlarge": 3.192000, + "eu-south-1|r5a.16xlarge": 4.256000, + "eu-south-1|r5a.24xlarge": 6.384000, + "eu-south-1|r5a.2xlarge": 0.532000, + "eu-south-1|r5a.4xlarge": 1.064000, + "eu-south-1|r5a.8xlarge": 2.128000, + "eu-south-1|r5a.large": 0.133000, + "eu-south-1|r5a.xlarge": 0.266000, + "eu-south-1|r5b.12xlarge": 4.200000, + "eu-south-1|r5b.16xlarge": 5.600000, + "eu-south-1|r5b.24xlarge": 8.400000, + "eu-south-1|r5b.2xlarge": 0.700000, + "eu-south-1|r5b.4xlarge": 1.400000, + "eu-south-1|r5b.8xlarge": 2.800000, + "eu-south-1|r5b.large": 0.175000, + "eu-south-1|r5b.metal": 8.400000, + "eu-south-1|r5b.xlarge": 0.350000, + "eu-south-1|r5d.12xlarge": 4.032000, + "eu-south-1|r5d.16xlarge": 5.376000, + "eu-south-1|r5d.24xlarge": 8.064000, + "eu-south-1|r5d.2xlarge": 0.672000, + "eu-south-1|r5d.4xlarge": 1.344000, + "eu-south-1|r5d.8xlarge": 2.688000, + "eu-south-1|r5d.large": 0.168000, + "eu-south-1|r5d.metal": 8.064000, + "eu-south-1|r5d.xlarge": 0.336000, + "eu-south-1|r5dn.12xlarge": 4.704000, + "eu-south-1|r5dn.16xlarge": 6.272000, + "eu-south-1|r5dn.24xlarge": 9.408000, + "eu-south-1|r5dn.2xlarge": 0.784000, + "eu-south-1|r5dn.4xlarge": 1.568000, + "eu-south-1|r5dn.8xlarge": 3.136000, + "eu-south-1|r5dn.large": 0.196000, + "eu-south-1|r5dn.metal": 9.408000, + "eu-south-1|r5dn.xlarge": 0.392000, + "eu-south-1|r5n.12xlarge": 4.200000, + "eu-south-1|r5n.16xlarge": 5.601000, + "eu-south-1|r5n.24xlarge": 8.401000, + "eu-south-1|r5n.2xlarge": 0.700000, + "eu-south-1|r5n.4xlarge": 1.400000, + "eu-south-1|r5n.8xlarge": 2.800000, + "eu-south-1|r5n.large": 0.175000, + "eu-south-1|r5n.metal": 8.401000, + "eu-south-1|r5n.xlarge": 0.350000, + "eu-south-1|r6g.12xlarge": 2.841600, + "eu-south-1|r6g.16xlarge": 3.788800, + "eu-south-1|r6g.2xlarge": 0.473600, + "eu-south-1|r6g.4xlarge": 0.947200, + "eu-south-1|r6g.8xlarge": 1.894400, + "eu-south-1|r6g.large": 0.118400, + "eu-south-1|r6g.medium": 0.059200, + "eu-south-1|r6g.metal": 3.788800, + "eu-south-1|r6g.xlarge": 0.236800, + "eu-south-1|r6i.12xlarge": 3.552000, + "eu-south-1|r6i.16xlarge": 4.736000, + "eu-south-1|r6i.24xlarge": 7.104000, + "eu-south-1|r6i.2xlarge": 0.592000, + "eu-south-1|r6i.32xlarge": 9.472000, + "eu-south-1|r6i.4xlarge": 1.184000, + "eu-south-1|r6i.8xlarge": 2.368000, + "eu-south-1|r6i.large": 0.148000, + "eu-south-1|r6i.metal": 9.472000, + "eu-south-1|r6i.xlarge": 0.296000, + "eu-south-1|r7g.12xlarge": 3.012100, + "eu-south-1|r7g.16xlarge": 4.016100, + "eu-south-1|r7g.2xlarge": 0.502000, + "eu-south-1|r7g.4xlarge": 1.004000, + "eu-south-1|r7g.8xlarge": 2.008100, + "eu-south-1|r7g.large": 0.125500, + "eu-south-1|r7g.medium": 0.062800, + "eu-south-1|r7g.metal": 4.016100, + "eu-south-1|r7g.xlarge": 0.251000, + "eu-south-1|r7gd.12xlarge": 3.810200, + "eu-south-1|r7gd.16xlarge": 5.080300, + "eu-south-1|r7gd.2xlarge": 0.635000, + "eu-south-1|r7gd.4xlarge": 1.270100, + "eu-south-1|r7gd.8xlarge": 2.540200, + "eu-south-1|r7gd.large": 0.158800, + "eu-south-1|r7gd.medium": 0.079400, + "eu-south-1|r7gd.metal": 5.080300, + "eu-south-1|r7gd.xlarge": 0.317500, + "eu-south-1|r7i.12xlarge": 3.729600, + "eu-south-1|r7i.16xlarge": 4.972800, + "eu-south-1|r7i.24xlarge": 7.459200, + "eu-south-1|r7i.2xlarge": 0.621600, + "eu-south-1|r7i.48xlarge": 14.918400, + "eu-south-1|r7i.4xlarge": 1.243200, + "eu-south-1|r7i.8xlarge": 2.486400, + "eu-south-1|r7i.large": 0.155400, + "eu-south-1|r7i.metal-24xl": 7.459200, + "eu-south-1|r7i.metal-48xl": 14.918400, + "eu-south-1|r7i.xlarge": 0.310800, + "eu-south-1|t3.2xlarge": 0.383400, + "eu-south-1|t3.large": 0.095800, + "eu-south-1|t3.medium": 0.047900, + "eu-south-1|t3.micro": 0.012000, + "eu-south-1|t3.nano": 0.006000, + "eu-south-1|t3.small": 0.024000, + "eu-south-1|t3.xlarge": 0.191700, + "eu-south-1|t3a.2xlarge": 0.345000, + "eu-south-1|t3a.large": 0.086200, + "eu-south-1|t3a.medium": 0.043100, + "eu-south-1|t3a.micro": 0.010800, + "eu-south-1|t3a.nano": 0.005400, + "eu-south-1|t3a.small": 0.021600, + "eu-south-1|t3a.xlarge": 0.172500, + "eu-south-1|t4g.2xlarge": 0.307200, + "eu-south-1|t4g.large": 0.076800, + "eu-south-1|t4g.medium": 0.038400, + "eu-south-1|t4g.micro": 0.009600, + "eu-south-1|t4g.nano": 0.004800, + "eu-south-1|t4g.small": 0.019200, + "eu-south-1|t4g.xlarge": 0.153600, + "eu-south-1|u-12tb1.112xlarge": 128.310000, + "eu-south-1|u-3tb1.56xlarge": 32.077500, + "eu-south-1|u-6tb1.112xlarge": 64.155000, + "eu-south-1|u-6tb1.56xlarge": 54.524590, + "eu-south-1|x2idn.16xlarge": 8.400500, + "eu-south-1|x2idn.24xlarge": 12.600750, + "eu-south-1|x2idn.32xlarge": 16.801000, + "eu-south-1|x2idn.metal": 16.801000, + "eu-south-1|x2iedn.16xlarge": 16.800500, + "eu-south-1|x2iedn.24xlarge": 25.200750, + "eu-south-1|x2iedn.2xlarge": 2.100060, + "eu-south-1|x2iedn.32xlarge": 33.601000, + "eu-south-1|x2iedn.4xlarge": 4.200130, + "eu-south-1|x2iedn.8xlarge": 8.400250, + "eu-south-1|x2iedn.metal": 33.601000, + "eu-south-1|x2iedn.xlarge": 1.050030, + "eu-west-1|a1.2xlarge": 0.230400, + "eu-west-1|a1.4xlarge": 0.460800, + "eu-west-1|a1.large": 0.057600, + "eu-west-1|a1.medium": 0.028800, + "eu-west-1|a1.metal": 0.461000, + "eu-west-1|a1.xlarge": 0.115200, + "eu-west-1|c1.medium": 0.148000, + "eu-west-1|c1.xlarge": 0.592000, + "eu-west-1|c3.2xlarge": 0.478000, + "eu-west-1|c3.4xlarge": 0.956000, + "eu-west-1|c3.8xlarge": 1.912000, + "eu-west-1|c3.large": 0.120000, + "eu-west-1|c3.xlarge": 0.239000, + "eu-west-1|c4.2xlarge": 0.453000, + "eu-west-1|c4.4xlarge": 0.905000, + "eu-west-1|c4.8xlarge": 1.811000, + "eu-west-1|c4.large": 0.113000, + "eu-west-1|c4.xlarge": 0.226000, + "eu-west-1|c5.12xlarge": 2.304000, + "eu-west-1|c5.18xlarge": 3.456000, + "eu-west-1|c5.24xlarge": 4.608000, + "eu-west-1|c5.2xlarge": 0.384000, + "eu-west-1|c5.4xlarge": 0.768000, + "eu-west-1|c5.9xlarge": 1.728000, + "eu-west-1|c5.large": 0.096000, + "eu-west-1|c5.metal": 4.608000, + "eu-west-1|c5.xlarge": 0.192000, + "eu-west-1|c5a.12xlarge": 2.064000, + "eu-west-1|c5a.16xlarge": 2.752000, + "eu-west-1|c5a.24xlarge": 4.128000, + "eu-west-1|c5a.2xlarge": 0.344000, + "eu-west-1|c5a.4xlarge": 0.688000, + "eu-west-1|c5a.8xlarge": 1.376000, + "eu-west-1|c5a.large": 0.086000, + "eu-west-1|c5a.xlarge": 0.172000, + "eu-west-1|c5ad.12xlarge": 2.352000, + "eu-west-1|c5ad.16xlarge": 3.136000, + "eu-west-1|c5ad.24xlarge": 4.704000, + "eu-west-1|c5ad.2xlarge": 0.392000, + "eu-west-1|c5ad.4xlarge": 0.784000, + "eu-west-1|c5ad.8xlarge": 1.568000, + "eu-west-1|c5ad.large": 0.098000, + "eu-west-1|c5ad.xlarge": 0.196000, + "eu-west-1|c5d.12xlarge": 2.616000, + "eu-west-1|c5d.18xlarge": 3.924000, + "eu-west-1|c5d.24xlarge": 5.232000, + "eu-west-1|c5d.2xlarge": 0.436000, + "eu-west-1|c5d.4xlarge": 0.872000, + "eu-west-1|c5d.9xlarge": 1.962000, + "eu-west-1|c5d.large": 0.109000, + "eu-west-1|c5d.metal": 5.232000, + "eu-west-1|c5d.xlarge": 0.218000, + "eu-west-1|c5n.18xlarge": 4.392000, + "eu-west-1|c5n.2xlarge": 0.488000, + "eu-west-1|c5n.4xlarge": 0.976000, + "eu-west-1|c5n.9xlarge": 2.196000, + "eu-west-1|c5n.large": 0.122000, + "eu-west-1|c5n.metal": 4.392000, + "eu-west-1|c5n.xlarge": 0.244000, + "eu-west-1|c6a.12xlarge": 1.969920, + "eu-west-1|c6a.16xlarge": 2.626560, + "eu-west-1|c6a.24xlarge": 3.939840, + "eu-west-1|c6a.2xlarge": 0.328320, + "eu-west-1|c6a.32xlarge": 5.253120, + "eu-west-1|c6a.48xlarge": 7.879680, + "eu-west-1|c6a.4xlarge": 0.656640, + "eu-west-1|c6a.8xlarge": 1.313280, + "eu-west-1|c6a.large": 0.082080, + "eu-west-1|c6a.metal": 7.879680, + "eu-west-1|c6a.xlarge": 0.164160, + "eu-west-1|c6g.12xlarge": 1.751000, + "eu-west-1|c6g.16xlarge": 2.334700, + "eu-west-1|c6g.2xlarge": 0.291800, + "eu-west-1|c6g.4xlarge": 0.583700, + "eu-west-1|c6g.8xlarge": 1.167400, + "eu-west-1|c6g.large": 0.073000, + "eu-west-1|c6g.medium": 0.036500, + "eu-west-1|c6g.metal": 2.334700, + "eu-west-1|c6g.xlarge": 0.145900, + "eu-west-1|c6gd.12xlarge": 2.092800, + "eu-west-1|c6gd.16xlarge": 2.790400, + "eu-west-1|c6gd.2xlarge": 0.348800, + "eu-west-1|c6gd.4xlarge": 0.697600, + "eu-west-1|c6gd.8xlarge": 1.395200, + "eu-west-1|c6gd.large": 0.087200, + "eu-west-1|c6gd.medium": 0.043600, + "eu-west-1|c6gd.metal": 2.790400, + "eu-west-1|c6gd.xlarge": 0.174400, + "eu-west-1|c6gn.12xlarge": 2.342400, + "eu-west-1|c6gn.16xlarge": 3.123200, + "eu-west-1|c6gn.2xlarge": 0.390400, + "eu-west-1|c6gn.4xlarge": 0.780800, + "eu-west-1|c6gn.8xlarge": 1.561600, + "eu-west-1|c6gn.large": 0.097600, + "eu-west-1|c6gn.medium": 0.048800, + "eu-west-1|c6gn.xlarge": 0.195200, + "eu-west-1|c6i.12xlarge": 2.188800, + "eu-west-1|c6i.16xlarge": 2.918400, + "eu-west-1|c6i.24xlarge": 4.377600, + "eu-west-1|c6i.2xlarge": 0.364800, + "eu-west-1|c6i.32xlarge": 5.836800, + "eu-west-1|c6i.4xlarge": 0.729600, + "eu-west-1|c6i.8xlarge": 1.459200, + "eu-west-1|c6i.large": 0.091200, + "eu-west-1|c6i.metal": 5.836800, + "eu-west-1|c6i.xlarge": 0.182400, + "eu-west-1|c6id.12xlarge": 2.746800, + "eu-west-1|c6id.16xlarge": 3.662400, + "eu-west-1|c6id.24xlarge": 5.493600, + "eu-west-1|c6id.2xlarge": 0.457800, + "eu-west-1|c6id.32xlarge": 7.324800, + "eu-west-1|c6id.4xlarge": 0.915600, + "eu-west-1|c6id.8xlarge": 1.831200, + "eu-west-1|c6id.large": 0.114450, + "eu-west-1|c6id.metal": 7.324800, + "eu-west-1|c6id.xlarge": 0.228900, + "eu-west-1|c6in.12xlarge": 3.074400, + "eu-west-1|c6in.16xlarge": 4.099200, + "eu-west-1|c6in.24xlarge": 6.148800, + "eu-west-1|c6in.2xlarge": 0.512400, + "eu-west-1|c6in.32xlarge": 8.198400, + "eu-west-1|c6in.4xlarge": 1.024800, + "eu-west-1|c6in.8xlarge": 2.049600, + "eu-west-1|c6in.large": 0.128100, + "eu-west-1|c6in.metal": 8.198400, + "eu-west-1|c6in.xlarge": 0.256200, + "eu-west-1|c7a.12xlarge": 2.642880, + "eu-west-1|c7a.16xlarge": 3.523840, + "eu-west-1|c7a.24xlarge": 5.285760, + "eu-west-1|c7a.2xlarge": 0.440480, + "eu-west-1|c7a.32xlarge": 7.047680, + "eu-west-1|c7a.48xlarge": 10.571520, + "eu-west-1|c7a.4xlarge": 0.880960, + "eu-west-1|c7a.8xlarge": 1.761920, + "eu-west-1|c7a.large": 0.110120, + "eu-west-1|c7a.medium": 0.055060, + "eu-west-1|c7a.metal-48xl": 10.571520, + "eu-west-1|c7a.xlarge": 0.220240, + "eu-west-1|c7g.12xlarge": 1.860500, + "eu-west-1|c7g.16xlarge": 2.480600, + "eu-west-1|c7g.2xlarge": 0.310100, + "eu-west-1|c7g.4xlarge": 0.620200, + "eu-west-1|c7g.8xlarge": 1.240300, + "eu-west-1|c7g.large": 0.077500, + "eu-west-1|c7g.medium": 0.038800, + "eu-west-1|c7g.metal": 2.480600, + "eu-west-1|c7g.xlarge": 0.155000, + "eu-west-1|c7gd.12xlarge": 2.472000, + "eu-west-1|c7gd.16xlarge": 3.296000, + "eu-west-1|c7gd.2xlarge": 0.412000, + "eu-west-1|c7gd.4xlarge": 0.824000, + "eu-west-1|c7gd.8xlarge": 1.648000, + "eu-west-1|c7gd.large": 0.103000, + "eu-west-1|c7gd.medium": 0.051500, + "eu-west-1|c7gd.metal": 3.296000, + "eu-west-1|c7gd.xlarge": 0.206000, + "eu-west-1|c7gn.12xlarge": 3.384000, + "eu-west-1|c7gn.16xlarge": 4.512000, + "eu-west-1|c7gn.2xlarge": 0.564000, + "eu-west-1|c7gn.4xlarge": 1.128000, + "eu-west-1|c7gn.8xlarge": 2.256000, + "eu-west-1|c7gn.large": 0.141000, + "eu-west-1|c7gn.medium": 0.070500, + "eu-west-1|c7gn.metal": 4.512000, + "eu-west-1|c7gn.xlarge": 0.282000, + "eu-west-1|c7i-flex.12xlarge": 2.183330, + "eu-west-1|c7i-flex.16xlarge": 2.911100, + "eu-west-1|c7i-flex.2xlarge": 0.363890, + "eu-west-1|c7i-flex.4xlarge": 0.727780, + "eu-west-1|c7i-flex.8xlarge": 1.455550, + "eu-west-1|c7i-flex.large": 0.090970, + "eu-west-1|c7i-flex.xlarge": 0.181940, + "eu-west-1|c7i.12xlarge": 2.298240, + "eu-west-1|c7i.16xlarge": 3.064320, + "eu-west-1|c7i.24xlarge": 4.596480, + "eu-west-1|c7i.2xlarge": 0.383040, + "eu-west-1|c7i.48xlarge": 9.192960, + "eu-west-1|c7i.4xlarge": 0.766080, + "eu-west-1|c7i.8xlarge": 1.532160, + "eu-west-1|c7i.large": 0.095760, + "eu-west-1|c7i.metal-24xl": 4.596480, + "eu-west-1|c7i.metal-48xl": 9.192960, + "eu-west-1|c7i.xlarge": 0.191520, + "eu-west-1|c8g.12xlarge": 2.046720, + "eu-west-1|c8g.16xlarge": 2.728960, + "eu-west-1|c8g.24xlarge": 4.093440, + "eu-west-1|c8g.2xlarge": 0.341120, + "eu-west-1|c8g.48xlarge": 8.186880, + "eu-west-1|c8g.4xlarge": 0.682240, + "eu-west-1|c8g.8xlarge": 1.364480, + "eu-west-1|c8g.large": 0.085280, + "eu-west-1|c8g.medium": 0.042640, + "eu-west-1|c8g.metal-24xl": 4.093440, + "eu-west-1|c8g.metal-48xl": 8.186880, + "eu-west-1|c8g.xlarge": 0.170560, + "eu-west-1|c8gd.12xlarge": 2.669760, + "eu-west-1|c8gd.16xlarge": 3.559680, + "eu-west-1|c8gd.24xlarge": 5.339520, + "eu-west-1|c8gd.2xlarge": 0.444960, + "eu-west-1|c8gd.48xlarge": 10.679040, + "eu-west-1|c8gd.4xlarge": 0.889920, + "eu-west-1|c8gd.8xlarge": 1.779840, + "eu-west-1|c8gd.large": 0.111240, + "eu-west-1|c8gd.medium": 0.055620, + "eu-west-1|c8gd.metal-24xl": 5.339520, + "eu-west-1|c8gd.metal-48xl": 10.679040, + "eu-west-1|c8gd.xlarge": 0.222480, + "eu-west-1|cr1.8xlarge": 3.750000, + "eu-west-1|d2.2xlarge": 1.470000, + "eu-west-1|d2.4xlarge": 2.940000, + "eu-west-1|d2.8xlarge": 5.880000, + "eu-west-1|d2.xlarge": 0.735000, + "eu-west-1|d3.2xlarge": 1.219000, + "eu-west-1|d3.4xlarge": 2.437000, + "eu-west-1|d3.8xlarge": 4.874480, + "eu-west-1|d3.xlarge": 0.609000, + "eu-west-1|d3en.12xlarge": 7.696560, + "eu-west-1|d3en.2xlarge": 1.283000, + "eu-west-1|d3en.4xlarge": 2.566000, + "eu-west-1|d3en.6xlarge": 3.848000, + "eu-west-1|d3en.8xlarge": 5.131040, + "eu-west-1|d3en.xlarge": 0.641000, + "eu-west-1|f1.16xlarge": 14.520000, + "eu-west-1|f1.2xlarge": 1.815000, + "eu-west-1|f1.4xlarge": 3.630000, + "eu-west-1|g2.2xlarge": 0.702000, + "eu-west-1|g2.8xlarge": 2.808000, + "eu-west-1|g3.16xlarge": 4.840000, + "eu-west-1|g3.4xlarge": 1.210000, + "eu-west-1|g3.8xlarge": 2.420000, + "eu-west-1|g3s.xlarge": 0.796000, + "eu-west-1|g4ad.16xlarge": 3.872000, + "eu-west-1|g4ad.2xlarge": 0.604210, + "eu-west-1|g4ad.4xlarge": 0.968000, + "eu-west-1|g4ad.8xlarge": 1.936000, + "eu-west-1|g4ad.xlarge": 0.422630, + "eu-west-1|g4dn.12xlarge": 4.362000, + "eu-west-1|g4dn.16xlarge": 4.853000, + "eu-west-1|g4dn.2xlarge": 0.838000, + "eu-west-1|g4dn.4xlarge": 1.342000, + "eu-west-1|g4dn.8xlarge": 2.426000, + "eu-west-1|g4dn.metal": 8.724000, + "eu-west-1|g4dn.xlarge": 0.587000, + "eu-west-1|g5.12xlarge": 6.331670, + "eu-west-1|g5.16xlarge": 4.572370, + "eu-west-1|g5.24xlarge": 9.091170, + "eu-west-1|g5.2xlarge": 1.352960, + "eu-west-1|g5.48xlarge": 18.182330, + "eu-west-1|g5.4xlarge": 1.812870, + "eu-west-1|g5.8xlarge": 2.732710, + "eu-west-1|g5.xlarge": 1.123000, + "eu-west-1|h1.16xlarge": 4.152000, + "eu-west-1|h1.2xlarge": 0.519000, + "eu-west-1|h1.4xlarge": 1.038000, + "eu-west-1|h1.8xlarge": 2.076000, + "eu-west-1|hpc7a.12xlarge": 7.725200, + "eu-west-1|hpc7a.24xlarge": 7.725200, + "eu-west-1|hpc7a.48xlarge": 7.725200, + "eu-west-1|hpc7a.96xlarge": 7.725200, + "eu-west-1|hpc7g.16xlarge": 1.805900, + "eu-west-1|hpc7g.4xlarge": 1.805900, + "eu-west-1|hpc7g.8xlarge": 1.805900, + "eu-west-1|i2.2xlarge": 1.876000, + "eu-west-1|i2.4xlarge": 3.751000, + "eu-west-1|i2.8xlarge": 7.502000, + "eu-west-1|i2.xlarge": 0.938000, + "eu-west-1|i3.16xlarge": 5.504000, + "eu-west-1|i3.2xlarge": 0.688000, + "eu-west-1|i3.4xlarge": 1.376000, + "eu-west-1|i3.8xlarge": 2.752000, + "eu-west-1|i3.large": 0.172000, + "eu-west-1|i3.metal": 5.504000, + "eu-west-1|i3.xlarge": 0.344000, + "eu-west-1|i3en.12xlarge": 6.000000, + "eu-west-1|i3en.24xlarge": 12.000000, + "eu-west-1|i3en.2xlarge": 1.000000, + "eu-west-1|i3en.3xlarge": 1.500000, + "eu-west-1|i3en.6xlarge": 3.000000, + "eu-west-1|i3en.large": 0.250000, + "eu-west-1|i3en.metal": 12.000000, + "eu-west-1|i3en.xlarge": 0.500000, + "eu-west-1|i4g.16xlarge": 5.446370, + "eu-west-1|i4g.2xlarge": 0.680800, + "eu-west-1|i4g.4xlarge": 1.361590, + "eu-west-1|i4g.8xlarge": 2.723190, + "eu-west-1|i4g.large": 0.170200, + "eu-west-1|i4g.xlarge": 0.340400, + "eu-west-1|i4i.12xlarge": 4.541000, + "eu-west-1|i4i.16xlarge": 6.054000, + "eu-west-1|i4i.24xlarge": 9.081600, + "eu-west-1|i4i.2xlarge": 0.757000, + "eu-west-1|i4i.32xlarge": 12.108800, + "eu-west-1|i4i.4xlarge": 1.514000, + "eu-west-1|i4i.8xlarge": 3.027000, + "eu-west-1|i4i.large": 0.189000, + "eu-west-1|i4i.metal": 12.109000, + "eu-west-1|i4i.xlarge": 0.378000, + "eu-west-1|i7i.12xlarge": 4.994900, + "eu-west-1|i7i.16xlarge": 6.659800, + "eu-west-1|i7i.24xlarge": 9.989800, + "eu-west-1|i7i.2xlarge": 0.832500, + "eu-west-1|i7i.48xlarge": 19.979500, + "eu-west-1|i7i.4xlarge": 1.665000, + "eu-west-1|i7i.8xlarge": 3.329900, + "eu-west-1|i7i.large": 0.208100, + "eu-west-1|i7i.metal-24xl": 9.989800, + "eu-west-1|i7i.metal-48xl": 19.979500, + "eu-west-1|i7i.xlarge": 0.416200, + "eu-west-1|i7ie.12xlarge": 6.900000, + "eu-west-1|i7ie.18xlarge": 10.350000, + "eu-west-1|i7ie.24xlarge": 13.800000, + "eu-west-1|i7ie.2xlarge": 1.150000, + "eu-west-1|i7ie.3xlarge": 1.725000, + "eu-west-1|i7ie.48xlarge": 27.600000, + "eu-west-1|i7ie.6xlarge": 3.450000, + "eu-west-1|i7ie.large": 0.287500, + "eu-west-1|i7ie.metal-24xl": 13.800000, + "eu-west-1|i7ie.metal-48xl": 27.600000, + "eu-west-1|i7ie.xlarge": 0.575000, + "eu-west-1|i8g.12xlarge": 4.538400, + "eu-west-1|i8g.16xlarge": 6.051200, + "eu-west-1|i8g.24xlarge": 9.076800, + "eu-west-1|i8g.2xlarge": 0.756400, + "eu-west-1|i8g.48xlarge": 18.153600, + "eu-west-1|i8g.4xlarge": 1.512800, + "eu-west-1|i8g.8xlarge": 3.025600, + "eu-west-1|i8g.large": 0.189100, + "eu-west-1|i8g.metal-24xl": 9.076800, + "eu-west-1|i8g.xlarge": 0.378200, + "eu-west-1|im4gn.16xlarge": 6.417660, + "eu-west-1|im4gn.2xlarge": 0.802210, + "eu-west-1|im4gn.4xlarge": 1.604420, + "eu-west-1|im4gn.8xlarge": 3.208830, + "eu-west-1|im4gn.large": 0.200550, + "eu-west-1|im4gn.xlarge": 0.401100, + "eu-west-1|inf1.24xlarge": 5.260000, + "eu-west-1|inf1.2xlarge": 0.403000, + "eu-west-1|inf1.6xlarge": 1.315000, + "eu-west-1|inf1.xlarge": 0.254000, + "eu-west-1|inf2.24xlarge": 8.113290, + "eu-west-1|inf2.48xlarge": 16.226580, + "eu-west-1|inf2.8xlarge": 2.459820, + "eu-west-1|inf2.xlarge": 0.947750, + "eu-west-1|is4gen.2xlarge": 1.275000, + "eu-west-1|is4gen.4xlarge": 2.550000, + "eu-west-1|is4gen.8xlarge": 5.100000, + "eu-west-1|is4gen.large": 0.318750, + "eu-west-1|is4gen.medium": 0.159380, + "eu-west-1|is4gen.xlarge": 0.637500, + "eu-west-1|m1.large": 0.190000, + "eu-west-1|m1.medium": 0.095000, + "eu-west-1|m1.small": 0.047000, + "eu-west-1|m1.xlarge": 0.379000, + "eu-west-1|m2.2xlarge": 0.550000, + "eu-west-1|m2.4xlarge": 1.100000, + "eu-west-1|m2.xlarge": 0.275000, + "eu-west-1|m3.2xlarge": 0.585000, + "eu-west-1|m3.large": 0.146000, + "eu-west-1|m3.medium": 0.073000, + "eu-west-1|m3.xlarge": 0.293000, + "eu-west-1|m4.10xlarge": 2.220000, + "eu-west-1|m4.16xlarge": 3.552000, + "eu-west-1|m4.2xlarge": 0.444000, + "eu-west-1|m4.4xlarge": 0.888000, + "eu-west-1|m4.large": 0.111000, + "eu-west-1|m4.xlarge": 0.222000, + "eu-west-1|m5.12xlarge": 2.568000, + "eu-west-1|m5.16xlarge": 3.424000, + "eu-west-1|m5.24xlarge": 5.136000, + "eu-west-1|m5.2xlarge": 0.428000, + "eu-west-1|m5.4xlarge": 0.856000, + "eu-west-1|m5.8xlarge": 1.712000, + "eu-west-1|m5.large": 0.107000, + "eu-west-1|m5.metal": 5.136000, + "eu-west-1|m5.xlarge": 0.214000, + "eu-west-1|m5a.12xlarge": 2.304000, + "eu-west-1|m5a.16xlarge": 3.072000, + "eu-west-1|m5a.24xlarge": 4.608000, + "eu-west-1|m5a.2xlarge": 0.384000, + "eu-west-1|m5a.4xlarge": 0.768000, + "eu-west-1|m5a.8xlarge": 1.536000, + "eu-west-1|m5a.large": 0.096000, + "eu-west-1|m5a.xlarge": 0.192000, + "eu-west-1|m5ad.12xlarge": 2.760000, + "eu-west-1|m5ad.16xlarge": 3.680000, + "eu-west-1|m5ad.24xlarge": 5.520000, + "eu-west-1|m5ad.2xlarge": 0.460000, + "eu-west-1|m5ad.4xlarge": 0.920000, + "eu-west-1|m5ad.8xlarge": 1.840000, + "eu-west-1|m5ad.large": 0.115000, + "eu-west-1|m5ad.xlarge": 0.230000, + "eu-west-1|m5d.12xlarge": 3.024000, + "eu-west-1|m5d.16xlarge": 4.032000, + "eu-west-1|m5d.24xlarge": 6.048000, + "eu-west-1|m5d.2xlarge": 0.504000, + "eu-west-1|m5d.4xlarge": 1.008000, + "eu-west-1|m5d.8xlarge": 2.016000, + "eu-west-1|m5d.large": 0.126000, + "eu-west-1|m5d.metal": 6.048000, + "eu-west-1|m5d.xlarge": 0.252000, + "eu-west-1|m5dn.12xlarge": 3.648000, + "eu-west-1|m5dn.16xlarge": 4.864000, + "eu-west-1|m5dn.24xlarge": 7.296000, + "eu-west-1|m5dn.2xlarge": 0.608000, + "eu-west-1|m5dn.4xlarge": 1.216000, + "eu-west-1|m5dn.8xlarge": 2.432000, + "eu-west-1|m5dn.large": 0.152000, + "eu-west-1|m5dn.metal": 7.296000, + "eu-west-1|m5dn.xlarge": 0.304000, + "eu-west-1|m5n.12xlarge": 3.192000, + "eu-west-1|m5n.16xlarge": 4.256000, + "eu-west-1|m5n.24xlarge": 6.384000, + "eu-west-1|m5n.2xlarge": 0.532000, + "eu-west-1|m5n.4xlarge": 1.064000, + "eu-west-1|m5n.8xlarge": 2.128000, + "eu-west-1|m5n.large": 0.133000, + "eu-west-1|m5n.metal": 6.384000, + "eu-west-1|m5n.xlarge": 0.266000, + "eu-west-1|m5zn.12xlarge": 4.418400, + "eu-west-1|m5zn.2xlarge": 0.736400, + "eu-west-1|m5zn.3xlarge": 1.104600, + "eu-west-1|m5zn.6xlarge": 2.209200, + "eu-west-1|m5zn.large": 0.184100, + "eu-west-1|m5zn.metal": 4.418400, + "eu-west-1|m5zn.xlarge": 0.368200, + "eu-west-1|m6a.12xlarge": 2.311200, + "eu-west-1|m6a.16xlarge": 3.081600, + "eu-west-1|m6a.24xlarge": 4.622400, + "eu-west-1|m6a.2xlarge": 0.385200, + "eu-west-1|m6a.32xlarge": 6.163200, + "eu-west-1|m6a.48xlarge": 9.244800, + "eu-west-1|m6a.4xlarge": 0.770400, + "eu-west-1|m6a.8xlarge": 1.540800, + "eu-west-1|m6a.large": 0.096300, + "eu-west-1|m6a.metal": 9.244800, + "eu-west-1|m6a.xlarge": 0.192600, + "eu-west-1|m6g.12xlarge": 2.064000, + "eu-west-1|m6g.16xlarge": 2.752000, + "eu-west-1|m6g.2xlarge": 0.344000, + "eu-west-1|m6g.4xlarge": 0.688000, + "eu-west-1|m6g.8xlarge": 1.376000, + "eu-west-1|m6g.large": 0.086000, + "eu-west-1|m6g.medium": 0.043000, + "eu-west-1|m6g.metal": 2.752000, + "eu-west-1|m6g.xlarge": 0.172000, + "eu-west-1|m6gd.12xlarge": 2.419200, + "eu-west-1|m6gd.16xlarge": 3.225600, + "eu-west-1|m6gd.2xlarge": 0.403200, + "eu-west-1|m6gd.4xlarge": 0.806400, + "eu-west-1|m6gd.8xlarge": 1.612800, + "eu-west-1|m6gd.large": 0.100800, + "eu-west-1|m6gd.medium": 0.050400, + "eu-west-1|m6gd.metal": 3.225600, + "eu-west-1|m6gd.xlarge": 0.201600, + "eu-west-1|m6i.12xlarge": 2.568000, + "eu-west-1|m6i.16xlarge": 3.424000, + "eu-west-1|m6i.24xlarge": 5.136000, + "eu-west-1|m6i.2xlarge": 0.428000, + "eu-west-1|m6i.32xlarge": 6.848000, + "eu-west-1|m6i.4xlarge": 0.856000, + "eu-west-1|m6i.8xlarge": 1.712000, + "eu-west-1|m6i.large": 0.107000, + "eu-west-1|m6i.metal": 6.848000, + "eu-west-1|m6i.xlarge": 0.214000, + "eu-west-1|m6id.12xlarge": 3.175200, + "eu-west-1|m6id.16xlarge": 4.233600, + "eu-west-1|m6id.24xlarge": 6.350400, + "eu-west-1|m6id.2xlarge": 0.529200, + "eu-west-1|m6id.32xlarge": 8.467200, + "eu-west-1|m6id.4xlarge": 1.058400, + "eu-west-1|m6id.8xlarge": 2.116800, + "eu-west-1|m6id.large": 0.132300, + "eu-west-1|m6id.metal": 8.467200, + "eu-west-1|m6id.xlarge": 0.264600, + "eu-west-1|m6idn.12xlarge": 4.268160, + "eu-west-1|m6idn.16xlarge": 5.690880, + "eu-west-1|m6idn.24xlarge": 8.536320, + "eu-west-1|m6idn.2xlarge": 0.711360, + "eu-west-1|m6idn.32xlarge": 11.381760, + "eu-west-1|m6idn.4xlarge": 1.422720, + "eu-west-1|m6idn.8xlarge": 2.845440, + "eu-west-1|m6idn.large": 0.177840, + "eu-west-1|m6idn.metal": 11.381760, + "eu-west-1|m6idn.xlarge": 0.355680, + "eu-west-1|m6in.12xlarge": 3.734640, + "eu-west-1|m6in.16xlarge": 4.979520, + "eu-west-1|m6in.24xlarge": 7.469280, + "eu-west-1|m6in.2xlarge": 0.622440, + "eu-west-1|m6in.32xlarge": 9.959040, + "eu-west-1|m6in.4xlarge": 1.244880, + "eu-west-1|m6in.8xlarge": 2.489760, + "eu-west-1|m6in.large": 0.155610, + "eu-west-1|m6in.metal": 9.959040, + "eu-west-1|m6in.xlarge": 0.311220, + "eu-west-1|m7a.12xlarge": 3.100800, + "eu-west-1|m7a.16xlarge": 4.134400, + "eu-west-1|m7a.24xlarge": 6.201600, + "eu-west-1|m7a.2xlarge": 0.516800, + "eu-west-1|m7a.32xlarge": 8.268800, + "eu-west-1|m7a.48xlarge": 12.403200, + "eu-west-1|m7a.4xlarge": 1.033600, + "eu-west-1|m7a.8xlarge": 2.067200, + "eu-west-1|m7a.large": 0.129200, + "eu-west-1|m7a.medium": 0.064600, + "eu-west-1|m7a.metal-48xl": 12.403200, + "eu-west-1|m7a.xlarge": 0.258400, + "eu-west-1|m7g.12xlarge": 2.182800, + "eu-west-1|m7g.16xlarge": 2.910400, + "eu-west-1|m7g.2xlarge": 0.363800, + "eu-west-1|m7g.4xlarge": 0.727600, + "eu-west-1|m7g.8xlarge": 1.455200, + "eu-west-1|m7g.large": 0.091000, + "eu-west-1|m7g.medium": 0.045500, + "eu-west-1|m7g.metal": 2.910400, + "eu-west-1|m7g.xlarge": 0.181900, + "eu-west-1|m7gd.12xlarge": 2.857700, + "eu-west-1|m7gd.16xlarge": 3.810200, + "eu-west-1|m7gd.2xlarge": 0.476300, + "eu-west-1|m7gd.4xlarge": 0.952600, + "eu-west-1|m7gd.8xlarge": 1.905100, + "eu-west-1|m7gd.large": 0.119100, + "eu-west-1|m7gd.medium": 0.059500, + "eu-west-1|m7gd.metal": 3.810200, + "eu-west-1|m7gd.xlarge": 0.238100, + "eu-west-1|m7i-flex.12xlarge": 2.561520, + "eu-west-1|m7i-flex.16xlarge": 3.415360, + "eu-west-1|m7i-flex.2xlarge": 0.426920, + "eu-west-1|m7i-flex.4xlarge": 0.853840, + "eu-west-1|m7i-flex.8xlarge": 1.707680, + "eu-west-1|m7i-flex.large": 0.106730, + "eu-west-1|m7i-flex.xlarge": 0.213460, + "eu-west-1|m7i.12xlarge": 2.696400, + "eu-west-1|m7i.16xlarge": 3.595200, + "eu-west-1|m7i.24xlarge": 5.392800, + "eu-west-1|m7i.2xlarge": 0.449400, + "eu-west-1|m7i.48xlarge": 10.785600, + "eu-west-1|m7i.4xlarge": 0.898800, + "eu-west-1|m7i.8xlarge": 1.797600, + "eu-west-1|m7i.large": 0.112350, + "eu-west-1|m7i.metal-24xl": 5.392800, + "eu-west-1|m7i.metal-48xl": 10.785600, + "eu-west-1|m7i.xlarge": 0.224700, + "eu-west-1|m8g.12xlarge": 2.400960, + "eu-west-1|m8g.16xlarge": 3.201280, + "eu-west-1|m8g.24xlarge": 4.801920, + "eu-west-1|m8g.2xlarge": 0.400160, + "eu-west-1|m8g.48xlarge": 9.603840, + "eu-west-1|m8g.4xlarge": 0.800320, + "eu-west-1|m8g.8xlarge": 1.600640, + "eu-west-1|m8g.large": 0.100040, + "eu-west-1|m8g.medium": 0.050020, + "eu-west-1|m8g.metal-24xl": 4.801920, + "eu-west-1|m8g.metal-48xl": 9.603840, + "eu-west-1|m8g.xlarge": 0.200080, + "eu-west-1|p2.16xlarge": 15.552000, + "eu-west-1|p2.8xlarge": 7.776000, + "eu-west-1|p2.xlarge": 0.972000, + "eu-west-1|p3.16xlarge": 26.440000, + "eu-west-1|p3.2xlarge": 3.305000, + "eu-west-1|p3.8xlarge": 13.220000, + "eu-west-1|p3dn.24xlarge": 33.711000, + "eu-west-1|p4d.24xlarge": 23.715690, + "eu-west-1|r3.2xlarge": 0.741000, + "eu-west-1|r3.4xlarge": 1.482000, + "eu-west-1|r3.8xlarge": 2.964000, + "eu-west-1|r3.large": 0.185000, + "eu-west-1|r3.xlarge": 0.371000, + "eu-west-1|r4.16xlarge": 4.742400, + "eu-west-1|r4.2xlarge": 0.592800, + "eu-west-1|r4.4xlarge": 1.185600, + "eu-west-1|r4.8xlarge": 2.371200, + "eu-west-1|r4.large": 0.148200, + "eu-west-1|r4.xlarge": 0.296400, + "eu-west-1|r5.12xlarge": 3.384000, + "eu-west-1|r5.16xlarge": 4.512000, + "eu-west-1|r5.24xlarge": 6.768000, + "eu-west-1|r5.2xlarge": 0.564000, + "eu-west-1|r5.4xlarge": 1.128000, + "eu-west-1|r5.8xlarge": 2.256000, + "eu-west-1|r5.large": 0.141000, + "eu-west-1|r5.metal": 6.768000, + "eu-west-1|r5.xlarge": 0.282000, + "eu-west-1|r5a.12xlarge": 3.048000, + "eu-west-1|r5a.16xlarge": 4.064000, + "eu-west-1|r5a.24xlarge": 6.096000, + "eu-west-1|r5a.2xlarge": 0.508000, + "eu-west-1|r5a.4xlarge": 1.016000, + "eu-west-1|r5a.8xlarge": 2.032000, + "eu-west-1|r5a.large": 0.127000, + "eu-west-1|r5a.xlarge": 0.254000, + "eu-west-1|r5ad.12xlarge": 3.504000, + "eu-west-1|r5ad.16xlarge": 4.672000, + "eu-west-1|r5ad.24xlarge": 7.008000, + "eu-west-1|r5ad.2xlarge": 0.584000, + "eu-west-1|r5ad.4xlarge": 1.168000, + "eu-west-1|r5ad.8xlarge": 2.336000, + "eu-west-1|r5ad.large": 0.146000, + "eu-west-1|r5ad.xlarge": 0.292000, + "eu-west-1|r5b.12xlarge": 4.008000, + "eu-west-1|r5b.16xlarge": 5.344000, + "eu-west-1|r5b.24xlarge": 8.016000, + "eu-west-1|r5b.2xlarge": 0.668000, + "eu-west-1|r5b.4xlarge": 1.336000, + "eu-west-1|r5b.8xlarge": 2.672000, + "eu-west-1|r5b.large": 0.167000, + "eu-west-1|r5b.metal": 8.016000, + "eu-west-1|r5b.xlarge": 0.334000, + "eu-west-1|r5d.12xlarge": 3.840000, + "eu-west-1|r5d.16xlarge": 5.120000, + "eu-west-1|r5d.24xlarge": 7.680000, + "eu-west-1|r5d.2xlarge": 0.640000, + "eu-west-1|r5d.4xlarge": 1.280000, + "eu-west-1|r5d.8xlarge": 2.560000, + "eu-west-1|r5d.large": 0.160000, + "eu-west-1|r5d.metal": 7.680000, + "eu-west-1|r5d.xlarge": 0.320000, + "eu-west-1|r5dn.12xlarge": 4.464000, + "eu-west-1|r5dn.16xlarge": 5.952000, + "eu-west-1|r5dn.24xlarge": 8.928000, + "eu-west-1|r5dn.2xlarge": 0.744000, + "eu-west-1|r5dn.4xlarge": 1.488000, + "eu-west-1|r5dn.8xlarge": 2.976000, + "eu-west-1|r5dn.large": 0.186000, + "eu-west-1|r5dn.metal": 8.928000, + "eu-west-1|r5dn.xlarge": 0.372000, + "eu-west-1|r5n.12xlarge": 4.008000, + "eu-west-1|r5n.16xlarge": 5.344000, + "eu-west-1|r5n.24xlarge": 8.016000, + "eu-west-1|r5n.2xlarge": 0.668000, + "eu-west-1|r5n.4xlarge": 1.336000, + "eu-west-1|r5n.8xlarge": 2.672000, + "eu-west-1|r5n.large": 0.167000, + "eu-west-1|r5n.metal": 8.016000, + "eu-west-1|r5n.xlarge": 0.334000, + "eu-west-1|r6a.12xlarge": 3.045600, + "eu-west-1|r6a.16xlarge": 4.060800, + "eu-west-1|r6a.24xlarge": 6.091200, + "eu-west-1|r6a.2xlarge": 0.507600, + "eu-west-1|r6a.32xlarge": 8.121600, + "eu-west-1|r6a.48xlarge": 12.182400, + "eu-west-1|r6a.4xlarge": 1.015200, + "eu-west-1|r6a.8xlarge": 2.030400, + "eu-west-1|r6a.large": 0.126900, + "eu-west-1|r6a.metal": 12.182400, + "eu-west-1|r6a.xlarge": 0.253800, + "eu-west-1|r6g.12xlarge": 2.707200, + "eu-west-1|r6g.16xlarge": 3.609600, + "eu-west-1|r6g.2xlarge": 0.451200, + "eu-west-1|r6g.4xlarge": 0.902400, + "eu-west-1|r6g.8xlarge": 1.804800, + "eu-west-1|r6g.large": 0.112800, + "eu-west-1|r6g.medium": 0.056400, + "eu-west-1|r6g.metal": 3.609600, + "eu-west-1|r6g.xlarge": 0.225600, + "eu-west-1|r6gd.12xlarge": 3.072000, + "eu-west-1|r6gd.16xlarge": 4.096000, + "eu-west-1|r6gd.2xlarge": 0.512000, + "eu-west-1|r6gd.4xlarge": 1.024000, + "eu-west-1|r6gd.8xlarge": 2.048000, + "eu-west-1|r6gd.large": 0.128000, + "eu-west-1|r6gd.medium": 0.064000, + "eu-west-1|r6gd.metal": 4.096000, + "eu-west-1|r6gd.xlarge": 0.256000, + "eu-west-1|r6i.12xlarge": 3.384000, + "eu-west-1|r6i.16xlarge": 4.512000, + "eu-west-1|r6i.24xlarge": 6.768000, + "eu-west-1|r6i.2xlarge": 0.564000, + "eu-west-1|r6i.32xlarge": 9.024000, + "eu-west-1|r6i.4xlarge": 1.128000, + "eu-west-1|r6i.8xlarge": 2.256000, + "eu-west-1|r6i.large": 0.141000, + "eu-west-1|r6i.metal": 9.024000, + "eu-west-1|r6i.xlarge": 0.282000, + "eu-west-1|r6id.12xlarge": 4.032000, + "eu-west-1|r6id.16xlarge": 5.376000, + "eu-west-1|r6id.24xlarge": 8.064000, + "eu-west-1|r6id.2xlarge": 0.672000, + "eu-west-1|r6id.32xlarge": 10.752000, + "eu-west-1|r6id.4xlarge": 1.344000, + "eu-west-1|r6id.8xlarge": 2.688000, + "eu-west-1|r6id.large": 0.168000, + "eu-west-1|r6id.metal": 10.752000, + "eu-west-1|r6id.xlarge": 0.336000, + "eu-west-1|r6idn.12xlarge": 5.222880, + "eu-west-1|r6idn.16xlarge": 6.963840, + "eu-west-1|r6idn.24xlarge": 10.445760, + "eu-west-1|r6idn.2xlarge": 0.870480, + "eu-west-1|r6idn.32xlarge": 13.927680, + "eu-west-1|r6idn.4xlarge": 1.740960, + "eu-west-1|r6idn.8xlarge": 3.481920, + "eu-west-1|r6idn.large": 0.217620, + "eu-west-1|r6idn.metal": 13.927680, + "eu-west-1|r6idn.xlarge": 0.435240, + "eu-west-1|r6in.12xlarge": 4.689360, + "eu-west-1|r6in.16xlarge": 6.252480, + "eu-west-1|r6in.24xlarge": 9.378720, + "eu-west-1|r6in.2xlarge": 0.781560, + "eu-west-1|r6in.32xlarge": 12.504960, + "eu-west-1|r6in.4xlarge": 1.563120, + "eu-west-1|r6in.8xlarge": 3.126240, + "eu-west-1|r6in.large": 0.195390, + "eu-west-1|r6in.metal": 12.504960, + "eu-west-1|r6in.xlarge": 0.390780, + "eu-west-1|r7a.12xlarge": 4.086240, + "eu-west-1|r7a.16xlarge": 5.448320, + "eu-west-1|r7a.24xlarge": 8.172480, + "eu-west-1|r7a.2xlarge": 0.681040, + "eu-west-1|r7a.32xlarge": 10.896640, + "eu-west-1|r7a.48xlarge": 16.344960, + "eu-west-1|r7a.4xlarge": 1.362080, + "eu-west-1|r7a.8xlarge": 2.724160, + "eu-west-1|r7a.large": 0.170260, + "eu-west-1|r7a.medium": 0.085130, + "eu-west-1|r7a.metal-48xl": 16.344960, + "eu-west-1|r7a.xlarge": 0.340520, + "eu-west-1|r7g.12xlarge": 2.876400, + "eu-west-1|r7g.16xlarge": 3.835200, + "eu-west-1|r7g.2xlarge": 0.479400, + "eu-west-1|r7g.4xlarge": 0.958800, + "eu-west-1|r7g.8xlarge": 1.917600, + "eu-west-1|r7g.large": 0.119900, + "eu-west-1|r7g.medium": 0.059900, + "eu-west-1|r7g.metal": 3.835200, + "eu-west-1|r7g.xlarge": 0.239700, + "eu-west-1|r7gd.12xlarge": 3.628800, + "eu-west-1|r7gd.16xlarge": 4.838400, + "eu-west-1|r7gd.2xlarge": 0.604800, + "eu-west-1|r7gd.4xlarge": 1.209600, + "eu-west-1|r7gd.8xlarge": 2.419200, + "eu-west-1|r7gd.large": 0.151200, + "eu-west-1|r7gd.medium": 0.075600, + "eu-west-1|r7gd.metal": 4.838400, + "eu-west-1|r7gd.xlarge": 0.302400, + "eu-west-1|r7i.12xlarge": 3.553200, + "eu-west-1|r7i.16xlarge": 4.737600, + "eu-west-1|r7i.24xlarge": 7.106400, + "eu-west-1|r7i.2xlarge": 0.592200, + "eu-west-1|r7i.48xlarge": 14.212800, + "eu-west-1|r7i.4xlarge": 1.184400, + "eu-west-1|r7i.8xlarge": 2.368800, + "eu-west-1|r7i.large": 0.148050, + "eu-west-1|r7i.metal-24xl": 7.106400, + "eu-west-1|r7i.metal-48xl": 14.212800, + "eu-west-1|r7i.xlarge": 0.296100, + "eu-west-1|r7iz.12xlarge": 4.992000, + "eu-west-1|r7iz.16xlarge": 6.656000, + "eu-west-1|r7iz.2xlarge": 0.832000, + "eu-west-1|r7iz.32xlarge": 13.312000, + "eu-west-1|r7iz.4xlarge": 1.664000, + "eu-west-1|r7iz.8xlarge": 3.328000, + "eu-west-1|r7iz.large": 0.208000, + "eu-west-1|r7iz.metal-16xl": 6.656000, + "eu-west-1|r7iz.metal-32xl": 13.312000, + "eu-west-1|r7iz.xlarge": 0.416000, + "eu-west-1|r8g.12xlarge": 3.164160, + "eu-west-1|r8g.16xlarge": 4.218880, + "eu-west-1|r8g.24xlarge": 6.328320, + "eu-west-1|r8g.2xlarge": 0.527360, + "eu-west-1|r8g.48xlarge": 12.656640, + "eu-west-1|r8g.4xlarge": 1.054720, + "eu-west-1|r8g.8xlarge": 2.109440, + "eu-west-1|r8g.large": 0.131840, + "eu-west-1|r8g.medium": 0.065920, + "eu-west-1|r8g.metal-24xl": 6.328320, + "eu-west-1|r8g.metal-48xl": 12.656640, + "eu-west-1|r8g.xlarge": 0.263680, + "eu-west-1|r8gd.12xlarge": 3.919200, + "eu-west-1|r8gd.16xlarge": 5.225600, + "eu-west-1|r8gd.24xlarge": 7.838400, + "eu-west-1|r8gd.2xlarge": 0.653200, + "eu-west-1|r8gd.48xlarge": 15.676800, + "eu-west-1|r8gd.4xlarge": 1.306400, + "eu-west-1|r8gd.8xlarge": 2.612800, + "eu-west-1|r8gd.large": 0.163300, + "eu-west-1|r8gd.medium": 0.081650, + "eu-west-1|r8gd.metal-24xl": 7.838400, + "eu-west-1|r8gd.metal-48xl": 15.676800, + "eu-west-1|r8gd.xlarge": 0.326600, + "eu-west-1|t1.micro": 0.020000, + "eu-west-1|t2.2xlarge": 0.403200, + "eu-west-1|t2.large": 0.100800, + "eu-west-1|t2.medium": 0.050000, + "eu-west-1|t2.micro": 0.012600, + "eu-west-1|t2.nano": 0.006300, + "eu-west-1|t2.small": 0.025000, + "eu-west-1|t2.xlarge": 0.201600, + "eu-west-1|t3.2xlarge": 0.364800, + "eu-west-1|t3.large": 0.091200, + "eu-west-1|t3.medium": 0.045600, + "eu-west-1|t3.micro": 0.011400, + "eu-west-1|t3.nano": 0.005700, + "eu-west-1|t3.small": 0.022800, + "eu-west-1|t3.xlarge": 0.182400, + "eu-west-1|t3a.2xlarge": 0.326400, + "eu-west-1|t3a.large": 0.081600, + "eu-west-1|t3a.medium": 0.040800, + "eu-west-1|t3a.micro": 0.010200, + "eu-west-1|t3a.nano": 0.005100, + "eu-west-1|t3a.small": 0.020400, + "eu-west-1|t3a.xlarge": 0.163200, + "eu-west-1|t4g.2xlarge": 0.294400, + "eu-west-1|t4g.large": 0.073600, + "eu-west-1|t4g.medium": 0.036800, + "eu-west-1|t4g.micro": 0.009200, + "eu-west-1|t4g.nano": 0.004600, + "eu-west-1|t4g.small": 0.018400, + "eu-west-1|t4g.xlarge": 0.147200, + "eu-west-1|u-12tb1.112xlarge": 122.200000, + "eu-west-1|u-18tb1.112xlarge": 183.300000, + "eu-west-1|u-24tb1.112xlarge": 244.400000, + "eu-west-1|u-3tb1.56xlarge": 30.550000, + "eu-west-1|u-6tb1.112xlarge": 61.100000, + "eu-west-1|u-6tb1.56xlarge": 51.928180, + "eu-west-1|u-9tb1.112xlarge": 91.650000, + "eu-west-1|u7i-12tb.224xlarge": 140.532190, + "eu-west-1|u7i-6tb.112xlarge": 70.265000, + "eu-west-1|u7i-8tb.112xlarge": 93.686660, + "eu-west-1|u7in-16tb.224xlarge": 201.960770, + "eu-west-1|vt1.24xlarge": 5.872940, + "eu-west-1|vt1.3xlarge": 0.734120, + "eu-west-1|vt1.6xlarge": 1.468240, + "eu-west-1|x1.16xlarge": 8.003000, + "eu-west-1|x1.32xlarge": 16.006000, + "eu-west-1|x1e.16xlarge": 16.000000, + "eu-west-1|x1e.2xlarge": 2.000000, + "eu-west-1|x1e.32xlarge": 32.000000, + "eu-west-1|x1e.4xlarge": 4.000000, + "eu-west-1|x1e.8xlarge": 8.000000, + "eu-west-1|x1e.xlarge": 1.000000, + "eu-west-1|x2gd.12xlarge": 4.800000, + "eu-west-1|x2gd.16xlarge": 6.400000, + "eu-west-1|x2gd.2xlarge": 0.800000, + "eu-west-1|x2gd.4xlarge": 1.600000, + "eu-west-1|x2gd.8xlarge": 3.200000, + "eu-west-1|x2gd.large": 0.200000, + "eu-west-1|x2gd.medium": 0.100000, + "eu-west-1|x2gd.metal": 6.400000, + "eu-west-1|x2gd.xlarge": 0.400000, + "eu-west-1|x2idn.16xlarge": 8.003000, + "eu-west-1|x2idn.24xlarge": 12.004500, + "eu-west-1|x2idn.32xlarge": 16.006000, + "eu-west-1|x2idn.metal": 16.006000, + "eu-west-1|x2iedn.16xlarge": 16.006000, + "eu-west-1|x2iedn.24xlarge": 24.009000, + "eu-west-1|x2iedn.2xlarge": 2.000750, + "eu-west-1|x2iedn.32xlarge": 32.012000, + "eu-west-1|x2iedn.4xlarge": 4.001500, + "eu-west-1|x2iedn.8xlarge": 8.003000, + "eu-west-1|x2iedn.metal": 32.012000, + "eu-west-1|x2iedn.xlarge": 1.000380, + "eu-west-1|x2iezn.12xlarge": 12.000000, + "eu-west-1|x2iezn.2xlarge": 2.000000, + "eu-west-1|x2iezn.4xlarge": 4.000000, + "eu-west-1|x2iezn.6xlarge": 6.000000, + "eu-west-1|x2iezn.8xlarge": 8.000000, + "eu-west-1|x2iezn.metal": 12.000000, + "eu-west-1|z1d.12xlarge": 4.992000, + "eu-west-1|z1d.2xlarge": 0.832000, + "eu-west-1|z1d.3xlarge": 1.248000, + "eu-west-1|z1d.6xlarge": 2.496000, + "eu-west-1|z1d.large": 0.208000, + "eu-west-1|z1d.metal": 4.992000, + "eu-west-1|z1d.xlarge": 0.416000, + "eu-west-2|c4.2xlarge": 0.476000, + "eu-west-2|c4.4xlarge": 0.950000, + "eu-west-2|c4.8xlarge": 1.902000, + "eu-west-2|c4.large": 0.119000, + "eu-west-2|c4.xlarge": 0.237000, + "eu-west-2|c5.12xlarge": 2.424000, + "eu-west-2|c5.18xlarge": 3.636000, + "eu-west-2|c5.24xlarge": 4.848000, + "eu-west-2|c5.2xlarge": 0.404000, + "eu-west-2|c5.4xlarge": 0.808000, + "eu-west-2|c5.9xlarge": 1.818000, + "eu-west-2|c5.large": 0.101000, + "eu-west-2|c5.metal": 4.848000, + "eu-west-2|c5.xlarge": 0.202000, + "eu-west-2|c5a.12xlarge": 2.184000, + "eu-west-2|c5a.16xlarge": 2.912000, + "eu-west-2|c5a.24xlarge": 4.368000, + "eu-west-2|c5a.2xlarge": 0.364000, + "eu-west-2|c5a.4xlarge": 0.728000, + "eu-west-2|c5a.8xlarge": 1.456000, + "eu-west-2|c5a.large": 0.091000, + "eu-west-2|c5a.xlarge": 0.182000, + "eu-west-2|c5d.12xlarge": 2.760000, + "eu-west-2|c5d.18xlarge": 4.140000, + "eu-west-2|c5d.24xlarge": 5.520000, + "eu-west-2|c5d.2xlarge": 0.460000, + "eu-west-2|c5d.4xlarge": 0.920000, + "eu-west-2|c5d.9xlarge": 2.070000, + "eu-west-2|c5d.large": 0.115000, + "eu-west-2|c5d.metal": 5.520000, + "eu-west-2|c5d.xlarge": 0.230000, + "eu-west-2|c5n.18xlarge": 4.608000, + "eu-west-2|c5n.2xlarge": 0.512000, + "eu-west-2|c5n.4xlarge": 1.024000, + "eu-west-2|c5n.9xlarge": 2.304000, + "eu-west-2|c5n.large": 0.128000, + "eu-west-2|c5n.metal": 4.608000, + "eu-west-2|c5n.xlarge": 0.256000, + "eu-west-2|c6a.12xlarge": 2.181600, + "eu-west-2|c6a.16xlarge": 2.908800, + "eu-west-2|c6a.24xlarge": 4.363200, + "eu-west-2|c6a.2xlarge": 0.363600, + "eu-west-2|c6a.32xlarge": 5.817600, + "eu-west-2|c6a.48xlarge": 8.726400, + "eu-west-2|c6a.4xlarge": 0.727200, + "eu-west-2|c6a.8xlarge": 1.454400, + "eu-west-2|c6a.large": 0.090900, + "eu-west-2|c6a.metal": 8.726400, + "eu-west-2|c6a.xlarge": 0.181800, + "eu-west-2|c6g.12xlarge": 1.939200, + "eu-west-2|c6g.16xlarge": 2.585600, + "eu-west-2|c6g.2xlarge": 0.323200, + "eu-west-2|c6g.4xlarge": 0.646400, + "eu-west-2|c6g.8xlarge": 1.292800, + "eu-west-2|c6g.large": 0.080800, + "eu-west-2|c6g.medium": 0.040400, + "eu-west-2|c6g.metal": 2.585600, + "eu-west-2|c6g.xlarge": 0.161600, + "eu-west-2|c6gd.12xlarge": 2.208000, + "eu-west-2|c6gd.16xlarge": 2.944000, + "eu-west-2|c6gd.2xlarge": 0.368000, + "eu-west-2|c6gd.4xlarge": 0.736000, + "eu-west-2|c6gd.8xlarge": 1.472000, + "eu-west-2|c6gd.large": 0.092000, + "eu-west-2|c6gd.medium": 0.046000, + "eu-west-2|c6gd.metal": 2.944000, + "eu-west-2|c6gd.xlarge": 0.184000, + "eu-west-2|c6gn.12xlarge": 2.460000, + "eu-west-2|c6gn.16xlarge": 3.280000, + "eu-west-2|c6gn.2xlarge": 0.410000, + "eu-west-2|c6gn.4xlarge": 0.820000, + "eu-west-2|c6gn.8xlarge": 1.640000, + "eu-west-2|c6gn.large": 0.102500, + "eu-west-2|c6gn.medium": 0.051250, + "eu-west-2|c6gn.xlarge": 0.205000, + "eu-west-2|c6i.12xlarge": 2.424000, + "eu-west-2|c6i.16xlarge": 3.232000, + "eu-west-2|c6i.24xlarge": 4.848000, + "eu-west-2|c6i.2xlarge": 0.404000, + "eu-west-2|c6i.32xlarge": 6.464000, + "eu-west-2|c6i.4xlarge": 0.808000, + "eu-west-2|c6i.8xlarge": 1.616000, + "eu-west-2|c6i.large": 0.101000, + "eu-west-2|c6i.metal": 6.464000, + "eu-west-2|c6i.xlarge": 0.202000, + "eu-west-2|c6id.12xlarge": 2.898000, + "eu-west-2|c6id.16xlarge": 3.864000, + "eu-west-2|c6id.24xlarge": 5.796000, + "eu-west-2|c6id.2xlarge": 0.483000, + "eu-west-2|c6id.32xlarge": 7.728000, + "eu-west-2|c6id.4xlarge": 0.966000, + "eu-west-2|c6id.8xlarge": 1.932000, + "eu-west-2|c6id.large": 0.120750, + "eu-west-2|c6id.metal": 7.728000, + "eu-west-2|c6id.xlarge": 0.241500, + "eu-west-2|c6in.12xlarge": 3.225600, + "eu-west-2|c6in.16xlarge": 4.300800, + "eu-west-2|c6in.24xlarge": 6.451200, + "eu-west-2|c6in.2xlarge": 0.537600, + "eu-west-2|c6in.32xlarge": 8.601600, + "eu-west-2|c6in.4xlarge": 1.075200, + "eu-west-2|c6in.8xlarge": 2.150400, + "eu-west-2|c6in.large": 0.134400, + "eu-west-2|c6in.metal": 8.601600, + "eu-west-2|c6in.xlarge": 0.268800, + "eu-west-2|c7a.12xlarge": 2.927040, + "eu-west-2|c7a.16xlarge": 3.902720, + "eu-west-2|c7a.24xlarge": 5.854080, + "eu-west-2|c7a.2xlarge": 0.487840, + "eu-west-2|c7a.32xlarge": 7.805440, + "eu-west-2|c7a.48xlarge": 11.708160, + "eu-west-2|c7a.4xlarge": 0.975680, + "eu-west-2|c7a.8xlarge": 1.951360, + "eu-west-2|c7a.large": 0.121960, + "eu-west-2|c7a.medium": 0.060980, + "eu-west-2|c7a.metal-48xl": 11.708160, + "eu-west-2|c7a.xlarge": 0.243920, + "eu-west-2|c7g.12xlarge": 2.060600, + "eu-west-2|c7g.16xlarge": 2.747500, + "eu-west-2|c7g.2xlarge": 0.343400, + "eu-west-2|c7g.4xlarge": 0.686900, + "eu-west-2|c7g.8xlarge": 1.373800, + "eu-west-2|c7g.large": 0.085900, + "eu-west-2|c7g.medium": 0.042900, + "eu-west-2|c7g.metal": 2.747500, + "eu-west-2|c7g.xlarge": 0.171700, + "eu-west-2|c7gd.12xlarge": 2.608300, + "eu-west-2|c7gd.16xlarge": 3.477800, + "eu-west-2|c7gd.2xlarge": 0.434700, + "eu-west-2|c7gd.4xlarge": 0.869400, + "eu-west-2|c7gd.8xlarge": 1.738900, + "eu-west-2|c7gd.large": 0.108700, + "eu-west-2|c7gd.medium": 0.054300, + "eu-west-2|c7gd.metal": 3.477800, + "eu-west-2|c7gd.xlarge": 0.217400, + "eu-west-2|c7i-flex.12xlarge": 2.417940, + "eu-west-2|c7i-flex.16xlarge": 3.223920, + "eu-west-2|c7i-flex.2xlarge": 0.402990, + "eu-west-2|c7i-flex.4xlarge": 0.805980, + "eu-west-2|c7i-flex.8xlarge": 1.611960, + "eu-west-2|c7i-flex.large": 0.100750, + "eu-west-2|c7i-flex.xlarge": 0.201500, + "eu-west-2|c7i.12xlarge": 2.545200, + "eu-west-2|c7i.16xlarge": 3.393600, + "eu-west-2|c7i.24xlarge": 5.090400, + "eu-west-2|c7i.2xlarge": 0.424200, + "eu-west-2|c7i.48xlarge": 10.180800, + "eu-west-2|c7i.4xlarge": 0.848400, + "eu-west-2|c7i.8xlarge": 1.696800, + "eu-west-2|c7i.large": 0.106050, + "eu-west-2|c7i.metal-24xl": 5.090400, + "eu-west-2|c7i.metal-48xl": 10.180800, + "eu-west-2|c7i.xlarge": 0.212100, + "eu-west-2|c8g.12xlarge": 2.266560, + "eu-west-2|c8g.16xlarge": 3.022080, + "eu-west-2|c8g.24xlarge": 4.533120, + "eu-west-2|c8g.2xlarge": 0.377760, + "eu-west-2|c8g.48xlarge": 9.066240, + "eu-west-2|c8g.4xlarge": 0.755520, + "eu-west-2|c8g.8xlarge": 1.511040, + "eu-west-2|c8g.large": 0.094440, + "eu-west-2|c8g.medium": 0.047220, + "eu-west-2|c8g.metal-24xl": 4.533120, + "eu-west-2|c8g.metal-48xl": 9.066240, + "eu-west-2|c8g.xlarge": 0.188880, + "eu-west-2|c8gd.12xlarge": 2.816640, + "eu-west-2|c8gd.16xlarge": 3.755520, + "eu-west-2|c8gd.24xlarge": 5.633280, + "eu-west-2|c8gd.2xlarge": 0.469440, + "eu-west-2|c8gd.48xlarge": 11.266560, + "eu-west-2|c8gd.4xlarge": 0.938880, + "eu-west-2|c8gd.8xlarge": 1.877760, + "eu-west-2|c8gd.large": 0.117360, + "eu-west-2|c8gd.medium": 0.058680, + "eu-west-2|c8gd.metal-24xl": 5.633280, + "eu-west-2|c8gd.metal-48xl": 11.266560, + "eu-west-2|c8gd.xlarge": 0.234720, + "eu-west-2|d2.2xlarge": 1.544000, + "eu-west-2|d2.4xlarge": 3.087000, + "eu-west-2|d2.8xlarge": 6.174000, + "eu-west-2|d2.xlarge": 0.772000, + "eu-west-2|d3.2xlarge": 1.280000, + "eu-west-2|d3.4xlarge": 2.559000, + "eu-west-2|d3.8xlarge": 5.118240, + "eu-west-2|d3.xlarge": 0.640000, + "eu-west-2|f1.2xlarge": 1.906000, + "eu-west-2|f1.4xlarge": 3.812000, + "eu-west-2|f2.12xlarge": 5.148000, + "eu-west-2|f2.48xlarge": 20.592000, + "eu-west-2|f2.6xlarge": 2.574000, + "eu-west-2|g3.16xlarge": 5.716000, + "eu-west-2|g3.4xlarge": 1.429000, + "eu-west-2|g3.8xlarge": 2.858000, + "eu-west-2|g3s.xlarge": 0.940000, + "eu-west-2|g4ad.16xlarge": 4.056000, + "eu-west-2|g4ad.2xlarge": 0.632920, + "eu-west-2|g4ad.4xlarge": 1.014000, + "eu-west-2|g4ad.8xlarge": 2.028000, + "eu-west-2|g4ad.xlarge": 0.442710, + "eu-west-2|g4dn.12xlarge": 4.577000, + "eu-west-2|g4dn.16xlarge": 5.092000, + "eu-west-2|g4dn.2xlarge": 0.880000, + "eu-west-2|g4dn.4xlarge": 1.409000, + "eu-west-2|g4dn.8xlarge": 2.546000, + "eu-west-2|g4dn.metal": 9.154000, + "eu-west-2|g4dn.xlarge": 0.615000, + "eu-west-2|g5.12xlarge": 7.199940, + "eu-west-2|g5.16xlarge": 5.199400, + "eu-west-2|g5.24xlarge": 10.337860, + "eu-west-2|g5.2xlarge": 1.538490, + "eu-west-2|g5.48xlarge": 20.675720, + "eu-west-2|g5.4xlarge": 2.061480, + "eu-west-2|g5.8xlarge": 3.107450, + "eu-west-2|g5.xlarge": 1.277000, + "eu-west-2|g6.12xlarge": 5.841200, + "eu-west-2|g6.16xlarge": 4.311840, + "eu-west-2|g6.24xlarge": 8.473390, + "eu-west-2|g6.2xlarge": 1.240950, + "eu-west-2|g6.48xlarge": 16.946780, + "eu-west-2|g6.4xlarge": 1.679650, + "eu-west-2|g6.8xlarge": 2.557050, + "eu-west-2|g6.xlarge": 1.021600, + "eu-west-2|g6f.2xlarge": 0.602980, + "eu-west-2|g6f.4xlarge": 1.205950, + "eu-west-2|g6f.large": 0.256420, + "eu-west-2|g6f.xlarge": 0.301490, + "eu-west-2|gr6.4xlarge": 1.953900, + "eu-west-2|gr6.8xlarge": 3.105520, + "eu-west-2|gr6f.4xlarge": 1.353210, + "eu-west-2|i3.16xlarge": 5.792000, + "eu-west-2|i3.2xlarge": 0.724000, + "eu-west-2|i3.4xlarge": 1.448000, + "eu-west-2|i3.8xlarge": 2.896000, + "eu-west-2|i3.large": 0.181000, + "eu-west-2|i3.metal": 5.792000, + "eu-west-2|i3.xlarge": 0.362000, + "eu-west-2|i3en.12xlarge": 6.312000, + "eu-west-2|i3en.24xlarge": 12.624000, + "eu-west-2|i3en.2xlarge": 1.052000, + "eu-west-2|i3en.3xlarge": 1.578000, + "eu-west-2|i3en.6xlarge": 3.156000, + "eu-west-2|i3en.large": 0.263000, + "eu-west-2|i3en.metal": 12.624000, + "eu-west-2|i3en.xlarge": 0.526000, + "eu-west-2|i4i.12xlarge": 4.778000, + "eu-west-2|i4i.16xlarge": 6.371000, + "eu-west-2|i4i.24xlarge": 9.556800, + "eu-west-2|i4i.2xlarge": 0.796000, + "eu-west-2|i4i.32xlarge": 12.742400, + "eu-west-2|i4i.4xlarge": 1.593000, + "eu-west-2|i4i.8xlarge": 3.186000, + "eu-west-2|i4i.large": 0.199000, + "eu-west-2|i4i.metal": 12.742000, + "eu-west-2|i4i.xlarge": 0.398000, + "eu-west-2|i7i.12xlarge": 5.256200, + "eu-west-2|i7i.16xlarge": 7.008300, + "eu-west-2|i7i.24xlarge": 10.512500, + "eu-west-2|i7i.2xlarge": 0.876000, + "eu-west-2|i7i.48xlarge": 21.025000, + "eu-west-2|i7i.4xlarge": 1.752100, + "eu-west-2|i7i.8xlarge": 3.504200, + "eu-west-2|i7i.large": 0.219000, + "eu-west-2|i7i.metal-24xl": 10.512500, + "eu-west-2|i7i.metal-48xl": 21.025000, + "eu-west-2|i7i.xlarge": 0.438000, + "eu-west-2|i7ie.12xlarge": 7.258800, + "eu-west-2|i7ie.18xlarge": 10.888200, + "eu-west-2|i7ie.24xlarge": 14.517600, + "eu-west-2|i7ie.2xlarge": 1.209800, + "eu-west-2|i7ie.3xlarge": 1.814700, + "eu-west-2|i7ie.48xlarge": 29.035200, + "eu-west-2|i7ie.6xlarge": 3.629400, + "eu-west-2|i7ie.large": 0.302500, + "eu-west-2|i7ie.metal-24xl": 14.517600, + "eu-west-2|i7ie.metal-48xl": 29.035200, + "eu-west-2|i7ie.xlarge": 0.604900, + "eu-west-2|i8g.12xlarge": 4.778400, + "eu-west-2|i8g.16xlarge": 6.371200, + "eu-west-2|i8g.24xlarge": 9.556800, + "eu-west-2|i8g.2xlarge": 0.796400, + "eu-west-2|i8g.48xlarge": 19.113600, + "eu-west-2|i8g.4xlarge": 1.592800, + "eu-west-2|i8g.8xlarge": 3.185600, + "eu-west-2|i8g.large": 0.199100, + "eu-west-2|i8g.metal-24xl": 9.556800, + "eu-west-2|i8g.xlarge": 0.398200, + "eu-west-2|im4gn.16xlarge": 6.753470, + "eu-west-2|im4gn.2xlarge": 0.844180, + "eu-west-2|im4gn.4xlarge": 1.688370, + "eu-west-2|im4gn.8xlarge": 3.376740, + "eu-west-2|im4gn.large": 0.211050, + "eu-west-2|im4gn.xlarge": 0.422090, + "eu-west-2|inf1.24xlarge": 5.530000, + "eu-west-2|inf1.2xlarge": 0.424000, + "eu-west-2|inf1.6xlarge": 1.382000, + "eu-west-2|inf1.xlarge": 0.267000, + "eu-west-2|inf2.24xlarge": 9.735950, + "eu-west-2|inf2.48xlarge": 19.471900, + "eu-west-2|inf2.8xlarge": 2.951790, + "eu-west-2|inf2.xlarge": 1.137300, + "eu-west-2|is4gen.2xlarge": 1.341300, + "eu-west-2|is4gen.4xlarge": 2.682610, + "eu-west-2|is4gen.8xlarge": 5.365220, + "eu-west-2|is4gen.large": 0.335330, + "eu-west-2|is4gen.medium": 0.167660, + "eu-west-2|is4gen.xlarge": 0.670650, + "eu-west-2|m4.10xlarge": 2.320000, + "eu-west-2|m4.16xlarge": 3.712000, + "eu-west-2|m4.2xlarge": 0.464000, + "eu-west-2|m4.4xlarge": 0.928000, + "eu-west-2|m4.large": 0.116000, + "eu-west-2|m4.xlarge": 0.232000, + "eu-west-2|m5.12xlarge": 2.664000, + "eu-west-2|m5.16xlarge": 3.552000, + "eu-west-2|m5.24xlarge": 5.328000, + "eu-west-2|m5.2xlarge": 0.444000, + "eu-west-2|m5.4xlarge": 0.888000, + "eu-west-2|m5.8xlarge": 1.776000, + "eu-west-2|m5.large": 0.111000, + "eu-west-2|m5.metal": 5.328000, + "eu-west-2|m5.xlarge": 0.222000, + "eu-west-2|m5a.12xlarge": 2.400000, + "eu-west-2|m5a.16xlarge": 3.200000, + "eu-west-2|m5a.24xlarge": 4.800000, + "eu-west-2|m5a.2xlarge": 0.400000, + "eu-west-2|m5a.4xlarge": 0.800000, + "eu-west-2|m5a.8xlarge": 1.600000, + "eu-west-2|m5a.large": 0.100000, + "eu-west-2|m5a.xlarge": 0.200000, + "eu-west-2|m5ad.12xlarge": 2.880000, + "eu-west-2|m5ad.16xlarge": 3.840000, + "eu-west-2|m5ad.24xlarge": 5.760000, + "eu-west-2|m5ad.2xlarge": 0.480000, + "eu-west-2|m5ad.4xlarge": 0.960000, + "eu-west-2|m5ad.8xlarge": 1.920000, + "eu-west-2|m5ad.large": 0.120000, + "eu-west-2|m5ad.xlarge": 0.240000, + "eu-west-2|m5d.12xlarge": 3.144000, + "eu-west-2|m5d.16xlarge": 4.192000, + "eu-west-2|m5d.24xlarge": 6.288000, + "eu-west-2|m5d.2xlarge": 0.524000, + "eu-west-2|m5d.4xlarge": 1.048000, + "eu-west-2|m5d.8xlarge": 2.096000, + "eu-west-2|m5d.large": 0.131000, + "eu-west-2|m5d.metal": 6.288000, + "eu-west-2|m5d.xlarge": 0.262000, + "eu-west-2|m6a.12xlarge": 2.397600, + "eu-west-2|m6a.16xlarge": 3.196800, + "eu-west-2|m6a.24xlarge": 4.795200, + "eu-west-2|m6a.2xlarge": 0.399600, + "eu-west-2|m6a.32xlarge": 6.393600, + "eu-west-2|m6a.48xlarge": 9.590400, + "eu-west-2|m6a.4xlarge": 0.799200, + "eu-west-2|m6a.8xlarge": 1.598400, + "eu-west-2|m6a.large": 0.099900, + "eu-west-2|m6a.metal": 9.590400, + "eu-west-2|m6a.xlarge": 0.199800, + "eu-west-2|m6g.12xlarge": 2.131200, + "eu-west-2|m6g.16xlarge": 2.841600, + "eu-west-2|m6g.2xlarge": 0.355200, + "eu-west-2|m6g.4xlarge": 0.710400, + "eu-west-2|m6g.8xlarge": 1.420800, + "eu-west-2|m6g.large": 0.088800, + "eu-west-2|m6g.medium": 0.044400, + "eu-west-2|m6g.metal": 2.841600, + "eu-west-2|m6g.xlarge": 0.177600, + "eu-west-2|m6gd.12xlarge": 2.515200, + "eu-west-2|m6gd.16xlarge": 3.353600, + "eu-west-2|m6gd.2xlarge": 0.419200, + "eu-west-2|m6gd.4xlarge": 0.838400, + "eu-west-2|m6gd.8xlarge": 1.676800, + "eu-west-2|m6gd.large": 0.104800, + "eu-west-2|m6gd.medium": 0.052400, + "eu-west-2|m6gd.metal": 3.353600, + "eu-west-2|m6gd.xlarge": 0.209600, + "eu-west-2|m6i.12xlarge": 2.664000, + "eu-west-2|m6i.16xlarge": 3.552000, + "eu-west-2|m6i.24xlarge": 5.328000, + "eu-west-2|m6i.2xlarge": 0.444000, + "eu-west-2|m6i.32xlarge": 7.104000, + "eu-west-2|m6i.4xlarge": 0.888000, + "eu-west-2|m6i.8xlarge": 1.776000, + "eu-west-2|m6i.large": 0.111000, + "eu-west-2|m6i.metal": 7.104000, + "eu-west-2|m6i.xlarge": 0.222000, + "eu-west-2|m6id.12xlarge": 3.301200, + "eu-west-2|m6id.16xlarge": 4.401600, + "eu-west-2|m6id.24xlarge": 6.602400, + "eu-west-2|m6id.2xlarge": 0.550200, + "eu-west-2|m6id.32xlarge": 8.803200, + "eu-west-2|m6id.4xlarge": 1.100400, + "eu-west-2|m6id.8xlarge": 2.200800, + "eu-west-2|m6id.large": 0.137550, + "eu-west-2|m6id.metal": 8.803200, + "eu-west-2|m6id.xlarge": 0.275100, + "eu-west-2|m7a.12xlarge": 3.216720, + "eu-west-2|m7a.16xlarge": 4.288960, + "eu-west-2|m7a.24xlarge": 6.433440, + "eu-west-2|m7a.2xlarge": 0.536120, + "eu-west-2|m7a.32xlarge": 8.577920, + "eu-west-2|m7a.48xlarge": 12.866880, + "eu-west-2|m7a.4xlarge": 1.072240, + "eu-west-2|m7a.8xlarge": 2.144480, + "eu-west-2|m7a.large": 0.134030, + "eu-west-2|m7a.medium": 0.067020, + "eu-west-2|m7a.metal-48xl": 12.866880, + "eu-west-2|m7a.xlarge": 0.268060, + "eu-west-2|m7g.12xlarge": 2.264600, + "eu-west-2|m7g.16xlarge": 3.019500, + "eu-west-2|m7g.2xlarge": 0.377400, + "eu-west-2|m7g.4xlarge": 0.754900, + "eu-west-2|m7g.8xlarge": 1.509800, + "eu-west-2|m7g.large": 0.094400, + "eu-west-2|m7g.medium": 0.047200, + "eu-west-2|m7g.metal": 3.019500, + "eu-west-2|m7g.xlarge": 0.188700, + "eu-west-2|m7i-flex.12xlarge": 2.657280, + "eu-west-2|m7i-flex.16xlarge": 3.543040, + "eu-west-2|m7i-flex.2xlarge": 0.442880, + "eu-west-2|m7i-flex.4xlarge": 0.885760, + "eu-west-2|m7i-flex.8xlarge": 1.771520, + "eu-west-2|m7i-flex.large": 0.110720, + "eu-west-2|m7i-flex.xlarge": 0.221440, + "eu-west-2|m7i.12xlarge": 2.797200, + "eu-west-2|m7i.16xlarge": 3.729600, + "eu-west-2|m7i.24xlarge": 5.594400, + "eu-west-2|m7i.2xlarge": 0.466200, + "eu-west-2|m7i.48xlarge": 11.188800, + "eu-west-2|m7i.4xlarge": 0.932400, + "eu-west-2|m7i.8xlarge": 1.864800, + "eu-west-2|m7i.large": 0.116550, + "eu-west-2|m7i.metal-24xl": 5.594400, + "eu-west-2|m7i.metal-48xl": 11.188800, + "eu-west-2|m7i.xlarge": 0.233100, + "eu-west-2|m8g.12xlarge": 2.491200, + "eu-west-2|m8g.16xlarge": 3.321600, + "eu-west-2|m8g.24xlarge": 4.982400, + "eu-west-2|m8g.2xlarge": 0.415200, + "eu-west-2|m8g.48xlarge": 9.964800, + "eu-west-2|m8g.4xlarge": 0.830400, + "eu-west-2|m8g.8xlarge": 1.660800, + "eu-west-2|m8g.large": 0.103800, + "eu-west-2|m8g.medium": 0.051900, + "eu-west-2|m8g.metal-24xl": 4.982400, + "eu-west-2|m8g.metal-48xl": 9.964800, + "eu-west-2|m8g.xlarge": 0.207600, + "eu-west-2|m8gd.12xlarge": 3.208800, + "eu-west-2|m8gd.16xlarge": 4.278400, + "eu-west-2|m8gd.24xlarge": 6.417600, + "eu-west-2|m8gd.2xlarge": 0.534800, + "eu-west-2|m8gd.48xlarge": 12.835200, + "eu-west-2|m8gd.4xlarge": 1.069600, + "eu-west-2|m8gd.8xlarge": 2.139200, + "eu-west-2|m8gd.large": 0.133700, + "eu-west-2|m8gd.medium": 0.066850, + "eu-west-2|m8gd.metal-24xl": 6.417600, + "eu-west-2|m8gd.metal-48xl": 12.835200, + "eu-west-2|m8gd.xlarge": 0.267400, + "eu-west-2|p3.16xlarge": 28.712000, + "eu-west-2|p3.2xlarge": 3.589000, + "eu-west-2|p3.8xlarge": 14.356000, + "eu-west-2|p4d.24xlarge": 28.544930, + "eu-west-2|p5.48xlarge": 71.552000, + "eu-west-2|p5.4xlarge": 8.944000, + "eu-west-2|r4.16xlarge": 4.992000, + "eu-west-2|r4.2xlarge": 0.624000, + "eu-west-2|r4.4xlarge": 1.248000, + "eu-west-2|r4.8xlarge": 2.496000, + "eu-west-2|r4.large": 0.156000, + "eu-west-2|r4.xlarge": 0.312000, + "eu-west-2|r5.12xlarge": 3.552000, + "eu-west-2|r5.16xlarge": 4.736000, + "eu-west-2|r5.24xlarge": 7.104000, + "eu-west-2|r5.2xlarge": 0.592000, + "eu-west-2|r5.4xlarge": 1.184000, + "eu-west-2|r5.8xlarge": 2.368000, + "eu-west-2|r5.large": 0.148000, + "eu-west-2|r5.metal": 7.104000, + "eu-west-2|r5.xlarge": 0.296000, + "eu-west-2|r5a.12xlarge": 3.192000, + "eu-west-2|r5a.16xlarge": 4.256000, + "eu-west-2|r5a.24xlarge": 6.384000, + "eu-west-2|r5a.2xlarge": 0.532000, + "eu-west-2|r5a.4xlarge": 1.064000, + "eu-west-2|r5a.8xlarge": 2.128000, + "eu-west-2|r5a.large": 0.133000, + "eu-west-2|r5a.xlarge": 0.266000, + "eu-west-2|r5ad.12xlarge": 3.696000, + "eu-west-2|r5ad.16xlarge": 4.928000, + "eu-west-2|r5ad.24xlarge": 7.392000, + "eu-west-2|r5ad.2xlarge": 0.616000, + "eu-west-2|r5ad.4xlarge": 1.232000, + "eu-west-2|r5ad.8xlarge": 2.464000, + "eu-west-2|r5ad.large": 0.154000, + "eu-west-2|r5ad.xlarge": 0.308000, + "eu-west-2|r5b.12xlarge": 4.200000, + "eu-west-2|r5b.16xlarge": 5.600000, + "eu-west-2|r5b.24xlarge": 8.400000, + "eu-west-2|r5b.2xlarge": 0.700000, + "eu-west-2|r5b.4xlarge": 1.400000, + "eu-west-2|r5b.8xlarge": 2.800000, + "eu-west-2|r5b.large": 0.175000, + "eu-west-2|r5b.metal": 8.400000, + "eu-west-2|r5b.xlarge": 0.350000, + "eu-west-2|r5d.12xlarge": 4.056000, + "eu-west-2|r5d.16xlarge": 5.408000, + "eu-west-2|r5d.24xlarge": 8.112000, + "eu-west-2|r5d.2xlarge": 0.676000, + "eu-west-2|r5d.4xlarge": 1.352000, + "eu-west-2|r5d.8xlarge": 2.704000, + "eu-west-2|r5d.large": 0.169000, + "eu-west-2|r5d.metal": 8.112000, + "eu-west-2|r5d.xlarge": 0.338000, + "eu-west-2|r5n.12xlarge": 4.200000, + "eu-west-2|r5n.16xlarge": 5.600000, + "eu-west-2|r5n.24xlarge": 8.400000, + "eu-west-2|r5n.2xlarge": 0.700000, + "eu-west-2|r5n.4xlarge": 1.400000, + "eu-west-2|r5n.8xlarge": 2.800000, + "eu-west-2|r5n.large": 0.175000, + "eu-west-2|r5n.metal": 8.400000, + "eu-west-2|r5n.xlarge": 0.350000, + "eu-west-2|r6g.12xlarge": 2.841600, + "eu-west-2|r6g.16xlarge": 3.788800, + "eu-west-2|r6g.2xlarge": 0.473600, + "eu-west-2|r6g.4xlarge": 0.947200, + "eu-west-2|r6g.8xlarge": 1.894400, + "eu-west-2|r6g.large": 0.118400, + "eu-west-2|r6g.medium": 0.059200, + "eu-west-2|r6g.metal": 3.788800, + "eu-west-2|r6g.xlarge": 0.236800, + "eu-west-2|r6gd.12xlarge": 3.244800, + "eu-west-2|r6gd.16xlarge": 4.326400, + "eu-west-2|r6gd.2xlarge": 0.540800, + "eu-west-2|r6gd.4xlarge": 1.081600, + "eu-west-2|r6gd.8xlarge": 2.163200, + "eu-west-2|r6gd.large": 0.135200, + "eu-west-2|r6gd.medium": 0.067600, + "eu-west-2|r6gd.metal": 4.326400, + "eu-west-2|r6gd.xlarge": 0.270400, + "eu-west-2|r6i.12xlarge": 3.552000, + "eu-west-2|r6i.16xlarge": 4.736000, + "eu-west-2|r6i.24xlarge": 7.104000, + "eu-west-2|r6i.2xlarge": 0.592000, + "eu-west-2|r6i.32xlarge": 9.472000, + "eu-west-2|r6i.4xlarge": 1.184000, + "eu-west-2|r6i.8xlarge": 2.368000, + "eu-west-2|r6i.large": 0.148000, + "eu-west-2|r6i.metal": 9.472000, + "eu-west-2|r6i.xlarge": 0.296000, + "eu-west-2|r6id.12xlarge": 4.258800, + "eu-west-2|r6id.16xlarge": 5.678400, + "eu-west-2|r6id.24xlarge": 8.517600, + "eu-west-2|r6id.2xlarge": 0.709800, + "eu-west-2|r6id.32xlarge": 11.356800, + "eu-west-2|r6id.4xlarge": 1.419600, + "eu-west-2|r6id.8xlarge": 2.839200, + "eu-west-2|r6id.large": 0.177450, + "eu-west-2|r6id.metal": 11.356800, + "eu-west-2|r6id.xlarge": 0.354900, + "eu-west-2|r7g.12xlarge": 3.019200, + "eu-west-2|r7g.16xlarge": 4.025600, + "eu-west-2|r7g.2xlarge": 0.503200, + "eu-west-2|r7g.4xlarge": 1.006400, + "eu-west-2|r7g.8xlarge": 2.012800, + "eu-west-2|r7g.large": 0.125800, + "eu-west-2|r7g.medium": 0.062900, + "eu-west-2|r7g.metal": 4.025600, + "eu-west-2|r7g.xlarge": 0.251600, + "eu-west-2|r7gd.12xlarge": 3.832800, + "eu-west-2|r7gd.16xlarge": 5.110400, + "eu-west-2|r7gd.2xlarge": 0.638800, + "eu-west-2|r7gd.4xlarge": 1.277600, + "eu-west-2|r7gd.8xlarge": 2.555200, + "eu-west-2|r7gd.large": 0.159700, + "eu-west-2|r7gd.medium": 0.079900, + "eu-west-2|r7gd.metal": 5.110400, + "eu-west-2|r7gd.xlarge": 0.319400, + "eu-west-2|r7i.12xlarge": 3.729600, + "eu-west-2|r7i.16xlarge": 4.972800, + "eu-west-2|r7i.24xlarge": 7.459200, + "eu-west-2|r7i.2xlarge": 0.621600, + "eu-west-2|r7i.48xlarge": 14.918400, + "eu-west-2|r7i.4xlarge": 1.243200, + "eu-west-2|r7i.8xlarge": 2.486400, + "eu-west-2|r7i.large": 0.155400, + "eu-west-2|r7i.metal-24xl": 7.459200, + "eu-west-2|r7i.metal-48xl": 14.918400, + "eu-west-2|r7i.xlarge": 0.310800, + "eu-west-2|r8g.12xlarge": 3.321120, + "eu-west-2|r8g.16xlarge": 4.428160, + "eu-west-2|r8g.24xlarge": 6.642240, + "eu-west-2|r8g.2xlarge": 0.553520, + "eu-west-2|r8g.48xlarge": 13.284480, + "eu-west-2|r8g.4xlarge": 1.107040, + "eu-west-2|r8g.8xlarge": 2.214080, + "eu-west-2|r8g.large": 0.138380, + "eu-west-2|r8g.medium": 0.069190, + "eu-west-2|r8g.metal-24xl": 6.642240, + "eu-west-2|r8g.metal-48xl": 13.284480, + "eu-west-2|r8g.xlarge": 0.276760, + "eu-west-2|r8gd.12xlarge": 4.139520, + "eu-west-2|r8gd.16xlarge": 5.519360, + "eu-west-2|r8gd.24xlarge": 8.279040, + "eu-west-2|r8gd.2xlarge": 0.689920, + "eu-west-2|r8gd.48xlarge": 16.558080, + "eu-west-2|r8gd.4xlarge": 1.379840, + "eu-west-2|r8gd.8xlarge": 2.759680, + "eu-west-2|r8gd.large": 0.172480, + "eu-west-2|r8gd.medium": 0.086240, + "eu-west-2|r8gd.metal-24xl": 8.279040, + "eu-west-2|r8gd.metal-48xl": 16.558080, + "eu-west-2|r8gd.xlarge": 0.344960, + "eu-west-2|r8i-flex.12xlarge": 3.720240, + "eu-west-2|r8i-flex.16xlarge": 4.960320, + "eu-west-2|r8i-flex.2xlarge": 0.620040, + "eu-west-2|r8i-flex.4xlarge": 1.240080, + "eu-west-2|r8i-flex.8xlarge": 2.480160, + "eu-west-2|r8i-flex.large": 0.155010, + "eu-west-2|r8i-flex.xlarge": 0.310020, + "eu-west-2|r8i.12xlarge": 3.916080, + "eu-west-2|r8i.16xlarge": 5.221440, + "eu-west-2|r8i.24xlarge": 7.832160, + "eu-west-2|r8i.2xlarge": 0.652680, + "eu-west-2|r8i.32xlarge": 10.442880, + "eu-west-2|r8i.48xlarge": 15.664320, + "eu-west-2|r8i.4xlarge": 1.305360, + "eu-west-2|r8i.8xlarge": 2.610720, + "eu-west-2|r8i.96xlarge": 31.328640, + "eu-west-2|r8i.large": 0.163170, + "eu-west-2|r8i.metal-48xl": 15.664320, + "eu-west-2|r8i.metal-96xl": 31.328640, + "eu-west-2|r8i.xlarge": 0.326340, + "eu-west-2|t2.2xlarge": 0.422400, + "eu-west-2|t2.large": 0.105600, + "eu-west-2|t2.medium": 0.052000, + "eu-west-2|t2.micro": 0.013200, + "eu-west-2|t2.nano": 0.006600, + "eu-west-2|t2.small": 0.026000, + "eu-west-2|t2.xlarge": 0.211200, + "eu-west-2|t3.2xlarge": 0.377600, + "eu-west-2|t3.large": 0.094400, + "eu-west-2|t3.medium": 0.047200, + "eu-west-2|t3.micro": 0.011800, + "eu-west-2|t3.nano": 0.005900, + "eu-west-2|t3.small": 0.023600, + "eu-west-2|t3.xlarge": 0.188800, + "eu-west-2|t3a.2xlarge": 0.339800, + "eu-west-2|t3a.large": 0.085000, + "eu-west-2|t3a.medium": 0.042500, + "eu-west-2|t3a.micro": 0.010600, + "eu-west-2|t3a.nano": 0.005300, + "eu-west-2|t3a.small": 0.021200, + "eu-west-2|t3a.xlarge": 0.169900, + "eu-west-2|t4g.2xlarge": 0.300800, + "eu-west-2|t4g.large": 0.075200, + "eu-west-2|t4g.medium": 0.037600, + "eu-west-2|t4g.micro": 0.009400, + "eu-west-2|t4g.nano": 0.004700, + "eu-west-2|t4g.small": 0.018800, + "eu-west-2|t4g.xlarge": 0.150400, + "eu-west-2|u-6tb1.112xlarge": 64.133000, + "eu-west-2|u-6tb1.56xlarge": 54.505890, + "eu-west-2|u-9tb1.112xlarge": 96.200000, + "eu-west-2|u7i-6tb.112xlarge": 73.752950, + "eu-west-2|u7i-8tb.112xlarge": 98.337780, + "eu-west-2|x1.16xlarge": 8.403000, + "eu-west-2|x1.32xlarge": 16.806000, + "eu-west-2|x2idn.16xlarge": 8.403000, + "eu-west-2|x2idn.24xlarge": 12.604500, + "eu-west-2|x2idn.32xlarge": 16.806000, + "eu-west-2|x2idn.metal": 16.806000, + "eu-west-2|x2iedn.16xlarge": 16.806000, + "eu-west-2|x2iedn.24xlarge": 25.209000, + "eu-west-2|x2iedn.2xlarge": 2.100750, + "eu-west-2|x2iedn.32xlarge": 33.612000, + "eu-west-2|x2iedn.4xlarge": 4.201500, + "eu-west-2|x2iedn.8xlarge": 8.403000, + "eu-west-2|x2iedn.metal": 33.612000, + "eu-west-2|x2iedn.xlarge": 1.050380, + "eu-west-2|z1d.12xlarge": 5.273000, + "eu-west-2|z1d.2xlarge": 0.879000, + "eu-west-2|z1d.3xlarge": 1.318000, + "eu-west-2|z1d.6xlarge": 2.636000, + "eu-west-2|z1d.large": 0.220000, + "eu-west-2|z1d.metal": 5.273000, + "eu-west-2|z1d.xlarge": 0.439000, + "eu-west-3|c5.12xlarge": 2.424000, + "eu-west-3|c5.18xlarge": 3.636000, + "eu-west-3|c5.24xlarge": 4.848000, + "eu-west-3|c5.2xlarge": 0.404000, + "eu-west-3|c5.4xlarge": 0.808000, + "eu-west-3|c5.9xlarge": 1.818000, + "eu-west-3|c5.large": 0.101000, + "eu-west-3|c5.metal": 4.848000, + "eu-west-3|c5.xlarge": 0.202000, + "eu-west-3|c5a.12xlarge": 2.184000, + "eu-west-3|c5a.16xlarge": 2.912000, + "eu-west-3|c5a.24xlarge": 4.368000, + "eu-west-3|c5a.2xlarge": 0.364000, + "eu-west-3|c5a.4xlarge": 0.728000, + "eu-west-3|c5a.8xlarge": 1.456000, + "eu-west-3|c5a.large": 0.091000, + "eu-west-3|c5a.xlarge": 0.182000, + "eu-west-3|c5d.18xlarge": 4.140000, + "eu-west-3|c5d.2xlarge": 0.460000, + "eu-west-3|c5d.4xlarge": 0.920000, + "eu-west-3|c5d.9xlarge": 2.070000, + "eu-west-3|c5d.large": 0.115000, + "eu-west-3|c5d.xlarge": 0.230000, + "eu-west-3|c5n.18xlarge": 4.608000, + "eu-west-3|c5n.2xlarge": 0.512000, + "eu-west-3|c5n.4xlarge": 1.024000, + "eu-west-3|c5n.9xlarge": 2.304000, + "eu-west-3|c5n.large": 0.128000, + "eu-west-3|c5n.metal": 4.608000, + "eu-west-3|c5n.xlarge": 0.256000, + "eu-west-3|c6g.12xlarge": 1.944000, + "eu-west-3|c6g.16xlarge": 2.592000, + "eu-west-3|c6g.2xlarge": 0.324000, + "eu-west-3|c6g.4xlarge": 0.648000, + "eu-west-3|c6g.8xlarge": 1.296000, + "eu-west-3|c6g.large": 0.081000, + "eu-west-3|c6g.medium": 0.040500, + "eu-west-3|c6g.metal": 2.592000, + "eu-west-3|c6g.xlarge": 0.162000, + "eu-west-3|c6gd.12xlarge": 2.208000, + "eu-west-3|c6gd.16xlarge": 2.944000, + "eu-west-3|c6gd.2xlarge": 0.368000, + "eu-west-3|c6gd.4xlarge": 0.736000, + "eu-west-3|c6gd.8xlarge": 1.472000, + "eu-west-3|c6gd.large": 0.092000, + "eu-west-3|c6gd.medium": 0.046000, + "eu-west-3|c6gd.metal": 2.944000, + "eu-west-3|c6gd.xlarge": 0.184000, + "eu-west-3|c6gn.12xlarge": 2.460000, + "eu-west-3|c6gn.16xlarge": 3.280000, + "eu-west-3|c6gn.2xlarge": 0.410000, + "eu-west-3|c6gn.4xlarge": 0.820000, + "eu-west-3|c6gn.8xlarge": 1.640000, + "eu-west-3|c6gn.large": 0.102500, + "eu-west-3|c6gn.medium": 0.051250, + "eu-west-3|c6gn.metal": 3.280000, + "eu-west-3|c6gn.xlarge": 0.205000, + "eu-west-3|c6i.12xlarge": 2.424000, + "eu-west-3|c6i.16xlarge": 3.232000, + "eu-west-3|c6i.24xlarge": 4.848000, + "eu-west-3|c6i.2xlarge": 0.404000, + "eu-west-3|c6i.32xlarge": 6.464000, + "eu-west-3|c6i.4xlarge": 0.808000, + "eu-west-3|c6i.8xlarge": 1.616000, + "eu-west-3|c6i.large": 0.101000, + "eu-west-3|c6i.metal": 6.464000, + "eu-west-3|c6i.xlarge": 0.202000, + "eu-west-3|c6id.12xlarge": 2.898000, + "eu-west-3|c6id.16xlarge": 3.864000, + "eu-west-3|c6id.24xlarge": 5.796000, + "eu-west-3|c6id.2xlarge": 0.483000, + "eu-west-3|c6id.32xlarge": 7.728000, + "eu-west-3|c6id.4xlarge": 0.966000, + "eu-west-3|c6id.8xlarge": 1.932000, + "eu-west-3|c6id.large": 0.120750, + "eu-west-3|c6id.metal": 7.728000, + "eu-west-3|c6id.xlarge": 0.241500, + "eu-west-3|c6in.12xlarge": 3.225600, + "eu-west-3|c6in.16xlarge": 4.300800, + "eu-west-3|c6in.24xlarge": 6.451200, + "eu-west-3|c6in.2xlarge": 0.537600, + "eu-west-3|c6in.32xlarge": 8.601600, + "eu-west-3|c6in.4xlarge": 1.075200, + "eu-west-3|c6in.8xlarge": 2.150400, + "eu-west-3|c6in.large": 0.134400, + "eu-west-3|c6in.metal": 8.601600, + "eu-west-3|c6in.xlarge": 0.268800, + "eu-west-3|c7g.12xlarge": 2.060600, + "eu-west-3|c7g.16xlarge": 2.747500, + "eu-west-3|c7g.2xlarge": 0.343400, + "eu-west-3|c7g.4xlarge": 0.686900, + "eu-west-3|c7g.8xlarge": 1.373800, + "eu-west-3|c7g.large": 0.085900, + "eu-west-3|c7g.medium": 0.042900, + "eu-west-3|c7g.metal": 2.747500, + "eu-west-3|c7g.xlarge": 0.171700, + "eu-west-3|c7gd.12xlarge": 2.608300, + "eu-west-3|c7gd.16xlarge": 3.477800, + "eu-west-3|c7gd.2xlarge": 0.434700, + "eu-west-3|c7gd.4xlarge": 0.869400, + "eu-west-3|c7gd.8xlarge": 1.738900, + "eu-west-3|c7gd.large": 0.108700, + "eu-west-3|c7gd.medium": 0.054300, + "eu-west-3|c7gd.metal": 3.477800, + "eu-west-3|c7gd.xlarge": 0.217400, + "eu-west-3|c7i-flex.12xlarge": 2.417940, + "eu-west-3|c7i-flex.16xlarge": 3.223920, + "eu-west-3|c7i-flex.2xlarge": 0.402990, + "eu-west-3|c7i-flex.4xlarge": 0.805980, + "eu-west-3|c7i-flex.8xlarge": 1.611960, + "eu-west-3|c7i-flex.large": 0.100750, + "eu-west-3|c7i-flex.xlarge": 0.201500, + "eu-west-3|c7i.12xlarge": 2.545200, + "eu-west-3|c7i.16xlarge": 3.393600, + "eu-west-3|c7i.24xlarge": 5.090400, + "eu-west-3|c7i.2xlarge": 0.424200, + "eu-west-3|c7i.48xlarge": 10.180800, + "eu-west-3|c7i.4xlarge": 0.848400, + "eu-west-3|c7i.8xlarge": 1.696800, + "eu-west-3|c7i.large": 0.106050, + "eu-west-3|c7i.metal-24xl": 5.090400, + "eu-west-3|c7i.metal-48xl": 10.180800, + "eu-west-3|c7i.xlarge": 0.212100, + "eu-west-3|d2.2xlarge": 1.544000, + "eu-west-3|d2.4xlarge": 3.088000, + "eu-west-3|d2.8xlarge": 6.176000, + "eu-west-3|d2.xlarge": 0.772000, + "eu-west-3|d3.2xlarge": 1.280000, + "eu-west-3|d3.4xlarge": 2.559000, + "eu-west-3|d3.8xlarge": 5.118240, + "eu-west-3|d3.xlarge": 0.640000, + "eu-west-3|g4dn.12xlarge": 4.574000, + "eu-west-3|g4dn.16xlarge": 5.088000, + "eu-west-3|g4dn.2xlarge": 0.879000, + "eu-west-3|g4dn.4xlarge": 1.408000, + "eu-west-3|g4dn.8xlarge": 2.544000, + "eu-west-3|g4dn.metal": 9.148000, + "eu-west-3|g4dn.xlarge": 0.615000, + "eu-west-3|g6.12xlarge": 5.841200, + "eu-west-3|g6.16xlarge": 4.311840, + "eu-west-3|g6.24xlarge": 8.473390, + "eu-west-3|g6.2xlarge": 1.240950, + "eu-west-3|g6.48xlarge": 16.946780, + "eu-west-3|g6.4xlarge": 1.679650, + "eu-west-3|g6.8xlarge": 2.557050, + "eu-west-3|g6.xlarge": 1.021600, + "eu-west-3|gr6.4xlarge": 1.953800, + "eu-west-3|gr6.8xlarge": 3.105360, + "eu-west-3|hpc6id.32xlarge": 6.772940, + "eu-west-3|hpc7a.12xlarge": 8.555300, + "eu-west-3|hpc7a.24xlarge": 8.555300, + "eu-west-3|hpc7a.48xlarge": 8.555300, + "eu-west-3|hpc7a.96xlarge": 8.555300, + "eu-west-3|i3.16xlarge": 5.792000, + "eu-west-3|i3.2xlarge": 0.724000, + "eu-west-3|i3.4xlarge": 1.448000, + "eu-west-3|i3.8xlarge": 2.896000, + "eu-west-3|i3.large": 0.181000, + "eu-west-3|i3.metal": 5.792000, + "eu-west-3|i3.xlarge": 0.362000, + "eu-west-3|i3en.12xlarge": 6.312000, + "eu-west-3|i3en.24xlarge": 12.624000, + "eu-west-3|i3en.2xlarge": 1.052000, + "eu-west-3|i3en.3xlarge": 1.578000, + "eu-west-3|i3en.6xlarge": 3.156000, + "eu-west-3|i3en.large": 0.263000, + "eu-west-3|i3en.metal": 12.624000, + "eu-west-3|i3en.xlarge": 0.526000, + "eu-west-3|i4i.12xlarge": 4.778000, + "eu-west-3|i4i.16xlarge": 6.371000, + "eu-west-3|i4i.24xlarge": 9.556800, + "eu-west-3|i4i.2xlarge": 0.796000, + "eu-west-3|i4i.32xlarge": 12.742400, + "eu-west-3|i4i.4xlarge": 1.593000, + "eu-west-3|i4i.8xlarge": 3.186000, + "eu-west-3|i4i.large": 0.199000, + "eu-west-3|i4i.metal": 12.742000, + "eu-west-3|i4i.xlarge": 0.398000, + "eu-west-3|i7ie.12xlarge": 7.258800, + "eu-west-3|i7ie.18xlarge": 10.888200, + "eu-west-3|i7ie.24xlarge": 14.517600, + "eu-west-3|i7ie.2xlarge": 1.209800, + "eu-west-3|i7ie.3xlarge": 1.814700, + "eu-west-3|i7ie.48xlarge": 29.035200, + "eu-west-3|i7ie.6xlarge": 3.629400, + "eu-west-3|i7ie.large": 0.302500, + "eu-west-3|i7ie.metal-24xl": 14.517600, + "eu-west-3|i7ie.metal-48xl": 29.035200, + "eu-west-3|i7ie.xlarge": 0.604900, + "eu-west-3|im4gn.16xlarge": 6.753470, + "eu-west-3|im4gn.2xlarge": 0.844180, + "eu-west-3|im4gn.4xlarge": 1.688370, + "eu-west-3|im4gn.8xlarge": 3.376740, + "eu-west-3|im4gn.large": 0.211050, + "eu-west-3|im4gn.xlarge": 0.422090, + "eu-west-3|inf1.24xlarge": 5.517000, + "eu-west-3|inf1.2xlarge": 0.423000, + "eu-west-3|inf1.6xlarge": 1.379000, + "eu-west-3|inf1.xlarge": 0.267000, + "eu-west-3|inf2.24xlarge": 9.086890, + "eu-west-3|inf2.48xlarge": 18.173770, + "eu-west-3|inf2.8xlarge": 2.755000, + "eu-west-3|inf2.xlarge": 1.061480, + "eu-west-3|is4gen.2xlarge": 1.341300, + "eu-west-3|is4gen.4xlarge": 2.682610, + "eu-west-3|is4gen.8xlarge": 5.365220, + "eu-west-3|is4gen.large": 0.335330, + "eu-west-3|is4gen.medium": 0.167660, + "eu-west-3|is4gen.xlarge": 0.670650, + "eu-west-3|m5.12xlarge": 2.688000, + "eu-west-3|m5.16xlarge": 3.584000, + "eu-west-3|m5.24xlarge": 5.376000, + "eu-west-3|m5.2xlarge": 0.448000, + "eu-west-3|m5.4xlarge": 0.896000, + "eu-west-3|m5.8xlarge": 1.792000, + "eu-west-3|m5.large": 0.112000, + "eu-west-3|m5.metal": 5.376000, + "eu-west-3|m5.xlarge": 0.224000, + "eu-west-3|m5a.12xlarge": 2.424000, + "eu-west-3|m5a.16xlarge": 3.232000, + "eu-west-3|m5a.24xlarge": 4.848000, + "eu-west-3|m5a.2xlarge": 0.404000, + "eu-west-3|m5a.4xlarge": 0.808000, + "eu-west-3|m5a.8xlarge": 1.616000, + "eu-west-3|m5a.large": 0.101000, + "eu-west-3|m5a.xlarge": 0.202000, + "eu-west-3|m5ad.12xlarge": 2.904000, + "eu-west-3|m5ad.16xlarge": 3.872000, + "eu-west-3|m5ad.24xlarge": 5.808000, + "eu-west-3|m5ad.2xlarge": 0.484000, + "eu-west-3|m5ad.4xlarge": 0.968000, + "eu-west-3|m5ad.8xlarge": 1.936000, + "eu-west-3|m5ad.large": 0.121000, + "eu-west-3|m5ad.xlarge": 0.242000, + "eu-west-3|m5d.12xlarge": 3.168000, + "eu-west-3|m5d.16xlarge": 4.224000, + "eu-west-3|m5d.24xlarge": 6.336000, + "eu-west-3|m5d.2xlarge": 0.528000, + "eu-west-3|m5d.4xlarge": 1.056000, + "eu-west-3|m5d.8xlarge": 2.112000, + "eu-west-3|m5d.large": 0.132000, + "eu-west-3|m5d.metal": 6.336000, + "eu-west-3|m5d.xlarge": 0.264000, + "eu-west-3|m6a.12xlarge": 2.419200, + "eu-west-3|m6a.16xlarge": 3.225600, + "eu-west-3|m6a.24xlarge": 4.838400, + "eu-west-3|m6a.2xlarge": 0.403200, + "eu-west-3|m6a.32xlarge": 6.451200, + "eu-west-3|m6a.48xlarge": 9.676800, + "eu-west-3|m6a.4xlarge": 0.806400, + "eu-west-3|m6a.8xlarge": 1.612800, + "eu-west-3|m6a.large": 0.100800, + "eu-west-3|m6a.metal": 9.676800, + "eu-west-3|m6a.xlarge": 0.201600, + "eu-west-3|m6g.12xlarge": 2.160000, + "eu-west-3|m6g.16xlarge": 2.880000, + "eu-west-3|m6g.2xlarge": 0.360000, + "eu-west-3|m6g.4xlarge": 0.720000, + "eu-west-3|m6g.8xlarge": 1.440000, + "eu-west-3|m6g.large": 0.090000, + "eu-west-3|m6g.medium": 0.045000, + "eu-west-3|m6g.metal": 2.880000, + "eu-west-3|m6g.xlarge": 0.180000, + "eu-west-3|m6gd.12xlarge": 2.534400, + "eu-west-3|m6gd.16xlarge": 3.379200, + "eu-west-3|m6gd.2xlarge": 0.422400, + "eu-west-3|m6gd.4xlarge": 0.844800, + "eu-west-3|m6gd.8xlarge": 1.689600, + "eu-west-3|m6gd.large": 0.105600, + "eu-west-3|m6gd.medium": 0.052800, + "eu-west-3|m6gd.metal": 3.379200, + "eu-west-3|m6gd.xlarge": 0.211200, + "eu-west-3|m6i.12xlarge": 2.688000, + "eu-west-3|m6i.16xlarge": 3.584000, + "eu-west-3|m6i.24xlarge": 5.376000, + "eu-west-3|m6i.2xlarge": 0.448000, + "eu-west-3|m6i.32xlarge": 7.168000, + "eu-west-3|m6i.4xlarge": 0.896000, + "eu-west-3|m6i.8xlarge": 1.792000, + "eu-west-3|m6i.large": 0.112000, + "eu-west-3|m6i.metal": 7.168000, + "eu-west-3|m6i.xlarge": 0.224000, + "eu-west-3|m7g.12xlarge": 2.284800, + "eu-west-3|m7g.16xlarge": 3.046400, + "eu-west-3|m7g.2xlarge": 0.380800, + "eu-west-3|m7g.4xlarge": 0.761600, + "eu-west-3|m7g.8xlarge": 1.523200, + "eu-west-3|m7g.large": 0.095200, + "eu-west-3|m7g.medium": 0.047600, + "eu-west-3|m7g.metal": 3.046400, + "eu-west-3|m7g.xlarge": 0.190400, + "eu-west-3|m7gd.12xlarge": 2.993800, + "eu-west-3|m7gd.16xlarge": 3.991700, + "eu-west-3|m7gd.2xlarge": 0.499000, + "eu-west-3|m7gd.4xlarge": 0.997900, + "eu-west-3|m7gd.8xlarge": 1.995800, + "eu-west-3|m7gd.large": 0.124700, + "eu-west-3|m7gd.medium": 0.062400, + "eu-west-3|m7gd.metal": 3.991700, + "eu-west-3|m7gd.xlarge": 0.249500, + "eu-west-3|m7i-flex.12xlarge": 2.681280, + "eu-west-3|m7i-flex.16xlarge": 3.575040, + "eu-west-3|m7i-flex.2xlarge": 0.446880, + "eu-west-3|m7i-flex.4xlarge": 0.893760, + "eu-west-3|m7i-flex.8xlarge": 1.787520, + "eu-west-3|m7i-flex.large": 0.111720, + "eu-west-3|m7i-flex.xlarge": 0.223440, + "eu-west-3|m7i.12xlarge": 2.822400, + "eu-west-3|m7i.16xlarge": 3.763200, + "eu-west-3|m7i.24xlarge": 5.644800, + "eu-west-3|m7i.2xlarge": 0.470400, + "eu-west-3|m7i.48xlarge": 11.289600, + "eu-west-3|m7i.4xlarge": 0.940800, + "eu-west-3|m7i.8xlarge": 1.881600, + "eu-west-3|m7i.large": 0.117600, + "eu-west-3|m7i.metal-24xl": 5.644800, + "eu-west-3|m7i.metal-48xl": 11.289600, + "eu-west-3|m7i.xlarge": 0.235200, + "eu-west-3|m8g.12xlarge": 2.513280, + "eu-west-3|m8g.16xlarge": 3.351040, + "eu-west-3|m8g.24xlarge": 5.026560, + "eu-west-3|m8g.2xlarge": 0.418880, + "eu-west-3|m8g.48xlarge": 10.053120, + "eu-west-3|m8g.4xlarge": 0.837760, + "eu-west-3|m8g.8xlarge": 1.675520, + "eu-west-3|m8g.large": 0.104720, + "eu-west-3|m8g.medium": 0.052360, + "eu-west-3|m8g.metal-24xl": 5.026560, + "eu-west-3|m8g.metal-48xl": 10.053120, + "eu-west-3|m8g.xlarge": 0.209440, + "eu-west-3|r4.16xlarge": 4.992000, + "eu-west-3|r4.2xlarge": 0.624000, + "eu-west-3|r4.4xlarge": 1.248000, + "eu-west-3|r4.8xlarge": 2.496000, + "eu-west-3|r4.large": 0.156000, + "eu-west-3|r4.xlarge": 0.312000, + "eu-west-3|r5.12xlarge": 3.552000, + "eu-west-3|r5.16xlarge": 4.736000, + "eu-west-3|r5.24xlarge": 7.104000, + "eu-west-3|r5.2xlarge": 0.592000, + "eu-west-3|r5.4xlarge": 1.184000, + "eu-west-3|r5.8xlarge": 2.368000, + "eu-west-3|r5.large": 0.148000, + "eu-west-3|r5.metal": 7.104000, + "eu-west-3|r5.xlarge": 0.296000, + "eu-west-3|r5a.12xlarge": 3.192000, + "eu-west-3|r5a.16xlarge": 4.256000, + "eu-west-3|r5a.24xlarge": 6.384000, + "eu-west-3|r5a.2xlarge": 0.532000, + "eu-west-3|r5a.4xlarge": 1.064000, + "eu-west-3|r5a.8xlarge": 2.128000, + "eu-west-3|r5a.large": 0.133000, + "eu-west-3|r5a.xlarge": 0.266000, + "eu-west-3|r5ad.12xlarge": 3.672000, + "eu-west-3|r5ad.16xlarge": 4.896000, + "eu-west-3|r5ad.24xlarge": 7.344000, + "eu-west-3|r5ad.2xlarge": 0.612000, + "eu-west-3|r5ad.4xlarge": 1.224000, + "eu-west-3|r5ad.8xlarge": 2.448000, + "eu-west-3|r5ad.large": 0.153000, + "eu-west-3|r5ad.xlarge": 0.306000, + "eu-west-3|r5d.12xlarge": 4.056000, + "eu-west-3|r5d.16xlarge": 5.408000, + "eu-west-3|r5d.24xlarge": 8.112000, + "eu-west-3|r5d.2xlarge": 0.676000, + "eu-west-3|r5d.4xlarge": 1.352000, + "eu-west-3|r5d.8xlarge": 2.704000, + "eu-west-3|r5d.large": 0.169000, + "eu-west-3|r5d.metal": 8.112000, + "eu-west-3|r5d.xlarge": 0.338000, + "eu-west-3|r5dn.12xlarge": 4.704000, + "eu-west-3|r5dn.16xlarge": 6.272000, + "eu-west-3|r5dn.24xlarge": 9.408000, + "eu-west-3|r5dn.2xlarge": 0.784000, + "eu-west-3|r5dn.4xlarge": 1.568000, + "eu-west-3|r5dn.8xlarge": 3.136000, + "eu-west-3|r5dn.large": 0.196000, + "eu-west-3|r5dn.metal": 9.408000, + "eu-west-3|r5dn.xlarge": 0.392000, + "eu-west-3|r5n.12xlarge": 4.200000, + "eu-west-3|r5n.16xlarge": 5.600000, + "eu-west-3|r5n.24xlarge": 8.400000, + "eu-west-3|r5n.2xlarge": 0.700000, + "eu-west-3|r5n.4xlarge": 1.400000, + "eu-west-3|r5n.8xlarge": 2.800000, + "eu-west-3|r5n.large": 0.175000, + "eu-west-3|r5n.metal": 8.400000, + "eu-west-3|r5n.xlarge": 0.350000, + "eu-west-3|r6g.12xlarge": 2.832000, + "eu-west-3|r6g.16xlarge": 3.776000, + "eu-west-3|r6g.2xlarge": 0.472000, + "eu-west-3|r6g.4xlarge": 0.944000, + "eu-west-3|r6g.8xlarge": 1.888000, + "eu-west-3|r6g.large": 0.118000, + "eu-west-3|r6g.medium": 0.059000, + "eu-west-3|r6g.metal": 3.776000, + "eu-west-3|r6g.xlarge": 0.236000, + "eu-west-3|r6gd.12xlarge": 3.244800, + "eu-west-3|r6gd.16xlarge": 4.326400, + "eu-west-3|r6gd.2xlarge": 0.540800, + "eu-west-3|r6gd.4xlarge": 1.081600, + "eu-west-3|r6gd.8xlarge": 2.163200, + "eu-west-3|r6gd.large": 0.135200, + "eu-west-3|r6gd.medium": 0.067600, + "eu-west-3|r6gd.metal": 4.326400, + "eu-west-3|r6gd.xlarge": 0.270400, + "eu-west-3|r6i.12xlarge": 3.552000, + "eu-west-3|r6i.16xlarge": 4.736000, + "eu-west-3|r6i.24xlarge": 7.104000, + "eu-west-3|r6i.2xlarge": 0.592000, + "eu-west-3|r6i.32xlarge": 9.472000, + "eu-west-3|r6i.4xlarge": 1.184000, + "eu-west-3|r6i.8xlarge": 2.368000, + "eu-west-3|r6i.large": 0.148000, + "eu-west-3|r6i.metal": 9.472000, + "eu-west-3|r6i.xlarge": 0.296000, + "eu-west-3|r7g.12xlarge": 3.019200, + "eu-west-3|r7g.16xlarge": 4.025600, + "eu-west-3|r7g.2xlarge": 0.503200, + "eu-west-3|r7g.4xlarge": 1.006400, + "eu-west-3|r7g.8xlarge": 2.012800, + "eu-west-3|r7g.large": 0.125800, + "eu-west-3|r7g.medium": 0.062900, + "eu-west-3|r7g.metal": 4.025600, + "eu-west-3|r7g.xlarge": 0.251600, + "eu-west-3|r7i.12xlarge": 3.729600, + "eu-west-3|r7i.16xlarge": 4.972800, + "eu-west-3|r7i.24xlarge": 7.459200, + "eu-west-3|r7i.2xlarge": 0.621600, + "eu-west-3|r7i.48xlarge": 14.918400, + "eu-west-3|r7i.4xlarge": 1.243200, + "eu-west-3|r7i.8xlarge": 2.486400, + "eu-west-3|r7i.large": 0.155400, + "eu-west-3|r7i.metal-24xl": 7.459200, + "eu-west-3|r7i.metal-48xl": 14.918400, + "eu-west-3|r7i.xlarge": 0.310800, + "eu-west-3|r8g.12xlarge": 3.321120, + "eu-west-3|r8g.16xlarge": 4.428160, + "eu-west-3|r8g.24xlarge": 6.642240, + "eu-west-3|r8g.2xlarge": 0.553520, + "eu-west-3|r8g.48xlarge": 13.284480, + "eu-west-3|r8g.4xlarge": 1.107040, + "eu-west-3|r8g.8xlarge": 2.214080, + "eu-west-3|r8g.large": 0.138380, + "eu-west-3|r8g.medium": 0.069190, + "eu-west-3|r8g.metal-24xl": 6.642240, + "eu-west-3|r8g.metal-48xl": 13.284480, + "eu-west-3|r8g.xlarge": 0.276760, + "eu-west-3|r8i-flex.12xlarge": 3.720240, + "eu-west-3|r8i-flex.16xlarge": 4.960320, + "eu-west-3|r8i-flex.2xlarge": 0.620040, + "eu-west-3|r8i-flex.4xlarge": 1.240080, + "eu-west-3|r8i-flex.8xlarge": 2.480160, + "eu-west-3|r8i-flex.large": 0.155010, + "eu-west-3|r8i-flex.xlarge": 0.310020, + "eu-west-3|r8i.12xlarge": 3.916080, + "eu-west-3|r8i.16xlarge": 5.221440, + "eu-west-3|r8i.24xlarge": 7.832160, + "eu-west-3|r8i.2xlarge": 0.652680, + "eu-west-3|r8i.32xlarge": 10.442880, + "eu-west-3|r8i.48xlarge": 15.664320, + "eu-west-3|r8i.4xlarge": 1.305360, + "eu-west-3|r8i.8xlarge": 2.610720, + "eu-west-3|r8i.96xlarge": 31.328640, + "eu-west-3|r8i.large": 0.163170, + "eu-west-3|r8i.metal-48xl": 15.664320, + "eu-west-3|r8i.metal-96xl": 31.328640, + "eu-west-3|r8i.xlarge": 0.326340, + "eu-west-3|t2.2xlarge": 0.422400, + "eu-west-3|t2.large": 0.105600, + "eu-west-3|t2.medium": 0.052800, + "eu-west-3|t2.micro": 0.013200, + "eu-west-3|t2.nano": 0.006600, + "eu-west-3|t2.small": 0.026400, + "eu-west-3|t2.xlarge": 0.211200, + "eu-west-3|t3.2xlarge": 0.377600, + "eu-west-3|t3.large": 0.094400, + "eu-west-3|t3.medium": 0.047200, + "eu-west-3|t3.micro": 0.011800, + "eu-west-3|t3.nano": 0.005900, + "eu-west-3|t3.small": 0.023600, + "eu-west-3|t3.xlarge": 0.188800, + "eu-west-3|t3a.2xlarge": 0.339800, + "eu-west-3|t3a.large": 0.085000, + "eu-west-3|t3a.medium": 0.042500, + "eu-west-3|t3a.micro": 0.010600, + "eu-west-3|t3a.nano": 0.005300, + "eu-west-3|t3a.small": 0.021200, + "eu-west-3|t3a.xlarge": 0.169900, + "eu-west-3|t4g.2xlarge": 0.300800, + "eu-west-3|t4g.large": 0.075200, + "eu-west-3|t4g.medium": 0.037600, + "eu-west-3|t4g.micro": 0.009400, + "eu-west-3|t4g.nano": 0.004700, + "eu-west-3|t4g.small": 0.018800, + "eu-west-3|t4g.xlarge": 0.150400, + "eu-west-3|u-3tb1.56xlarge": 32.077500, + "eu-west-3|u-6tb1.112xlarge": 64.133000, + "eu-west-3|u-6tb1.56xlarge": 54.505890, + "eu-west-3|u-9tb1.112xlarge": 96.200000, + "eu-west-3|u7i-6tb.112xlarge": 73.752950, + "eu-west-3|x1.16xlarge": 8.403000, + "eu-west-3|x1.32xlarge": 16.806000, + "eu-west-3|x2idn.16xlarge": 8.403000, + "eu-west-3|x2idn.24xlarge": 12.604500, + "eu-west-3|x2idn.32xlarge": 16.806000, + "eu-west-3|x2idn.metal": 16.806000, + "eu-west-3|x2iedn.16xlarge": 16.806000, + "eu-west-3|x2iedn.24xlarge": 25.209000, + "eu-west-3|x2iedn.2xlarge": 2.100750, + "eu-west-3|x2iedn.32xlarge": 33.612000, + "eu-west-3|x2iedn.4xlarge": 4.201500, + "eu-west-3|x2iedn.8xlarge": 8.403000, + "eu-west-3|x2iedn.metal": 33.612000, + "eu-west-3|x2iedn.xlarge": 1.050380, + "sa-east-1|c1.medium": 0.179000, + "sa-east-1|c1.xlarge": 0.718000, + "sa-east-1|c3.2xlarge": 0.650000, + "sa-east-1|c3.4xlarge": 1.300000, + "sa-east-1|c3.8xlarge": 2.600000, + "sa-east-1|c3.large": 0.163000, + "sa-east-1|c3.xlarge": 0.325000, + "sa-east-1|c4.2xlarge": 0.618000, + "sa-east-1|c4.4xlarge": 1.235000, + "sa-east-1|c4.8xlarge": 2.470000, + "sa-east-1|c4.large": 0.155000, + "sa-east-1|c4.xlarge": 0.309000, + "sa-east-1|c5.12xlarge": 3.144000, + "sa-east-1|c5.18xlarge": 4.716000, + "sa-east-1|c5.24xlarge": 6.288000, + "sa-east-1|c5.2xlarge": 0.524000, + "sa-east-1|c5.4xlarge": 1.048000, + "sa-east-1|c5.9xlarge": 2.358000, + "sa-east-1|c5.large": 0.131000, + "sa-east-1|c5.metal": 6.288000, + "sa-east-1|c5.xlarge": 0.262000, + "sa-east-1|c5a.12xlarge": 2.832000, + "sa-east-1|c5a.16xlarge": 3.776000, + "sa-east-1|c5a.24xlarge": 5.664000, + "sa-east-1|c5a.2xlarge": 0.472000, + "sa-east-1|c5a.4xlarge": 0.944000, + "sa-east-1|c5a.8xlarge": 1.888000, + "sa-east-1|c5a.large": 0.118000, + "sa-east-1|c5a.xlarge": 0.236000, + "sa-east-1|c5ad.12xlarge": 3.216000, + "sa-east-1|c5ad.16xlarge": 4.288000, + "sa-east-1|c5ad.24xlarge": 6.432000, + "sa-east-1|c5ad.2xlarge": 0.536000, + "sa-east-1|c5ad.4xlarge": 1.072000, + "sa-east-1|c5ad.8xlarge": 2.144000, + "sa-east-1|c5ad.large": 0.134000, + "sa-east-1|c5ad.xlarge": 0.268000, + "sa-east-1|c5d.12xlarge": 3.576000, + "sa-east-1|c5d.18xlarge": 5.364000, + "sa-east-1|c5d.24xlarge": 7.152000, + "sa-east-1|c5d.2xlarge": 0.596000, + "sa-east-1|c5d.4xlarge": 1.192000, + "sa-east-1|c5d.9xlarge": 2.682000, + "sa-east-1|c5d.large": 0.149000, + "sa-east-1|c5d.metal": 7.152000, + "sa-east-1|c5d.xlarge": 0.298000, + "sa-east-1|c5n.18xlarge": 5.976000, + "sa-east-1|c5n.2xlarge": 0.664000, + "sa-east-1|c5n.4xlarge": 1.328000, + "sa-east-1|c5n.9xlarge": 2.988000, + "sa-east-1|c5n.large": 0.166000, + "sa-east-1|c5n.metal": 5.976000, + "sa-east-1|c5n.xlarge": 0.332000, + "sa-east-1|c6a.12xlarge": 2.829600, + "sa-east-1|c6a.16xlarge": 3.772800, + "sa-east-1|c6a.24xlarge": 5.659200, + "sa-east-1|c6a.2xlarge": 0.471600, + "sa-east-1|c6a.32xlarge": 7.545600, + "sa-east-1|c6a.48xlarge": 11.318400, + "sa-east-1|c6a.4xlarge": 0.943200, + "sa-east-1|c6a.8xlarge": 1.886400, + "sa-east-1|c6a.large": 0.117900, + "sa-east-1|c6a.metal": 11.318400, + "sa-east-1|c6a.xlarge": 0.235800, + "sa-east-1|c6g.12xlarge": 2.515200, + "sa-east-1|c6g.16xlarge": 3.353600, + "sa-east-1|c6g.2xlarge": 0.419200, + "sa-east-1|c6g.4xlarge": 0.838400, + "sa-east-1|c6g.8xlarge": 1.676800, + "sa-east-1|c6g.large": 0.104800, + "sa-east-1|c6g.medium": 0.052400, + "sa-east-1|c6g.metal": 3.353600, + "sa-east-1|c6g.xlarge": 0.209600, + "sa-east-1|c6gd.12xlarge": 2.856000, + "sa-east-1|c6gd.16xlarge": 3.808000, + "sa-east-1|c6gd.2xlarge": 0.476000, + "sa-east-1|c6gd.4xlarge": 0.952000, + "sa-east-1|c6gd.8xlarge": 1.904000, + "sa-east-1|c6gd.large": 0.119000, + "sa-east-1|c6gd.medium": 0.059500, + "sa-east-1|c6gd.metal": 3.808000, + "sa-east-1|c6gd.xlarge": 0.238000, + "sa-east-1|c6gn.12xlarge": 3.192000, + "sa-east-1|c6gn.16xlarge": 4.256000, + "sa-east-1|c6gn.2xlarge": 0.532000, + "sa-east-1|c6gn.4xlarge": 1.064000, + "sa-east-1|c6gn.8xlarge": 2.128000, + "sa-east-1|c6gn.large": 0.133000, + "sa-east-1|c6gn.medium": 0.066500, + "sa-east-1|c6gn.xlarge": 0.266000, + "sa-east-1|c6i.12xlarge": 3.144000, + "sa-east-1|c6i.16xlarge": 4.192000, + "sa-east-1|c6i.24xlarge": 6.288000, + "sa-east-1|c6i.2xlarge": 0.524000, + "sa-east-1|c6i.32xlarge": 8.384000, + "sa-east-1|c6i.4xlarge": 1.048000, + "sa-east-1|c6i.8xlarge": 2.096000, + "sa-east-1|c6i.large": 0.131000, + "sa-east-1|c6i.metal": 8.384000, + "sa-east-1|c6i.xlarge": 0.262000, + "sa-east-1|c6id.12xlarge": 3.754800, + "sa-east-1|c6id.16xlarge": 5.006400, + "sa-east-1|c6id.24xlarge": 7.509600, + "sa-east-1|c6id.2xlarge": 0.625800, + "sa-east-1|c6id.32xlarge": 10.012800, + "sa-east-1|c6id.4xlarge": 1.251600, + "sa-east-1|c6id.8xlarge": 2.503200, + "sa-east-1|c6id.large": 0.156450, + "sa-east-1|c6id.metal": 10.012800, + "sa-east-1|c6id.xlarge": 0.312900, + "sa-east-1|c6in.12xlarge": 4.183200, + "sa-east-1|c6in.16xlarge": 5.577600, + "sa-east-1|c6in.24xlarge": 8.366400, + "sa-east-1|c6in.2xlarge": 0.697200, + "sa-east-1|c6in.32xlarge": 11.155200, + "sa-east-1|c6in.4xlarge": 1.394400, + "sa-east-1|c6in.8xlarge": 2.788800, + "sa-east-1|c6in.large": 0.174300, + "sa-east-1|c6in.metal": 11.155200, + "sa-east-1|c6in.xlarge": 0.348600, + "sa-east-1|c7g.12xlarge": 2.665900, + "sa-east-1|c7g.16xlarge": 3.554600, + "sa-east-1|c7g.2xlarge": 0.444300, + "sa-east-1|c7g.4xlarge": 0.888600, + "sa-east-1|c7g.8xlarge": 1.777300, + "sa-east-1|c7g.large": 0.111100, + "sa-east-1|c7g.medium": 0.055500, + "sa-east-1|c7g.metal": 3.554600, + "sa-east-1|c7g.xlarge": 0.222200, + "sa-east-1|c7gd.12xlarge": 3.379200, + "sa-east-1|c7gd.16xlarge": 4.505600, + "sa-east-1|c7gd.2xlarge": 0.563200, + "sa-east-1|c7gd.4xlarge": 1.126400, + "sa-east-1|c7gd.8xlarge": 2.252800, + "sa-east-1|c7gd.large": 0.140800, + "sa-east-1|c7gd.medium": 0.070400, + "sa-east-1|c7gd.metal": 4.505600, + "sa-east-1|c7gd.xlarge": 0.281600, + "sa-east-1|c7i-flex.12xlarge": 3.136140, + "sa-east-1|c7i-flex.16xlarge": 4.181520, + "sa-east-1|c7i-flex.2xlarge": 0.522690, + "sa-east-1|c7i-flex.4xlarge": 1.045380, + "sa-east-1|c7i-flex.8xlarge": 2.090760, + "sa-east-1|c7i-flex.large": 0.130670, + "sa-east-1|c7i-flex.xlarge": 0.261350, + "sa-east-1|c7i.12xlarge": 3.301200, + "sa-east-1|c7i.16xlarge": 4.401600, + "sa-east-1|c7i.24xlarge": 6.602400, + "sa-east-1|c7i.2xlarge": 0.550200, + "sa-east-1|c7i.48xlarge": 13.204800, + "sa-east-1|c7i.4xlarge": 1.100400, + "sa-east-1|c7i.8xlarge": 2.200800, + "sa-east-1|c7i.large": 0.137550, + "sa-east-1|c7i.metal-24xl": 6.602400, + "sa-east-1|c7i.metal-48xl": 13.204800, + "sa-east-1|c7i.xlarge": 0.275100, + "sa-east-1|c8g.12xlarge": 2.932320, + "sa-east-1|c8g.16xlarge": 3.909760, + "sa-east-1|c8g.24xlarge": 5.864640, + "sa-east-1|c8g.2xlarge": 0.488720, + "sa-east-1|c8g.48xlarge": 11.729280, + "sa-east-1|c8g.4xlarge": 0.977440, + "sa-east-1|c8g.8xlarge": 1.954880, + "sa-east-1|c8g.large": 0.122180, + "sa-east-1|c8g.medium": 0.061090, + "sa-east-1|c8g.metal-24xl": 5.864640, + "sa-east-1|c8g.metal-48xl": 11.729280, + "sa-east-1|c8g.xlarge": 0.244360, + "sa-east-1|g4dn.12xlarge": 6.649000, + "sa-east-1|g4dn.16xlarge": 7.397000, + "sa-east-1|g4dn.2xlarge": 1.278000, + "sa-east-1|g4dn.4xlarge": 2.046000, + "sa-east-1|g4dn.8xlarge": 3.698000, + "sa-east-1|g4dn.metal": 13.298000, + "sa-east-1|g4dn.xlarge": 0.894000, + "sa-east-1|g5.12xlarge": 9.641270, + "sa-east-1|g5.16xlarge": 6.962390, + "sa-east-1|g5.24xlarge": 13.843180, + "sa-east-1|g5.2xlarge": 2.060160, + "sa-east-1|g5.48xlarge": 27.686360, + "sa-east-1|g5.4xlarge": 2.760480, + "sa-east-1|g5.8xlarge": 4.161110, + "sa-east-1|g5.xlarge": 1.710000, + "sa-east-1|g6.12xlarge": 7.821810, + "sa-east-1|g6.16xlarge": 5.773880, + "sa-east-1|g6.24xlarge": 11.346510, + "sa-east-1|g6.2xlarge": 1.661730, + "sa-east-1|g6.48xlarge": 22.693030, + "sa-east-1|g6.4xlarge": 2.249180, + "sa-east-1|g6.8xlarge": 3.424080, + "sa-east-1|g6.xlarge": 1.368000, + "sa-east-1|g6f.2xlarge": 0.807420, + "sa-east-1|g6f.4xlarge": 1.614830, + "sa-east-1|g6f.large": 0.343360, + "sa-east-1|g6f.xlarge": 0.403710, + "sa-east-1|gr6.4xlarge": 2.616400, + "sa-east-1|gr6.8xlarge": 4.158500, + "sa-east-1|gr6f.4xlarge": 1.812030, + "sa-east-1|i3.16xlarge": 7.968000, + "sa-east-1|i3.2xlarge": 0.996000, + "sa-east-1|i3.4xlarge": 1.992000, + "sa-east-1|i3.8xlarge": 3.984000, + "sa-east-1|i3.large": 0.249000, + "sa-east-1|i3.metal": 7.968000, + "sa-east-1|i3.xlarge": 0.498000, + "sa-east-1|i3en.12xlarge": 8.640000, + "sa-east-1|i3en.24xlarge": 17.280000, + "sa-east-1|i3en.2xlarge": 1.440000, + "sa-east-1|i3en.3xlarge": 2.160000, + "sa-east-1|i3en.6xlarge": 4.320000, + "sa-east-1|i3en.large": 0.360000, + "sa-east-1|i3en.metal": 17.280000, + "sa-east-1|i3en.xlarge": 0.720000, + "sa-east-1|i4g.16xlarge": 7.891200, + "sa-east-1|i4g.2xlarge": 0.986400, + "sa-east-1|i4g.4xlarge": 1.972800, + "sa-east-1|i4g.8xlarge": 3.945600, + "sa-east-1|i4g.large": 0.246600, + "sa-east-1|i4g.xlarge": 0.493200, + "sa-east-1|i4i.12xlarge": 6.574000, + "sa-east-1|i4i.16xlarge": 8.765000, + "sa-east-1|i4i.24xlarge": 13.147200, + "sa-east-1|i4i.2xlarge": 1.096000, + "sa-east-1|i4i.32xlarge": 17.529600, + "sa-east-1|i4i.4xlarge": 2.191000, + "sa-east-1|i4i.8xlarge": 4.382000, + "sa-east-1|i4i.large": 0.274000, + "sa-east-1|i4i.metal": 17.530000, + "sa-east-1|i4i.xlarge": 0.548000, + "sa-east-1|i7i.12xlarge": 7.231000, + "sa-east-1|i7i.16xlarge": 9.641300, + "sa-east-1|i7i.24xlarge": 14.461900, + "sa-east-1|i7i.2xlarge": 1.205200, + "sa-east-1|i7i.48xlarge": 28.923800, + "sa-east-1|i7i.4xlarge": 2.410300, + "sa-east-1|i7i.8xlarge": 4.820600, + "sa-east-1|i7i.large": 0.301300, + "sa-east-1|i7i.metal-24xl": 14.461900, + "sa-east-1|i7i.metal-48xl": 28.923800, + "sa-east-1|i7i.xlarge": 0.602600, + "sa-east-1|i7ie.12xlarge": 9.936000, + "sa-east-1|i7ie.18xlarge": 14.904000, + "sa-east-1|i7ie.24xlarge": 19.872000, + "sa-east-1|i7ie.2xlarge": 1.656000, + "sa-east-1|i7ie.3xlarge": 2.484000, + "sa-east-1|i7ie.48xlarge": 39.744000, + "sa-east-1|i7ie.6xlarge": 4.968000, + "sa-east-1|i7ie.large": 0.414000, + "sa-east-1|i7ie.metal-24xl": 19.872000, + "sa-east-1|i7ie.metal-48xl": 39.744000, + "sa-east-1|i7ie.xlarge": 0.828000, + "sa-east-1|i8g.12xlarge": 6.576000, + "sa-east-1|i8g.16xlarge": 8.768000, + "sa-east-1|i8g.24xlarge": 13.152000, + "sa-east-1|i8g.2xlarge": 1.096000, + "sa-east-1|i8g.48xlarge": 26.304000, + "sa-east-1|i8g.4xlarge": 2.192000, + "sa-east-1|i8g.8xlarge": 4.384000, + "sa-east-1|i8g.large": 0.274000, + "sa-east-1|i8g.metal-24xl": 13.152000, + "sa-east-1|i8g.xlarge": 0.548000, + "sa-east-1|inf1.24xlarge": 7.800000, + "sa-east-1|inf1.2xlarge": 0.598000, + "sa-east-1|inf1.6xlarge": 1.950000, + "sa-east-1|inf1.xlarge": 0.377000, + "sa-east-1|inf2.24xlarge": 11.034080, + "sa-east-1|inf2.48xlarge": 22.068150, + "sa-east-1|inf2.8xlarge": 3.345360, + "sa-east-1|inf2.xlarge": 1.288940, + "sa-east-1|m1.large": 0.233000, + "sa-east-1|m1.medium": 0.117000, + "sa-east-1|m1.small": 0.058000, + "sa-east-1|m1.xlarge": 0.467000, + "sa-east-1|m2.2xlarge": 0.645000, + "sa-east-1|m2.4xlarge": 1.291000, + "sa-east-1|m2.xlarge": 0.323000, + "sa-east-1|m3.2xlarge": 0.761000, + "sa-east-1|m3.large": 0.190000, + "sa-east-1|m3.medium": 0.095000, + "sa-east-1|m3.xlarge": 0.381000, + "sa-east-1|m4.10xlarge": 3.180000, + "sa-east-1|m4.16xlarge": 5.088000, + "sa-east-1|m4.2xlarge": 0.636000, + "sa-east-1|m4.4xlarge": 1.272000, + "sa-east-1|m4.large": 0.159000, + "sa-east-1|m4.xlarge": 0.318000, + "sa-east-1|m5.12xlarge": 3.672000, + "sa-east-1|m5.16xlarge": 4.896000, + "sa-east-1|m5.24xlarge": 7.344000, + "sa-east-1|m5.2xlarge": 0.612000, + "sa-east-1|m5.4xlarge": 1.224000, + "sa-east-1|m5.8xlarge": 2.448000, + "sa-east-1|m5.large": 0.153000, + "sa-east-1|m5.metal": 7.344000, + "sa-east-1|m5.xlarge": 0.306000, + "sa-east-1|m5a.12xlarge": 3.312000, + "sa-east-1|m5a.16xlarge": 4.416000, + "sa-east-1|m5a.24xlarge": 6.624000, + "sa-east-1|m5a.2xlarge": 0.552000, + "sa-east-1|m5a.4xlarge": 1.104000, + "sa-east-1|m5a.8xlarge": 2.208000, + "sa-east-1|m5a.large": 0.138000, + "sa-east-1|m5a.xlarge": 0.276000, + "sa-east-1|m5ad.12xlarge": 3.960000, + "sa-east-1|m5ad.16xlarge": 5.280000, + "sa-east-1|m5ad.24xlarge": 7.920000, + "sa-east-1|m5ad.2xlarge": 0.660000, + "sa-east-1|m5ad.4xlarge": 1.320000, + "sa-east-1|m5ad.8xlarge": 2.640000, + "sa-east-1|m5ad.large": 0.165000, + "sa-east-1|m5ad.xlarge": 0.330000, + "sa-east-1|m5d.12xlarge": 4.320000, + "sa-east-1|m5d.16xlarge": 5.760000, + "sa-east-1|m5d.24xlarge": 8.640000, + "sa-east-1|m5d.2xlarge": 0.720000, + "sa-east-1|m5d.4xlarge": 1.440000, + "sa-east-1|m5d.8xlarge": 2.880000, + "sa-east-1|m5d.large": 0.180000, + "sa-east-1|m5d.metal": 8.640000, + "sa-east-1|m5d.xlarge": 0.360000, + "sa-east-1|m5zn.12xlarge": 6.317800, + "sa-east-1|m5zn.2xlarge": 1.053000, + "sa-east-1|m5zn.3xlarge": 1.579400, + "sa-east-1|m5zn.6xlarge": 3.158900, + "sa-east-1|m5zn.large": 0.263200, + "sa-east-1|m5zn.metal": 6.317800, + "sa-east-1|m5zn.xlarge": 0.526500, + "sa-east-1|m6a.12xlarge": 3.304800, + "sa-east-1|m6a.16xlarge": 4.406400, + "sa-east-1|m6a.24xlarge": 6.609600, + "sa-east-1|m6a.2xlarge": 0.550800, + "sa-east-1|m6a.32xlarge": 8.812800, + "sa-east-1|m6a.48xlarge": 13.219200, + "sa-east-1|m6a.4xlarge": 1.101600, + "sa-east-1|m6a.8xlarge": 2.203200, + "sa-east-1|m6a.large": 0.137700, + "sa-east-1|m6a.metal": 13.219200, + "sa-east-1|m6a.xlarge": 0.275400, + "sa-east-1|m6g.12xlarge": 2.937600, + "sa-east-1|m6g.16xlarge": 3.916800, + "sa-east-1|m6g.2xlarge": 0.489600, + "sa-east-1|m6g.4xlarge": 0.979200, + "sa-east-1|m6g.8xlarge": 1.958400, + "sa-east-1|m6g.large": 0.122400, + "sa-east-1|m6g.medium": 0.061200, + "sa-east-1|m6g.metal": 3.916800, + "sa-east-1|m6g.xlarge": 0.244800, + "sa-east-1|m6gd.12xlarge": 3.456000, + "sa-east-1|m6gd.16xlarge": 4.608000, + "sa-east-1|m6gd.2xlarge": 0.576000, + "sa-east-1|m6gd.4xlarge": 1.152000, + "sa-east-1|m6gd.8xlarge": 2.304000, + "sa-east-1|m6gd.large": 0.144000, + "sa-east-1|m6gd.medium": 0.072000, + "sa-east-1|m6gd.metal": 4.608000, + "sa-east-1|m6gd.xlarge": 0.288000, + "sa-east-1|m6i.12xlarge": 3.672000, + "sa-east-1|m6i.16xlarge": 4.896000, + "sa-east-1|m6i.24xlarge": 7.344000, + "sa-east-1|m6i.2xlarge": 0.612000, + "sa-east-1|m6i.32xlarge": 9.792000, + "sa-east-1|m6i.4xlarge": 1.224000, + "sa-east-1|m6i.8xlarge": 2.448000, + "sa-east-1|m6i.large": 0.153000, + "sa-east-1|m6i.metal": 9.792000, + "sa-east-1|m6i.xlarge": 0.306000, + "sa-east-1|m6id.12xlarge": 4.536000, + "sa-east-1|m6id.16xlarge": 6.048000, + "sa-east-1|m6id.24xlarge": 9.072000, + "sa-east-1|m6id.2xlarge": 0.756000, + "sa-east-1|m6id.32xlarge": 12.096000, + "sa-east-1|m6id.4xlarge": 1.512000, + "sa-east-1|m6id.8xlarge": 3.024000, + "sa-east-1|m6id.large": 0.189000, + "sa-east-1|m6id.metal": 12.096000, + "sa-east-1|m6id.xlarge": 0.378000, + "sa-east-1|m7g.12xlarge": 3.121200, + "sa-east-1|m7g.16xlarge": 4.161600, + "sa-east-1|m7g.2xlarge": 0.520200, + "sa-east-1|m7g.4xlarge": 1.040400, + "sa-east-1|m7g.8xlarge": 2.080800, + "sa-east-1|m7g.large": 0.130100, + "sa-east-1|m7g.medium": 0.065000, + "sa-east-1|m7g.metal": 4.161600, + "sa-east-1|m7g.xlarge": 0.260100, + "sa-east-1|m7gd.12xlarge": 4.082400, + "sa-east-1|m7gd.16xlarge": 5.443200, + "sa-east-1|m7gd.2xlarge": 0.680400, + "sa-east-1|m7gd.4xlarge": 1.360800, + "sa-east-1|m7gd.8xlarge": 2.721600, + "sa-east-1|m7gd.large": 0.170100, + "sa-east-1|m7gd.medium": 0.085100, + "sa-east-1|m7gd.metal": 5.443200, + "sa-east-1|m7gd.xlarge": 0.340200, + "sa-east-1|m7i-flex.12xlarge": 3.662880, + "sa-east-1|m7i-flex.16xlarge": 4.883840, + "sa-east-1|m7i-flex.2xlarge": 0.610480, + "sa-east-1|m7i-flex.4xlarge": 1.220960, + "sa-east-1|m7i-flex.8xlarge": 2.441920, + "sa-east-1|m7i-flex.large": 0.152620, + "sa-east-1|m7i-flex.xlarge": 0.305240, + "sa-east-1|m7i.12xlarge": 3.855600, + "sa-east-1|m7i.16xlarge": 5.140800, + "sa-east-1|m7i.24xlarge": 7.711200, + "sa-east-1|m7i.2xlarge": 0.642600, + "sa-east-1|m7i.48xlarge": 15.422400, + "sa-east-1|m7i.4xlarge": 1.285200, + "sa-east-1|m7i.8xlarge": 2.570400, + "sa-east-1|m7i.large": 0.160650, + "sa-east-1|m7i.metal-24xl": 7.711200, + "sa-east-1|m7i.metal-48xl": 15.422400, + "sa-east-1|m7i.xlarge": 0.321300, + "sa-east-1|m8g.12xlarge": 3.433440, + "sa-east-1|m8g.16xlarge": 4.577920, + "sa-east-1|m8g.24xlarge": 6.866880, + "sa-east-1|m8g.2xlarge": 0.572240, + "sa-east-1|m8g.48xlarge": 13.733760, + "sa-east-1|m8g.4xlarge": 1.144480, + "sa-east-1|m8g.8xlarge": 2.288960, + "sa-east-1|m8g.large": 0.143060, + "sa-east-1|m8g.medium": 0.071530, + "sa-east-1|m8g.metal-24xl": 6.866880, + "sa-east-1|m8g.metal-48xl": 13.733760, + "sa-east-1|m8g.xlarge": 0.286120, + "sa-east-1|m8gd.12xlarge": 4.408800, + "sa-east-1|m8gd.16xlarge": 5.878400, + "sa-east-1|m8gd.24xlarge": 8.817600, + "sa-east-1|m8gd.2xlarge": 0.734800, + "sa-east-1|m8gd.48xlarge": 17.635200, + "sa-east-1|m8gd.4xlarge": 1.469600, + "sa-east-1|m8gd.8xlarge": 2.939200, + "sa-east-1|m8gd.large": 0.183700, + "sa-east-1|m8gd.medium": 0.091850, + "sa-east-1|m8gd.metal-24xl": 8.817600, + "sa-east-1|m8gd.metal-48xl": 17.635200, + "sa-east-1|m8gd.xlarge": 0.367400, + "sa-east-1|p4d.24xlarge": 35.556900, + "sa-east-1|p5.48xlarge": 92.467200, + "sa-east-1|p5.4xlarge": 11.558400, + "sa-east-1|r3.2xlarge": 1.399000, + "sa-east-1|r3.4xlarge": 2.799000, + "sa-east-1|r3.8xlarge": 5.597000, + "sa-east-1|r3.large": 0.350000, + "sa-east-1|r3.xlarge": 0.700000, + "sa-east-1|r4.16xlarge": 8.960000, + "sa-east-1|r4.2xlarge": 1.120000, + "sa-east-1|r4.4xlarge": 2.240000, + "sa-east-1|r4.8xlarge": 4.480000, + "sa-east-1|r4.large": 0.280000, + "sa-east-1|r4.xlarge": 0.560000, + "sa-east-1|r5.12xlarge": 4.824000, + "sa-east-1|r5.16xlarge": 6.432000, + "sa-east-1|r5.24xlarge": 9.648000, + "sa-east-1|r5.2xlarge": 0.804000, + "sa-east-1|r5.4xlarge": 1.608000, + "sa-east-1|r5.8xlarge": 3.216000, + "sa-east-1|r5.large": 0.201000, + "sa-east-1|r5.metal": 9.648000, + "sa-east-1|r5.xlarge": 0.402000, + "sa-east-1|r5a.12xlarge": 4.344000, + "sa-east-1|r5a.16xlarge": 5.792000, + "sa-east-1|r5a.24xlarge": 8.688000, + "sa-east-1|r5a.2xlarge": 0.724000, + "sa-east-1|r5a.4xlarge": 1.448000, + "sa-east-1|r5a.8xlarge": 2.896000, + "sa-east-1|r5a.large": 0.181000, + "sa-east-1|r5a.xlarge": 0.362000, + "sa-east-1|r5ad.12xlarge": 4.992000, + "sa-east-1|r5ad.16xlarge": 6.656000, + "sa-east-1|r5ad.24xlarge": 9.984000, + "sa-east-1|r5ad.2xlarge": 0.832000, + "sa-east-1|r5ad.4xlarge": 1.664000, + "sa-east-1|r5ad.8xlarge": 3.328000, + "sa-east-1|r5ad.large": 0.208000, + "sa-east-1|r5ad.xlarge": 0.416000, + "sa-east-1|r5b.12xlarge": 5.688000, + "sa-east-1|r5b.16xlarge": 7.584000, + "sa-east-1|r5b.24xlarge": 11.376000, + "sa-east-1|r5b.2xlarge": 0.948000, + "sa-east-1|r5b.4xlarge": 1.896000, + "sa-east-1|r5b.8xlarge": 3.792000, + "sa-east-1|r5b.large": 0.237000, + "sa-east-1|r5b.metal": 11.376000, + "sa-east-1|r5b.xlarge": 0.474000, + "sa-east-1|r5d.12xlarge": 5.472000, + "sa-east-1|r5d.16xlarge": 7.296000, + "sa-east-1|r5d.24xlarge": 10.944000, + "sa-east-1|r5d.2xlarge": 0.912000, + "sa-east-1|r5d.4xlarge": 1.824000, + "sa-east-1|r5d.8xlarge": 3.648000, + "sa-east-1|r5d.large": 0.228000, + "sa-east-1|r5d.metal": 10.944000, + "sa-east-1|r5d.xlarge": 0.456000, + "sa-east-1|r5n.12xlarge": 5.664000, + "sa-east-1|r5n.16xlarge": 7.552000, + "sa-east-1|r5n.24xlarge": 11.328000, + "sa-east-1|r5n.2xlarge": 0.944000, + "sa-east-1|r5n.4xlarge": 1.888000, + "sa-east-1|r5n.8xlarge": 3.776000, + "sa-east-1|r5n.large": 0.236000, + "sa-east-1|r5n.metal": 11.328000, + "sa-east-1|r5n.xlarge": 0.472000, + "sa-east-1|r6g.12xlarge": 3.859200, + "sa-east-1|r6g.16xlarge": 5.145600, + "sa-east-1|r6g.2xlarge": 0.643200, + "sa-east-1|r6g.4xlarge": 1.286400, + "sa-east-1|r6g.8xlarge": 2.572800, + "sa-east-1|r6g.large": 0.160800, + "sa-east-1|r6g.medium": 0.080400, + "sa-east-1|r6g.metal": 5.145600, + "sa-east-1|r6g.xlarge": 0.321600, + "sa-east-1|r6gd.12xlarge": 4.377600, + "sa-east-1|r6gd.16xlarge": 5.836800, + "sa-east-1|r6gd.2xlarge": 0.729600, + "sa-east-1|r6gd.4xlarge": 1.459200, + "sa-east-1|r6gd.8xlarge": 2.918400, + "sa-east-1|r6gd.large": 0.182400, + "sa-east-1|r6gd.medium": 0.091200, + "sa-east-1|r6gd.metal": 5.836800, + "sa-east-1|r6gd.xlarge": 0.364800, + "sa-east-1|r6i.12xlarge": 4.824000, + "sa-east-1|r6i.16xlarge": 6.432000, + "sa-east-1|r6i.24xlarge": 9.648000, + "sa-east-1|r6i.2xlarge": 0.804000, + "sa-east-1|r6i.32xlarge": 12.864000, + "sa-east-1|r6i.4xlarge": 1.608000, + "sa-east-1|r6i.8xlarge": 3.216000, + "sa-east-1|r6i.large": 0.201000, + "sa-east-1|r6i.metal": 12.864000, + "sa-east-1|r6i.xlarge": 0.402000, + "sa-east-1|r7g.12xlarge": 4.090600, + "sa-east-1|r7g.16xlarge": 5.454100, + "sa-east-1|r7g.2xlarge": 0.681800, + "sa-east-1|r7g.4xlarge": 1.363500, + "sa-east-1|r7g.8xlarge": 2.727000, + "sa-east-1|r7g.large": 0.170400, + "sa-east-1|r7g.medium": 0.085200, + "sa-east-1|r7g.metal": 5.454100, + "sa-east-1|r7g.xlarge": 0.340900, + "sa-east-1|r7i.12xlarge": 5.065200, + "sa-east-1|r7i.16xlarge": 6.753600, + "sa-east-1|r7i.24xlarge": 10.130400, + "sa-east-1|r7i.2xlarge": 0.844200, + "sa-east-1|r7i.48xlarge": 20.260800, + "sa-east-1|r7i.4xlarge": 1.688400, + "sa-east-1|r7i.8xlarge": 3.376800, + "sa-east-1|r7i.large": 0.211050, + "sa-east-1|r7i.metal-24xl": 10.130400, + "sa-east-1|r7i.metal-48xl": 20.260800, + "sa-east-1|r7i.xlarge": 0.422100, + "sa-east-1|r8g.12xlarge": 4.499520, + "sa-east-1|r8g.16xlarge": 5.999360, + "sa-east-1|r8g.24xlarge": 8.999040, + "sa-east-1|r8g.2xlarge": 0.749920, + "sa-east-1|r8g.48xlarge": 17.998080, + "sa-east-1|r8g.4xlarge": 1.499840, + "sa-east-1|r8g.8xlarge": 2.999680, + "sa-east-1|r8g.large": 0.187480, + "sa-east-1|r8g.medium": 0.093740, + "sa-east-1|r8g.metal-24xl": 8.999040, + "sa-east-1|r8g.metal-48xl": 17.998080, + "sa-east-1|r8g.xlarge": 0.374960, + "sa-east-1|r8gd.12xlarge": 5.584800, + "sa-east-1|r8gd.16xlarge": 7.446400, + "sa-east-1|r8gd.24xlarge": 11.169600, + "sa-east-1|r8gd.2xlarge": 0.930800, + "sa-east-1|r8gd.48xlarge": 22.339200, + "sa-east-1|r8gd.4xlarge": 1.861600, + "sa-east-1|r8gd.8xlarge": 3.723200, + "sa-east-1|r8gd.large": 0.232700, + "sa-east-1|r8gd.medium": 0.116350, + "sa-east-1|r8gd.metal-24xl": 11.169600, + "sa-east-1|r8gd.metal-48xl": 22.339200, + "sa-east-1|r8gd.xlarge": 0.465400, + "sa-east-1|r8i-flex.12xlarge": 5.052480, + "sa-east-1|r8i-flex.16xlarge": 6.736640, + "sa-east-1|r8i-flex.2xlarge": 0.842080, + "sa-east-1|r8i-flex.4xlarge": 1.684160, + "sa-east-1|r8i-flex.8xlarge": 3.368320, + "sa-east-1|r8i-flex.large": 0.210520, + "sa-east-1|r8i-flex.xlarge": 0.421040, + "sa-east-1|r8i.12xlarge": 5.318400, + "sa-east-1|r8i.16xlarge": 7.091200, + "sa-east-1|r8i.24xlarge": 10.636800, + "sa-east-1|r8i.2xlarge": 0.886400, + "sa-east-1|r8i.32xlarge": 14.182400, + "sa-east-1|r8i.48xlarge": 21.273600, + "sa-east-1|r8i.4xlarge": 1.772800, + "sa-east-1|r8i.8xlarge": 3.545600, + "sa-east-1|r8i.96xlarge": 42.547200, + "sa-east-1|r8i.large": 0.221600, + "sa-east-1|r8i.metal-48xl": 21.273600, + "sa-east-1|r8i.metal-96xl": 42.547200, + "sa-east-1|r8i.xlarge": 0.443200, + "sa-east-1|t1.micro": 0.027000, + "sa-east-1|t2.2xlarge": 0.595200, + "sa-east-1|t2.large": 0.148800, + "sa-east-1|t2.medium": 0.074400, + "sa-east-1|t2.micro": 0.018600, + "sa-east-1|t2.nano": 0.009300, + "sa-east-1|t2.small": 0.037200, + "sa-east-1|t2.xlarge": 0.297600, + "sa-east-1|t3.2xlarge": 0.537600, + "sa-east-1|t3.large": 0.134400, + "sa-east-1|t3.medium": 0.067200, + "sa-east-1|t3.micro": 0.016800, + "sa-east-1|t3.nano": 0.008400, + "sa-east-1|t3.small": 0.033600, + "sa-east-1|t3.xlarge": 0.268800, + "sa-east-1|t3a.2xlarge": 0.483800, + "sa-east-1|t3a.large": 0.121000, + "sa-east-1|t3a.medium": 0.060500, + "sa-east-1|t3a.micro": 0.015100, + "sa-east-1|t3a.nano": 0.007600, + "sa-east-1|t3a.small": 0.030200, + "sa-east-1|t3a.xlarge": 0.241900, + "sa-east-1|t4g.2xlarge": 0.428800, + "sa-east-1|t4g.large": 0.107200, + "sa-east-1|t4g.medium": 0.053600, + "sa-east-1|t4g.micro": 0.013400, + "sa-east-1|t4g.nano": 0.006700, + "sa-east-1|t4g.small": 0.026800, + "sa-east-1|t4g.xlarge": 0.214400, + "sa-east-1|u-12tb1.112xlarge": 174.200000, + "sa-east-1|u-18tb1.112xlarge": 261.300000, + "sa-east-1|u-3tb1.56xlarge": 43.550000, + "sa-east-1|u-6tb1.112xlarge": 87.100000, + "sa-east-1|u-6tb1.56xlarge": 74.025280, + "sa-east-1|u-9tb1.112xlarge": 130.650000, + "sa-east-1|u7i-12tb.224xlarge": 200.333110, + "sa-east-1|u7i-8tb.112xlarge": 133.553330, + "sa-east-1|x1.16xlarge": 13.005000, + "sa-east-1|x1.32xlarge": 26.010000, + "sa-east-1|x1e.16xlarge": 26.010000, + "sa-east-1|x1e.2xlarge": 3.251000, + "sa-east-1|x1e.32xlarge": 52.019000, + "sa-east-1|x1e.4xlarge": 6.502000, + "sa-east-1|x1e.8xlarge": 13.005000, + "sa-east-1|x1e.xlarge": 1.626000, + "sa-east-1|x2idn.16xlarge": 13.005000, + "sa-east-1|x2idn.24xlarge": 19.507500, + "sa-east-1|x2idn.32xlarge": 26.010000, + "sa-east-1|x2idn.metal": 26.010000, + "sa-east-1|x2iedn.16xlarge": 26.010000, + "sa-east-1|x2iedn.24xlarge": 39.015000, + "sa-east-1|x2iedn.2xlarge": 3.251250, + "sa-east-1|x2iedn.32xlarge": 52.020000, + "sa-east-1|x2iedn.4xlarge": 6.502500, + "sa-east-1|x2iedn.8xlarge": 13.005000, + "sa-east-1|x2iedn.metal": 52.020000, + "sa-east-1|x2iedn.xlarge": 1.625630, + "us-east-1|a1.2xlarge": 0.204000, + "us-east-1|a1.4xlarge": 0.408000, + "us-east-1|a1.large": 0.051000, + "us-east-1|a1.medium": 0.025500, + "us-east-1|a1.metal": 0.408000, + "us-east-1|a1.xlarge": 0.102000, + "us-east-1|c1.medium": 0.130000, + "us-east-1|c1.xlarge": 0.520000, + "us-east-1|c3.2xlarge": 0.420000, + "us-east-1|c3.4xlarge": 0.840000, + "us-east-1|c3.8xlarge": 1.680000, + "us-east-1|c3.large": 0.105000, + "us-east-1|c3.xlarge": 0.210000, + "us-east-1|c4.2xlarge": 0.398000, + "us-east-1|c4.4xlarge": 0.796000, + "us-east-1|c4.8xlarge": 1.591000, + "us-east-1|c4.large": 0.100000, + "us-east-1|c4.xlarge": 0.199000, + "us-east-1|c5.12xlarge": 2.040000, + "us-east-1|c5.18xlarge": 3.060000, + "us-east-1|c5.24xlarge": 4.080000, + "us-east-1|c5.2xlarge": 0.340000, + "us-east-1|c5.4xlarge": 0.680000, + "us-east-1|c5.9xlarge": 1.530000, + "us-east-1|c5.large": 0.085000, + "us-east-1|c5.metal": 4.080000, + "us-east-1|c5.xlarge": 0.170000, + "us-east-1|c5a.12xlarge": 1.848000, + "us-east-1|c5a.16xlarge": 2.464000, + "us-east-1|c5a.24xlarge": 3.696000, + "us-east-1|c5a.2xlarge": 0.308000, + "us-east-1|c5a.4xlarge": 0.616000, + "us-east-1|c5a.8xlarge": 1.232000, + "us-east-1|c5a.large": 0.077000, + "us-east-1|c5a.xlarge": 0.154000, + "us-east-1|c5ad.12xlarge": 2.064000, + "us-east-1|c5ad.16xlarge": 2.752000, + "us-east-1|c5ad.24xlarge": 4.128000, + "us-east-1|c5ad.2xlarge": 0.344000, + "us-east-1|c5ad.4xlarge": 0.688000, + "us-east-1|c5ad.8xlarge": 1.376000, + "us-east-1|c5ad.large": 0.086000, + "us-east-1|c5ad.xlarge": 0.172000, + "us-east-1|c5d.12xlarge": 2.304000, + "us-east-1|c5d.18xlarge": 3.456000, + "us-east-1|c5d.24xlarge": 4.608000, + "us-east-1|c5d.2xlarge": 0.384000, + "us-east-1|c5d.4xlarge": 0.768000, + "us-east-1|c5d.9xlarge": 1.728000, + "us-east-1|c5d.large": 0.096000, + "us-east-1|c5d.metal": 4.608000, + "us-east-1|c5d.xlarge": 0.192000, + "us-east-1|c5n.18xlarge": 3.888000, + "us-east-1|c5n.2xlarge": 0.432000, + "us-east-1|c5n.4xlarge": 0.864000, + "us-east-1|c5n.9xlarge": 1.944000, + "us-east-1|c5n.large": 0.108000, + "us-east-1|c5n.metal": 3.888000, + "us-east-1|c5n.xlarge": 0.216000, + "us-east-1|c6a.12xlarge": 1.836000, + "us-east-1|c6a.16xlarge": 2.448000, + "us-east-1|c6a.24xlarge": 3.672000, + "us-east-1|c6a.2xlarge": 0.306000, + "us-east-1|c6a.32xlarge": 4.896000, + "us-east-1|c6a.48xlarge": 7.344000, + "us-east-1|c6a.4xlarge": 0.612000, + "us-east-1|c6a.8xlarge": 1.224000, + "us-east-1|c6a.large": 0.076500, + "us-east-1|c6a.metal": 7.344000, + "us-east-1|c6a.xlarge": 0.153000, + "us-east-1|c6g.12xlarge": 1.632000, + "us-east-1|c6g.16xlarge": 2.176000, + "us-east-1|c6g.2xlarge": 0.272000, + "us-east-1|c6g.4xlarge": 0.544000, + "us-east-1|c6g.8xlarge": 1.088000, + "us-east-1|c6g.large": 0.068000, + "us-east-1|c6g.medium": 0.034000, + "us-east-1|c6g.metal": 2.176000, + "us-east-1|c6g.xlarge": 0.136000, + "us-east-1|c6gd.12xlarge": 1.843200, + "us-east-1|c6gd.16xlarge": 2.457600, + "us-east-1|c6gd.2xlarge": 0.307200, + "us-east-1|c6gd.4xlarge": 0.614400, + "us-east-1|c6gd.8xlarge": 1.228800, + "us-east-1|c6gd.large": 0.076800, + "us-east-1|c6gd.medium": 0.038400, + "us-east-1|c6gd.metal": 2.457600, + "us-east-1|c6gd.xlarge": 0.153600, + "us-east-1|c6gn.12xlarge": 2.073600, + "us-east-1|c6gn.16xlarge": 2.764800, + "us-east-1|c6gn.2xlarge": 0.345600, + "us-east-1|c6gn.4xlarge": 0.691200, + "us-east-1|c6gn.8xlarge": 1.382400, + "us-east-1|c6gn.large": 0.086400, + "us-east-1|c6gn.medium": 0.043200, + "us-east-1|c6gn.xlarge": 0.172800, + "us-east-1|c6i.12xlarge": 2.040000, + "us-east-1|c6i.16xlarge": 2.720000, + "us-east-1|c6i.24xlarge": 4.080000, + "us-east-1|c6i.2xlarge": 0.340000, + "us-east-1|c6i.32xlarge": 5.440000, + "us-east-1|c6i.4xlarge": 0.680000, + "us-east-1|c6i.8xlarge": 1.360000, + "us-east-1|c6i.large": 0.085000, + "us-east-1|c6i.metal": 5.440000, + "us-east-1|c6i.xlarge": 0.170000, + "us-east-1|c6id.12xlarge": 2.419200, + "us-east-1|c6id.16xlarge": 3.225600, + "us-east-1|c6id.24xlarge": 4.838400, + "us-east-1|c6id.2xlarge": 0.403200, + "us-east-1|c6id.32xlarge": 6.451200, + "us-east-1|c6id.4xlarge": 0.806400, + "us-east-1|c6id.8xlarge": 1.612800, + "us-east-1|c6id.large": 0.100800, + "us-east-1|c6id.metal": 6.451200, + "us-east-1|c6id.xlarge": 0.201600, + "us-east-1|c6in.12xlarge": 2.721600, + "us-east-1|c6in.16xlarge": 3.628800, + "us-east-1|c6in.24xlarge": 5.443200, + "us-east-1|c6in.2xlarge": 0.453600, + "us-east-1|c6in.32xlarge": 7.257600, + "us-east-1|c6in.4xlarge": 0.907200, + "us-east-1|c6in.8xlarge": 1.814400, + "us-east-1|c6in.large": 0.113400, + "us-east-1|c6in.metal": 7.257600, + "us-east-1|c6in.xlarge": 0.226800, + "us-east-1|c7a.12xlarge": 2.463360, + "us-east-1|c7a.16xlarge": 3.284480, + "us-east-1|c7a.24xlarge": 4.926720, + "us-east-1|c7a.2xlarge": 0.410560, + "us-east-1|c7a.32xlarge": 6.568960, + "us-east-1|c7a.48xlarge": 9.853440, + "us-east-1|c7a.4xlarge": 0.821120, + "us-east-1|c7a.8xlarge": 1.642240, + "us-east-1|c7a.large": 0.102640, + "us-east-1|c7a.medium": 0.051320, + "us-east-1|c7a.metal-48xl": 9.853440, + "us-east-1|c7a.xlarge": 0.205280, + "us-east-1|c7g.12xlarge": 1.740000, + "us-east-1|c7g.16xlarge": 2.320000, + "us-east-1|c7g.2xlarge": 0.290000, + "us-east-1|c7g.4xlarge": 0.580000, + "us-east-1|c7g.8xlarge": 1.160000, + "us-east-1|c7g.large": 0.072500, + "us-east-1|c7g.medium": 0.036300, + "us-east-1|c7g.metal": 2.320000, + "us-east-1|c7g.xlarge": 0.145000, + "us-east-1|c7gd.12xlarge": 2.177300, + "us-east-1|c7gd.16xlarge": 2.903000, + "us-east-1|c7gd.2xlarge": 0.362900, + "us-east-1|c7gd.4xlarge": 0.725800, + "us-east-1|c7gd.8xlarge": 1.451500, + "us-east-1|c7gd.large": 0.090700, + "us-east-1|c7gd.medium": 0.045400, + "us-east-1|c7gd.metal": 2.903000, + "us-east-1|c7gd.xlarge": 0.181400, + "us-east-1|c7gn.12xlarge": 2.995200, + "us-east-1|c7gn.16xlarge": 3.993600, + "us-east-1|c7gn.2xlarge": 0.499200, + "us-east-1|c7gn.4xlarge": 0.998400, + "us-east-1|c7gn.8xlarge": 1.996800, + "us-east-1|c7gn.large": 0.124800, + "us-east-1|c7gn.medium": 0.062400, + "us-east-1|c7gn.metal": 3.993600, + "us-east-1|c7gn.xlarge": 0.249600, + "us-east-1|c7i-flex.12xlarge": 2.034900, + "us-east-1|c7i-flex.16xlarge": 2.713200, + "us-east-1|c7i-flex.2xlarge": 0.339150, + "us-east-1|c7i-flex.4xlarge": 0.678300, + "us-east-1|c7i-flex.8xlarge": 1.356600, + "us-east-1|c7i-flex.large": 0.084790, + "us-east-1|c7i-flex.xlarge": 0.169580, + "us-east-1|c7i.12xlarge": 2.142000, + "us-east-1|c7i.16xlarge": 2.856000, + "us-east-1|c7i.24xlarge": 4.284000, + "us-east-1|c7i.2xlarge": 0.357000, + "us-east-1|c7i.48xlarge": 8.568000, + "us-east-1|c7i.4xlarge": 0.714000, + "us-east-1|c7i.8xlarge": 1.428000, + "us-east-1|c7i.large": 0.089250, + "us-east-1|c7i.metal-24xl": 4.284000, + "us-east-1|c7i.metal-48xl": 8.568000, + "us-east-1|c7i.xlarge": 0.178500, + "us-east-1|c8a.12xlarge": 2.586480, + "us-east-1|c8a.16xlarge": 3.448640, + "us-east-1|c8a.24xlarge": 5.172960, + "us-east-1|c8a.2xlarge": 0.431080, + "us-east-1|c8a.48xlarge": 10.345920, + "us-east-1|c8a.4xlarge": 0.862160, + "us-east-1|c8a.8xlarge": 1.724320, + "us-east-1|c8a.large": 0.107770, + "us-east-1|c8a.medium": 0.053890, + "us-east-1|c8a.metal-24xl": 5.172960, + "us-east-1|c8a.metal-48xl": 10.345920, + "us-east-1|c8a.xlarge": 0.215540, + "us-east-1|c8g.12xlarge": 1.914240, + "us-east-1|c8g.16xlarge": 2.552320, + "us-east-1|c8g.24xlarge": 3.828480, + "us-east-1|c8g.2xlarge": 0.319040, + "us-east-1|c8g.48xlarge": 7.656960, + "us-east-1|c8g.4xlarge": 0.638080, + "us-east-1|c8g.8xlarge": 1.276160, + "us-east-1|c8g.large": 0.079760, + "us-east-1|c8g.medium": 0.039880, + "us-east-1|c8g.metal-24xl": 3.828480, + "us-east-1|c8g.metal-48xl": 7.656960, + "us-east-1|c8g.xlarge": 0.159520, + "us-east-1|c8gb.12xlarge": 2.844000, + "us-east-1|c8gb.16xlarge": 3.792000, + "us-east-1|c8gb.24xlarge": 5.688000, + "us-east-1|c8gb.2xlarge": 0.474000, + "us-east-1|c8gb.4xlarge": 0.948000, + "us-east-1|c8gb.8xlarge": 1.896000, + "us-east-1|c8gb.large": 0.118500, + "us-east-1|c8gb.medium": 0.059250, + "us-east-1|c8gb.metal-24xl": 5.688000, + "us-east-1|c8gb.xlarge": 0.237000, + "us-east-1|c8gd.12xlarge": 2.351520, + "us-east-1|c8gd.16xlarge": 3.135360, + "us-east-1|c8gd.24xlarge": 4.703040, + "us-east-1|c8gd.2xlarge": 0.391920, + "us-east-1|c8gd.48xlarge": 9.406080, + "us-east-1|c8gd.4xlarge": 0.783840, + "us-east-1|c8gd.8xlarge": 1.567680, + "us-east-1|c8gd.large": 0.097980, + "us-east-1|c8gd.medium": 0.048990, + "us-east-1|c8gd.metal-24xl": 4.703040, + "us-east-1|c8gd.metal-48xl": 9.406080, + "us-east-1|c8gd.xlarge": 0.195960, + "us-east-1|c8gn.12xlarge": 2.844000, + "us-east-1|c8gn.16xlarge": 3.792000, + "us-east-1|c8gn.24xlarge": 5.688000, + "us-east-1|c8gn.2xlarge": 0.474000, + "us-east-1|c8gn.48xlarge": 11.376000, + "us-east-1|c8gn.4xlarge": 0.948000, + "us-east-1|c8gn.8xlarge": 1.896000, + "us-east-1|c8gn.large": 0.118500, + "us-east-1|c8gn.medium": 0.059300, + "us-east-1|c8gn.metal-24xl": 5.688000, + "us-east-1|c8gn.metal-48xl": 11.376000, + "us-east-1|c8gn.xlarge": 0.237000, + "us-east-1|c8i-flex.12xlarge": 2.136480, + "us-east-1|c8i-flex.16xlarge": 2.848640, + "us-east-1|c8i-flex.2xlarge": 0.356080, + "us-east-1|c8i-flex.4xlarge": 0.712160, + "us-east-1|c8i-flex.8xlarge": 1.424320, + "us-east-1|c8i-flex.large": 0.089020, + "us-east-1|c8i-flex.xlarge": 0.178040, + "us-east-1|c8i.12xlarge": 2.249040, + "us-east-1|c8i.16xlarge": 2.998720, + "us-east-1|c8i.24xlarge": 4.498080, + "us-east-1|c8i.2xlarge": 0.374840, + "us-east-1|c8i.32xlarge": 5.997440, + "us-east-1|c8i.48xlarge": 8.996160, + "us-east-1|c8i.4xlarge": 0.749680, + "us-east-1|c8i.8xlarge": 1.499360, + "us-east-1|c8i.96xlarge": 17.992320, + "us-east-1|c8i.large": 0.093710, + "us-east-1|c8i.metal-48xl": 8.996160, + "us-east-1|c8i.metal-96xl": 17.992320, + "us-east-1|c8i.xlarge": 0.187420, + "us-east-1|cr1.8xlarge": 3.500000, + "us-east-1|d2.2xlarge": 1.380000, + "us-east-1|d2.4xlarge": 2.760000, + "us-east-1|d2.8xlarge": 5.520000, + "us-east-1|d2.xlarge": 0.690000, + "us-east-1|d3.2xlarge": 0.999000, + "us-east-1|d3.4xlarge": 1.998000, + "us-east-1|d3.8xlarge": 3.995520, + "us-east-1|d3.xlarge": 0.499000, + "us-east-1|d3en.12xlarge": 6.308640, + "us-east-1|d3en.2xlarge": 1.051000, + "us-east-1|d3en.4xlarge": 2.103000, + "us-east-1|d3en.6xlarge": 3.154000, + "us-east-1|d3en.8xlarge": 4.205760, + "us-east-1|d3en.xlarge": 0.526000, + "us-east-1|dl1.24xlarge": 13.109040, + "us-east-1|f1.16xlarge": 13.200000, + "us-east-1|f1.2xlarge": 1.650000, + "us-east-1|f1.4xlarge": 3.300000, + "us-east-1|f2.12xlarge": 3.960000, + "us-east-1|f2.48xlarge": 15.840000, + "us-east-1|f2.6xlarge": 1.980000, + "us-east-1|g2.2xlarge": 0.650000, + "us-east-1|g2.8xlarge": 2.600000, + "us-east-1|g3.16xlarge": 4.560000, + "us-east-1|g3.4xlarge": 1.140000, + "us-east-1|g3.8xlarge": 2.280000, + "us-east-1|g3s.xlarge": 0.750000, + "us-east-1|g4ad.16xlarge": 3.468000, + "us-east-1|g4ad.2xlarge": 0.541170, + "us-east-1|g4ad.4xlarge": 0.867000, + "us-east-1|g4ad.8xlarge": 1.734000, + "us-east-1|g4ad.xlarge": 0.378530, + "us-east-1|g4dn.12xlarge": 3.912000, + "us-east-1|g4dn.16xlarge": 4.352000, + "us-east-1|g4dn.2xlarge": 0.752000, + "us-east-1|g4dn.4xlarge": 1.204000, + "us-east-1|g4dn.8xlarge": 2.176000, + "us-east-1|g4dn.metal": 7.824000, + "us-east-1|g4dn.xlarge": 0.526000, + "us-east-1|g5.12xlarge": 5.672000, + "us-east-1|g5.16xlarge": 4.096000, + "us-east-1|g5.24xlarge": 8.144000, + "us-east-1|g5.2xlarge": 1.212000, + "us-east-1|g5.48xlarge": 16.288000, + "us-east-1|g5.4xlarge": 1.624000, + "us-east-1|g5.8xlarge": 2.448000, + "us-east-1|g5.xlarge": 1.006000, + "us-east-1|g5g.16xlarge": 2.744000, + "us-east-1|g5g.2xlarge": 0.556000, + "us-east-1|g5g.4xlarge": 0.828000, + "us-east-1|g5g.8xlarge": 1.372000, + "us-east-1|g5g.metal": 2.744000, + "us-east-1|g5g.xlarge": 0.420000, + "us-east-1|g6.12xlarge": 4.601600, + "us-east-1|g6.16xlarge": 3.396800, + "us-east-1|g6.24xlarge": 6.675200, + "us-east-1|g6.2xlarge": 0.977600, + "us-east-1|g6.48xlarge": 13.350400, + "us-east-1|g6.4xlarge": 1.323200, + "us-east-1|g6.8xlarge": 2.014400, + "us-east-1|g6.xlarge": 0.804800, + "us-east-1|g6e.12xlarge": 10.492640, + "us-east-1|g6e.16xlarge": 7.577190, + "us-east-1|g6e.24xlarge": 15.065590, + "us-east-1|g6e.2xlarge": 2.242080, + "us-east-1|g6e.48xlarge": 30.131180, + "us-east-1|g6e.4xlarge": 3.004240, + "us-east-1|g6e.8xlarge": 4.528560, + "us-east-1|g6e.xlarge": 1.861000, + "us-east-1|g6f.2xlarge": 0.475000, + "us-east-1|g6f.4xlarge": 0.950000, + "us-east-1|g6f.large": 0.202000, + "us-east-1|g6f.xlarge": 0.237500, + "us-east-1|gr6.4xlarge": 1.539200, + "us-east-1|gr6.8xlarge": 2.446400, + "us-east-1|gr6f.4xlarge": 1.066000, + "us-east-1|h1.16xlarge": 3.744000, + "us-east-1|h1.2xlarge": 0.468000, + "us-east-1|h1.4xlarge": 0.936000, + "us-east-1|h1.8xlarge": 1.872000, + "us-east-1|hpc7g.16xlarge": 1.683200, + "us-east-1|hpc7g.4xlarge": 1.683200, + "us-east-1|hpc7g.8xlarge": 1.683200, + "us-east-1|i2.2xlarge": 1.705000, + "us-east-1|i2.4xlarge": 3.410000, + "us-east-1|i2.8xlarge": 6.820000, + "us-east-1|i2.xlarge": 0.853000, + "us-east-1|i3.16xlarge": 4.992000, + "us-east-1|i3.2xlarge": 0.624000, + "us-east-1|i3.4xlarge": 1.248000, + "us-east-1|i3.8xlarge": 2.496000, + "us-east-1|i3.large": 0.156000, + "us-east-1|i3.metal": 4.992000, + "us-east-1|i3.xlarge": 0.312000, + "us-east-1|i3en.12xlarge": 5.424000, + "us-east-1|i3en.24xlarge": 10.848000, + "us-east-1|i3en.2xlarge": 0.904000, + "us-east-1|i3en.3xlarge": 1.356000, + "us-east-1|i3en.6xlarge": 2.712000, + "us-east-1|i3en.large": 0.226000, + "us-east-1|i3en.metal": 10.848000, + "us-east-1|i3en.xlarge": 0.452000, + "us-east-1|i4g.16xlarge": 4.942080, + "us-east-1|i4g.2xlarge": 0.617760, + "us-east-1|i4g.4xlarge": 1.235520, + "us-east-1|i4g.8xlarge": 2.471040, + "us-east-1|i4g.large": 0.154440, + "us-east-1|i4g.xlarge": 0.308880, + "us-east-1|i4i.12xlarge": 4.118000, + "us-east-1|i4i.16xlarge": 5.491000, + "us-east-1|i4i.24xlarge": 8.236800, + "us-east-1|i4i.2xlarge": 0.686000, + "us-east-1|i4i.32xlarge": 10.982400, + "us-east-1|i4i.4xlarge": 1.373000, + "us-east-1|i4i.8xlarge": 2.746000, + "us-east-1|i4i.large": 0.172000, + "us-east-1|i4i.metal": 10.982000, + "us-east-1|i4i.xlarge": 0.343000, + "us-east-1|i7i.12xlarge": 4.530200, + "us-east-1|i7i.16xlarge": 6.040300, + "us-east-1|i7i.24xlarge": 9.060500, + "us-east-1|i7i.2xlarge": 0.755000, + "us-east-1|i7i.48xlarge": 18.121000, + "us-east-1|i7i.4xlarge": 1.510100, + "us-east-1|i7i.8xlarge": 3.020200, + "us-east-1|i7i.large": 0.188800, + "us-east-1|i7i.metal-24xl": 9.060500, + "us-east-1|i7i.metal-48xl": 18.121000, + "us-east-1|i7i.xlarge": 0.377500, + "us-east-1|i7ie.12xlarge": 6.237600, + "us-east-1|i7ie.18xlarge": 9.356400, + "us-east-1|i7ie.24xlarge": 12.475200, + "us-east-1|i7ie.2xlarge": 1.039600, + "us-east-1|i7ie.3xlarge": 1.559400, + "us-east-1|i7ie.48xlarge": 24.950400, + "us-east-1|i7ie.6xlarge": 3.118800, + "us-east-1|i7ie.large": 0.259900, + "us-east-1|i7ie.metal-24xl": 12.475200, + "us-east-1|i7ie.metal-48xl": 24.950400, + "us-east-1|i7ie.xlarge": 0.519800, + "us-east-1|i8g.12xlarge": 4.118400, + "us-east-1|i8g.16xlarge": 5.491200, + "us-east-1|i8g.24xlarge": 8.236800, + "us-east-1|i8g.2xlarge": 0.686400, + "us-east-1|i8g.48xlarge": 16.473600, + "us-east-1|i8g.4xlarge": 1.372800, + "us-east-1|i8g.8xlarge": 2.745600, + "us-east-1|i8g.large": 0.171600, + "us-east-1|i8g.metal-24xl": 8.236800, + "us-east-1|i8g.xlarge": 0.343200, + "us-east-1|i8ge.12xlarge": 5.695200, + "us-east-1|i8ge.18xlarge": 8.542800, + "us-east-1|i8ge.24xlarge": 11.390400, + "us-east-1|i8ge.2xlarge": 0.949200, + "us-east-1|i8ge.3xlarge": 1.423800, + "us-east-1|i8ge.48xlarge": 22.780800, + "us-east-1|i8ge.6xlarge": 2.847600, + "us-east-1|i8ge.large": 0.237300, + "us-east-1|i8ge.metal-24xl": 11.390400, + "us-east-1|i8ge.metal-48xl": 22.780800, + "us-east-1|i8ge.xlarge": 0.474600, + "us-east-1|im4gn.16xlarge": 5.820670, + "us-east-1|im4gn.2xlarge": 0.727580, + "us-east-1|im4gn.4xlarge": 1.455170, + "us-east-1|im4gn.8xlarge": 2.910340, + "us-east-1|im4gn.large": 0.181900, + "us-east-1|im4gn.xlarge": 0.363790, + "us-east-1|inf1.24xlarge": 4.721000, + "us-east-1|inf1.2xlarge": 0.362000, + "us-east-1|inf1.6xlarge": 1.180000, + "us-east-1|inf1.xlarge": 0.228000, + "us-east-1|inf2.24xlarge": 6.490630, + "us-east-1|inf2.48xlarge": 12.981270, + "us-east-1|inf2.8xlarge": 1.967860, + "us-east-1|inf2.xlarge": 0.758200, + "us-east-1|is4gen.2xlarge": 1.152600, + "us-east-1|is4gen.4xlarge": 2.305200, + "us-east-1|is4gen.8xlarge": 4.610400, + "us-east-1|is4gen.large": 0.288150, + "us-east-1|is4gen.medium": 0.144080, + "us-east-1|is4gen.xlarge": 0.576300, + "us-east-1|m1.large": 0.175000, + "us-east-1|m1.medium": 0.087000, + "us-east-1|m1.small": 0.044000, + "us-east-1|m1.xlarge": 0.350000, + "us-east-1|m2.2xlarge": 0.490000, + "us-east-1|m2.4xlarge": 0.980000, + "us-east-1|m2.xlarge": 0.245000, + "us-east-1|m3.2xlarge": 0.532000, + "us-east-1|m3.large": 0.133000, + "us-east-1|m3.medium": 0.067000, + "us-east-1|m3.xlarge": 0.266000, + "us-east-1|m4.10xlarge": 2.000000, + "us-east-1|m4.16xlarge": 3.200000, + "us-east-1|m4.2xlarge": 0.400000, + "us-east-1|m4.4xlarge": 0.800000, + "us-east-1|m4.large": 0.100000, + "us-east-1|m4.xlarge": 0.200000, + "us-east-1|m5.12xlarge": 2.304000, + "us-east-1|m5.16xlarge": 3.072000, + "us-east-1|m5.24xlarge": 4.608000, + "us-east-1|m5.2xlarge": 0.384000, + "us-east-1|m5.4xlarge": 0.768000, + "us-east-1|m5.8xlarge": 1.536000, + "us-east-1|m5.large": 0.096000, + "us-east-1|m5.metal": 4.608000, + "us-east-1|m5.xlarge": 0.192000, + "us-east-1|m5a.12xlarge": 2.064000, + "us-east-1|m5a.16xlarge": 2.752000, + "us-east-1|m5a.24xlarge": 4.128000, + "us-east-1|m5a.2xlarge": 0.344000, + "us-east-1|m5a.4xlarge": 0.688000, + "us-east-1|m5a.8xlarge": 1.376000, + "us-east-1|m5a.large": 0.086000, + "us-east-1|m5a.xlarge": 0.172000, + "us-east-1|m5ad.12xlarge": 2.472000, + "us-east-1|m5ad.16xlarge": 3.296000, + "us-east-1|m5ad.24xlarge": 4.944000, + "us-east-1|m5ad.2xlarge": 0.412000, + "us-east-1|m5ad.4xlarge": 0.824000, + "us-east-1|m5ad.8xlarge": 1.648000, + "us-east-1|m5ad.large": 0.103000, + "us-east-1|m5ad.xlarge": 0.206000, + "us-east-1|m5d.12xlarge": 2.712000, + "us-east-1|m5d.16xlarge": 3.616000, + "us-east-1|m5d.24xlarge": 5.424000, + "us-east-1|m5d.2xlarge": 0.452000, + "us-east-1|m5d.4xlarge": 0.904000, + "us-east-1|m5d.8xlarge": 1.808000, + "us-east-1|m5d.large": 0.113000, + "us-east-1|m5d.metal": 5.424000, + "us-east-1|m5d.xlarge": 0.226000, + "us-east-1|m5dn.12xlarge": 3.264000, + "us-east-1|m5dn.16xlarge": 4.352000, + "us-east-1|m5dn.24xlarge": 6.528000, + "us-east-1|m5dn.2xlarge": 0.544000, + "us-east-1|m5dn.4xlarge": 1.088000, + "us-east-1|m5dn.8xlarge": 2.176000, + "us-east-1|m5dn.large": 0.136000, + "us-east-1|m5dn.metal": 6.528000, + "us-east-1|m5dn.xlarge": 0.272000, + "us-east-1|m5n.12xlarge": 2.856000, + "us-east-1|m5n.16xlarge": 3.808000, + "us-east-1|m5n.24xlarge": 5.712000, + "us-east-1|m5n.2xlarge": 0.476000, + "us-east-1|m5n.4xlarge": 0.952000, + "us-east-1|m5n.8xlarge": 1.904000, + "us-east-1|m5n.large": 0.119000, + "us-east-1|m5n.metal": 5.712000, + "us-east-1|m5n.xlarge": 0.238000, + "us-east-1|m5zn.12xlarge": 3.964100, + "us-east-1|m5zn.2xlarge": 0.660700, + "us-east-1|m5zn.3xlarge": 0.991000, + "us-east-1|m5zn.6xlarge": 1.982000, + "us-east-1|m5zn.large": 0.165200, + "us-east-1|m5zn.metal": 3.964100, + "us-east-1|m5zn.xlarge": 0.330300, + "us-east-1|m6a.12xlarge": 2.073600, + "us-east-1|m6a.16xlarge": 2.764800, + "us-east-1|m6a.24xlarge": 4.147200, + "us-east-1|m6a.2xlarge": 0.345600, + "us-east-1|m6a.32xlarge": 5.529600, + "us-east-1|m6a.48xlarge": 8.294400, + "us-east-1|m6a.4xlarge": 0.691200, + "us-east-1|m6a.8xlarge": 1.382400, + "us-east-1|m6a.large": 0.086400, + "us-east-1|m6a.metal": 8.294400, + "us-east-1|m6a.xlarge": 0.172800, + "us-east-1|m6g.12xlarge": 1.848000, + "us-east-1|m6g.16xlarge": 2.464000, + "us-east-1|m6g.2xlarge": 0.308000, + "us-east-1|m6g.4xlarge": 0.616000, + "us-east-1|m6g.8xlarge": 1.232000, + "us-east-1|m6g.large": 0.077000, + "us-east-1|m6g.medium": 0.038500, + "us-east-1|m6g.metal": 2.464000, + "us-east-1|m6g.xlarge": 0.154000, + "us-east-1|m6gd.12xlarge": 2.169600, + "us-east-1|m6gd.16xlarge": 2.892800, + "us-east-1|m6gd.2xlarge": 0.361600, + "us-east-1|m6gd.4xlarge": 0.723200, + "us-east-1|m6gd.8xlarge": 1.446400, + "us-east-1|m6gd.large": 0.090400, + "us-east-1|m6gd.medium": 0.045200, + "us-east-1|m6gd.metal": 2.892800, + "us-east-1|m6gd.xlarge": 0.180800, + "us-east-1|m6i.12xlarge": 2.304000, + "us-east-1|m6i.16xlarge": 3.072000, + "us-east-1|m6i.24xlarge": 4.608000, + "us-east-1|m6i.2xlarge": 0.384000, + "us-east-1|m6i.32xlarge": 6.144000, + "us-east-1|m6i.4xlarge": 0.768000, + "us-east-1|m6i.8xlarge": 1.536000, + "us-east-1|m6i.large": 0.096000, + "us-east-1|m6i.metal": 6.144000, + "us-east-1|m6i.xlarge": 0.192000, + "us-east-1|m6id.12xlarge": 2.847600, + "us-east-1|m6id.16xlarge": 3.796800, + "us-east-1|m6id.24xlarge": 5.695200, + "us-east-1|m6id.2xlarge": 0.474600, + "us-east-1|m6id.32xlarge": 7.593600, + "us-east-1|m6id.4xlarge": 0.949200, + "us-east-1|m6id.8xlarge": 1.898400, + "us-east-1|m6id.large": 0.118650, + "us-east-1|m6id.metal": 7.593600, + "us-east-1|m6id.xlarge": 0.237300, + "us-east-1|m6idn.12xlarge": 3.818880, + "us-east-1|m6idn.16xlarge": 5.091840, + "us-east-1|m6idn.24xlarge": 7.637760, + "us-east-1|m6idn.2xlarge": 0.636480, + "us-east-1|m6idn.32xlarge": 10.183680, + "us-east-1|m6idn.4xlarge": 1.272960, + "us-east-1|m6idn.8xlarge": 2.545920, + "us-east-1|m6idn.large": 0.159120, + "us-east-1|m6idn.metal": 10.183680, + "us-east-1|m6idn.xlarge": 0.318240, + "us-east-1|m6in.12xlarge": 3.341520, + "us-east-1|m6in.16xlarge": 4.455360, + "us-east-1|m6in.24xlarge": 6.683040, + "us-east-1|m6in.2xlarge": 0.556920, + "us-east-1|m6in.32xlarge": 8.910720, + "us-east-1|m6in.4xlarge": 1.113840, + "us-east-1|m6in.8xlarge": 2.227680, + "us-east-1|m6in.large": 0.139230, + "us-east-1|m6in.metal": 8.910720, + "us-east-1|m6in.xlarge": 0.278460, + "us-east-1|m7a.12xlarge": 2.782080, + "us-east-1|m7a.16xlarge": 3.709440, + "us-east-1|m7a.24xlarge": 5.564160, + "us-east-1|m7a.2xlarge": 0.463680, + "us-east-1|m7a.32xlarge": 7.418880, + "us-east-1|m7a.48xlarge": 11.128320, + "us-east-1|m7a.4xlarge": 0.927360, + "us-east-1|m7a.8xlarge": 1.854720, + "us-east-1|m7a.large": 0.115920, + "us-east-1|m7a.medium": 0.057960, + "us-east-1|m7a.metal-48xl": 11.128320, + "us-east-1|m7a.xlarge": 0.231840, + "us-east-1|m7g.12xlarge": 1.958400, + "us-east-1|m7g.16xlarge": 2.611200, + "us-east-1|m7g.2xlarge": 0.326400, + "us-east-1|m7g.4xlarge": 0.652800, + "us-east-1|m7g.8xlarge": 1.305600, + "us-east-1|m7g.large": 0.081600, + "us-east-1|m7g.medium": 0.040800, + "us-east-1|m7g.metal": 2.611200, + "us-east-1|m7g.xlarge": 0.163200, + "us-east-1|m7gd.12xlarge": 2.562800, + "us-east-1|m7gd.16xlarge": 3.417100, + "us-east-1|m7gd.2xlarge": 0.427100, + "us-east-1|m7gd.4xlarge": 0.854300, + "us-east-1|m7gd.8xlarge": 1.708600, + "us-east-1|m7gd.large": 0.106800, + "us-east-1|m7gd.medium": 0.053400, + "us-east-1|m7gd.metal": 3.417100, + "us-east-1|m7gd.xlarge": 0.213600, + "us-east-1|m7i-flex.12xlarge": 2.298240, + "us-east-1|m7i-flex.16xlarge": 3.064320, + "us-east-1|m7i-flex.2xlarge": 0.383040, + "us-east-1|m7i-flex.4xlarge": 0.766080, + "us-east-1|m7i-flex.8xlarge": 1.532160, + "us-east-1|m7i-flex.large": 0.095760, + "us-east-1|m7i-flex.xlarge": 0.191520, + "us-east-1|m7i.12xlarge": 2.419200, + "us-east-1|m7i.16xlarge": 3.225600, + "us-east-1|m7i.24xlarge": 4.838400, + "us-east-1|m7i.2xlarge": 0.403200, + "us-east-1|m7i.48xlarge": 9.676800, + "us-east-1|m7i.4xlarge": 0.806400, + "us-east-1|m7i.8xlarge": 1.612800, + "us-east-1|m7i.large": 0.100800, + "us-east-1|m7i.metal-24xl": 4.838400, + "us-east-1|m7i.metal-48xl": 9.676800, + "us-east-1|m7i.xlarge": 0.201600, + "us-east-1|m8a.12xlarge": 2.921280, + "us-east-1|m8a.16xlarge": 3.895040, + "us-east-1|m8a.24xlarge": 5.842560, + "us-east-1|m8a.2xlarge": 0.486880, + "us-east-1|m8a.48xlarge": 11.685120, + "us-east-1|m8a.4xlarge": 0.973760, + "us-east-1|m8a.8xlarge": 1.947520, + "us-east-1|m8a.large": 0.121720, + "us-east-1|m8a.medium": 0.060860, + "us-east-1|m8a.metal-24xl": 5.842560, + "us-east-1|m8a.metal-48xl": 11.685120, + "us-east-1|m8a.xlarge": 0.243440, + "us-east-1|m8g.12xlarge": 2.154240, + "us-east-1|m8g.16xlarge": 2.872320, + "us-east-1|m8g.24xlarge": 4.308480, + "us-east-1|m8g.2xlarge": 0.359040, + "us-east-1|m8g.48xlarge": 8.616960, + "us-east-1|m8g.4xlarge": 0.718080, + "us-east-1|m8g.8xlarge": 1.436160, + "us-east-1|m8g.large": 0.089760, + "us-east-1|m8g.medium": 0.044880, + "us-east-1|m8g.metal-24xl": 4.308480, + "us-east-1|m8g.metal-48xl": 8.616960, + "us-east-1|m8g.xlarge": 0.179520, + "us-east-1|m8gb.12xlarge": 3.492000, + "us-east-1|m8gb.16xlarge": 4.656000, + "us-east-1|m8gb.24xlarge": 6.984000, + "us-east-1|m8gb.2xlarge": 0.582000, + "us-east-1|m8gb.4xlarge": 1.164000, + "us-east-1|m8gb.8xlarge": 2.328000, + "us-east-1|m8gb.large": 0.145500, + "us-east-1|m8gb.medium": 0.072750, + "us-east-1|m8gb.xlarge": 0.291000, + "us-east-1|m8gd.12xlarge": 2.767680, + "us-east-1|m8gd.16xlarge": 3.690240, + "us-east-1|m8gd.24xlarge": 5.535360, + "us-east-1|m8gd.2xlarge": 0.461280, + "us-east-1|m8gd.48xlarge": 11.070720, + "us-east-1|m8gd.4xlarge": 0.922560, + "us-east-1|m8gd.8xlarge": 1.845120, + "us-east-1|m8gd.large": 0.115320, + "us-east-1|m8gd.medium": 0.057660, + "us-east-1|m8gd.metal-24xl": 5.535360, + "us-east-1|m8gd.metal-48xl": 11.070720, + "us-east-1|m8gd.xlarge": 0.230640, + "us-east-1|m8gn.12xlarge": 3.492000, + "us-east-1|m8gn.16xlarge": 4.656000, + "us-east-1|m8gn.24xlarge": 6.984000, + "us-east-1|m8gn.2xlarge": 0.582000, + "us-east-1|m8gn.48xlarge": 13.968000, + "us-east-1|m8gn.4xlarge": 1.164000, + "us-east-1|m8gn.8xlarge": 2.328000, + "us-east-1|m8gn.large": 0.145500, + "us-east-1|m8gn.medium": 0.072800, + "us-east-1|m8gn.xlarge": 0.291000, + "us-east-1|m8i-flex.12xlarge": 2.413200, + "us-east-1|m8i-flex.16xlarge": 3.217600, + "us-east-1|m8i-flex.2xlarge": 0.402200, + "us-east-1|m8i-flex.4xlarge": 0.804400, + "us-east-1|m8i-flex.8xlarge": 1.608800, + "us-east-1|m8i-flex.large": 0.100550, + "us-east-1|m8i-flex.xlarge": 0.201100, + "us-east-1|m8i.12xlarge": 2.540160, + "us-east-1|m8i.16xlarge": 3.386880, + "us-east-1|m8i.24xlarge": 5.080320, + "us-east-1|m8i.2xlarge": 0.423360, + "us-east-1|m8i.32xlarge": 6.773760, + "us-east-1|m8i.48xlarge": 10.160640, + "us-east-1|m8i.4xlarge": 0.846720, + "us-east-1|m8i.8xlarge": 1.693440, + "us-east-1|m8i.96xlarge": 20.321280, + "us-east-1|m8i.large": 0.105840, + "us-east-1|m8i.metal-48xl": 10.160640, + "us-east-1|m8i.metal-96xl": 20.321280, + "us-east-1|m8i.xlarge": 0.211680, + "us-east-1|p2.16xlarge": 14.400000, + "us-east-1|p2.8xlarge": 7.200000, + "us-east-1|p2.xlarge": 0.900000, + "us-east-1|p3.16xlarge": 24.480000, + "us-east-1|p3.2xlarge": 3.060000, + "us-east-1|p3.8xlarge": 12.240000, + "us-east-1|p3dn.24xlarge": 31.212000, + "us-east-1|p4d.24xlarge": 21.957642, + "us-east-1|p4de.24xlarge": 27.447050, + "us-east-1|p5.48xlarge": 55.040000, + "us-east-1|p5.4xlarge": 6.880000, + "us-east-1|p5en.48xlarge": 63.296000, + "us-east-1|p6-b200.48xlarge": 113.932800, + "us-east-1|r3.2xlarge": 0.665000, + "us-east-1|r3.4xlarge": 1.330000, + "us-east-1|r3.8xlarge": 2.660000, + "us-east-1|r3.large": 0.166000, + "us-east-1|r3.xlarge": 0.333000, + "us-east-1|r4.16xlarge": 4.256000, + "us-east-1|r4.2xlarge": 0.532000, + "us-east-1|r4.4xlarge": 1.064000, + "us-east-1|r4.8xlarge": 2.128000, + "us-east-1|r4.large": 0.133000, + "us-east-1|r4.xlarge": 0.266000, + "us-east-1|r5.12xlarge": 3.024000, + "us-east-1|r5.16xlarge": 4.032000, + "us-east-1|r5.24xlarge": 6.048000, + "us-east-1|r5.2xlarge": 0.504000, + "us-east-1|r5.4xlarge": 1.008000, + "us-east-1|r5.8xlarge": 2.016000, + "us-east-1|r5.large": 0.126000, + "us-east-1|r5.metal": 6.048000, + "us-east-1|r5.xlarge": 0.252000, + "us-east-1|r5a.12xlarge": 2.712000, + "us-east-1|r5a.16xlarge": 3.616000, + "us-east-1|r5a.24xlarge": 5.424000, + "us-east-1|r5a.2xlarge": 0.452000, + "us-east-1|r5a.4xlarge": 0.904000, + "us-east-1|r5a.8xlarge": 1.808000, + "us-east-1|r5a.large": 0.113000, + "us-east-1|r5a.xlarge": 0.226000, + "us-east-1|r5ad.12xlarge": 3.144000, + "us-east-1|r5ad.16xlarge": 4.192000, + "us-east-1|r5ad.24xlarge": 6.288000, + "us-east-1|r5ad.2xlarge": 0.524000, + "us-east-1|r5ad.4xlarge": 1.048000, + "us-east-1|r5ad.8xlarge": 2.096000, + "us-east-1|r5ad.large": 0.131000, + "us-east-1|r5ad.xlarge": 0.262000, + "us-east-1|r5b.12xlarge": 3.576000, + "us-east-1|r5b.16xlarge": 4.768000, + "us-east-1|r5b.24xlarge": 7.152000, + "us-east-1|r5b.2xlarge": 0.596000, + "us-east-1|r5b.4xlarge": 1.192000, + "us-east-1|r5b.8xlarge": 2.384000, + "us-east-1|r5b.large": 0.149000, + "us-east-1|r5b.metal": 7.152000, + "us-east-1|r5b.xlarge": 0.298000, + "us-east-1|r5d.12xlarge": 3.456000, + "us-east-1|r5d.16xlarge": 4.608000, + "us-east-1|r5d.24xlarge": 6.912000, + "us-east-1|r5d.2xlarge": 0.576000, + "us-east-1|r5d.4xlarge": 1.152000, + "us-east-1|r5d.8xlarge": 2.304000, + "us-east-1|r5d.large": 0.144000, + "us-east-1|r5d.metal": 6.912000, + "us-east-1|r5d.xlarge": 0.288000, + "us-east-1|r5dn.12xlarge": 4.008000, + "us-east-1|r5dn.16xlarge": 5.344000, + "us-east-1|r5dn.24xlarge": 8.016000, + "us-east-1|r5dn.2xlarge": 0.668000, + "us-east-1|r5dn.4xlarge": 1.336000, + "us-east-1|r5dn.8xlarge": 2.672000, + "us-east-1|r5dn.large": 0.167000, + "us-east-1|r5dn.metal": 8.016000, + "us-east-1|r5dn.xlarge": 0.334000, + "us-east-1|r5n.12xlarge": 3.576000, + "us-east-1|r5n.16xlarge": 4.768000, + "us-east-1|r5n.24xlarge": 7.152000, + "us-east-1|r5n.2xlarge": 0.596000, + "us-east-1|r5n.4xlarge": 1.192000, + "us-east-1|r5n.8xlarge": 2.384000, + "us-east-1|r5n.large": 0.149000, + "us-east-1|r5n.metal": 7.152000, + "us-east-1|r5n.xlarge": 0.298000, + "us-east-1|r6a.12xlarge": 2.721600, + "us-east-1|r6a.16xlarge": 3.628800, + "us-east-1|r6a.24xlarge": 5.443200, + "us-east-1|r6a.2xlarge": 0.453600, + "us-east-1|r6a.32xlarge": 7.257600, + "us-east-1|r6a.48xlarge": 10.886400, + "us-east-1|r6a.4xlarge": 0.907200, + "us-east-1|r6a.8xlarge": 1.814400, + "us-east-1|r6a.large": 0.113400, + "us-east-1|r6a.metal": 10.886400, + "us-east-1|r6a.xlarge": 0.226800, + "us-east-1|r6g.12xlarge": 2.419200, + "us-east-1|r6g.16xlarge": 3.225600, + "us-east-1|r6g.2xlarge": 0.403200, + "us-east-1|r6g.4xlarge": 0.806400, + "us-east-1|r6g.8xlarge": 1.612800, + "us-east-1|r6g.large": 0.100800, + "us-east-1|r6g.medium": 0.050400, + "us-east-1|r6g.metal": 3.225600, + "us-east-1|r6g.xlarge": 0.201600, + "us-east-1|r6gd.12xlarge": 2.764800, + "us-east-1|r6gd.16xlarge": 3.686400, + "us-east-1|r6gd.2xlarge": 0.460800, + "us-east-1|r6gd.4xlarge": 0.921600, + "us-east-1|r6gd.8xlarge": 1.843200, + "us-east-1|r6gd.large": 0.115200, + "us-east-1|r6gd.medium": 0.057600, + "us-east-1|r6gd.metal": 3.686400, + "us-east-1|r6gd.xlarge": 0.230400, + "us-east-1|r6i.12xlarge": 3.024000, + "us-east-1|r6i.16xlarge": 4.032000, + "us-east-1|r6i.24xlarge": 6.048000, + "us-east-1|r6i.2xlarge": 0.504000, + "us-east-1|r6i.32xlarge": 8.064000, + "us-east-1|r6i.4xlarge": 1.008000, + "us-east-1|r6i.8xlarge": 2.016000, + "us-east-1|r6i.large": 0.126000, + "us-east-1|r6i.metal": 8.064000, + "us-east-1|r6i.xlarge": 0.252000, + "us-east-1|r6id.12xlarge": 3.628800, + "us-east-1|r6id.16xlarge": 4.838400, + "us-east-1|r6id.24xlarge": 7.257600, + "us-east-1|r6id.2xlarge": 0.604800, + "us-east-1|r6id.32xlarge": 9.676800, + "us-east-1|r6id.4xlarge": 1.209600, + "us-east-1|r6id.8xlarge": 2.419200, + "us-east-1|r6id.large": 0.151200, + "us-east-1|r6id.metal": 9.676800, + "us-east-1|r6id.xlarge": 0.302400, + "us-east-1|r6idn.12xlarge": 4.689360, + "us-east-1|r6idn.16xlarge": 6.252480, + "us-east-1|r6idn.24xlarge": 9.378720, + "us-east-1|r6idn.2xlarge": 0.781560, + "us-east-1|r6idn.32xlarge": 12.504960, + "us-east-1|r6idn.4xlarge": 1.563120, + "us-east-1|r6idn.8xlarge": 3.126240, + "us-east-1|r6idn.large": 0.195390, + "us-east-1|r6idn.metal": 12.504960, + "us-east-1|r6idn.xlarge": 0.390780, + "us-east-1|r6in.12xlarge": 4.183920, + "us-east-1|r6in.16xlarge": 5.578560, + "us-east-1|r6in.24xlarge": 8.367840, + "us-east-1|r6in.2xlarge": 0.697320, + "us-east-1|r6in.32xlarge": 11.157120, + "us-east-1|r6in.4xlarge": 1.394640, + "us-east-1|r6in.8xlarge": 2.789280, + "us-east-1|r6in.large": 0.174330, + "us-east-1|r6in.metal": 11.157120, + "us-east-1|r6in.xlarge": 0.348660, + "us-east-1|r7a.12xlarge": 3.651600, + "us-east-1|r7a.16xlarge": 4.868800, + "us-east-1|r7a.24xlarge": 7.303200, + "us-east-1|r7a.2xlarge": 0.608600, + "us-east-1|r7a.32xlarge": 9.737600, + "us-east-1|r7a.48xlarge": 14.606400, + "us-east-1|r7a.4xlarge": 1.217200, + "us-east-1|r7a.8xlarge": 2.434400, + "us-east-1|r7a.large": 0.152150, + "us-east-1|r7a.medium": 0.076080, + "us-east-1|r7a.metal-48xl": 14.606400, + "us-east-1|r7a.xlarge": 0.304300, + "us-east-1|r7g.12xlarge": 2.570400, + "us-east-1|r7g.16xlarge": 3.427200, + "us-east-1|r7g.2xlarge": 0.428400, + "us-east-1|r7g.4xlarge": 0.856800, + "us-east-1|r7g.8xlarge": 1.713600, + "us-east-1|r7g.large": 0.107100, + "us-east-1|r7g.medium": 0.053600, + "us-east-1|r7g.metal": 3.427200, + "us-east-1|r7g.xlarge": 0.214200, + "us-east-1|r7gd.12xlarge": 3.265900, + "us-east-1|r7gd.16xlarge": 4.354600, + "us-east-1|r7gd.2xlarge": 0.544300, + "us-east-1|r7gd.4xlarge": 1.088600, + "us-east-1|r7gd.8xlarge": 2.177300, + "us-east-1|r7gd.large": 0.136100, + "us-east-1|r7gd.medium": 0.068000, + "us-east-1|r7gd.metal": 4.354600, + "us-east-1|r7gd.xlarge": 0.272200, + "us-east-1|r7i.12xlarge": 3.175200, + "us-east-1|r7i.16xlarge": 4.233600, + "us-east-1|r7i.24xlarge": 6.350400, + "us-east-1|r7i.2xlarge": 0.529200, + "us-east-1|r7i.48xlarge": 12.700800, + "us-east-1|r7i.4xlarge": 1.058400, + "us-east-1|r7i.8xlarge": 2.116800, + "us-east-1|r7i.large": 0.132300, + "us-east-1|r7i.metal-24xl": 6.350400, + "us-east-1|r7i.metal-48xl": 12.700800, + "us-east-1|r7i.xlarge": 0.264600, + "us-east-1|r7iz.12xlarge": 4.464000, + "us-east-1|r7iz.16xlarge": 5.952000, + "us-east-1|r7iz.2xlarge": 0.744000, + "us-east-1|r7iz.32xlarge": 11.904000, + "us-east-1|r7iz.4xlarge": 1.488000, + "us-east-1|r7iz.8xlarge": 2.976000, + "us-east-1|r7iz.large": 0.186000, + "us-east-1|r7iz.metal-16xl": 5.952000, + "us-east-1|r7iz.metal-32xl": 11.904000, + "us-east-1|r7iz.xlarge": 0.372000, + "us-east-1|r8a.12xlarge": 3.834240, + "us-east-1|r8a.16xlarge": 5.112320, + "us-east-1|r8a.24xlarge": 7.668480, + "us-east-1|r8a.2xlarge": 0.639040, + "us-east-1|r8a.48xlarge": 15.336960, + "us-east-1|r8a.4xlarge": 1.278080, + "us-east-1|r8a.8xlarge": 2.556160, + "us-east-1|r8a.large": 0.159760, + "us-east-1|r8a.medium": 0.079880, + "us-east-1|r8a.metal-24xl": 7.668480, + "us-east-1|r8a.metal-48xl": 15.336960, + "us-east-1|r8a.xlarge": 0.319520, + "us-east-1|r8g.12xlarge": 2.827680, + "us-east-1|r8g.16xlarge": 3.770240, + "us-east-1|r8g.24xlarge": 5.655360, + "us-east-1|r8g.2xlarge": 0.471280, + "us-east-1|r8g.48xlarge": 11.310720, + "us-east-1|r8g.4xlarge": 0.942560, + "us-east-1|r8g.8xlarge": 1.885120, + "us-east-1|r8g.large": 0.117820, + "us-east-1|r8g.medium": 0.058910, + "us-east-1|r8g.metal-24xl": 5.655360, + "us-east-1|r8g.metal-48xl": 11.310720, + "us-east-1|r8g.xlarge": 0.235640, + "us-east-1|r8gb.12xlarge": 4.372320, + "us-east-1|r8gb.16xlarge": 5.829760, + "us-east-1|r8gb.24xlarge": 8.744640, + "us-east-1|r8gb.2xlarge": 0.728720, + "us-east-1|r8gb.4xlarge": 1.457440, + "us-east-1|r8gb.8xlarge": 2.914880, + "us-east-1|r8gb.large": 0.182180, + "us-east-1|r8gb.medium": 0.091090, + "us-east-1|r8gb.metal-24xl": 17.489280, + "us-east-1|r8gb.xlarge": 0.364360, + "us-east-1|r8gd.12xlarge": 3.527040, + "us-east-1|r8gd.16xlarge": 4.702720, + "us-east-1|r8gd.24xlarge": 7.054080, + "us-east-1|r8gd.2xlarge": 0.587840, + "us-east-1|r8gd.48xlarge": 14.108160, + "us-east-1|r8gd.4xlarge": 1.175680, + "us-east-1|r8gd.8xlarge": 2.351360, + "us-east-1|r8gd.large": 0.146960, + "us-east-1|r8gd.medium": 0.073480, + "us-east-1|r8gd.metal-24xl": 7.054080, + "us-east-1|r8gd.metal-48xl": 14.108160, + "us-east-1|r8gd.xlarge": 0.293920, + "us-east-1|r8gn.12xlarge": 4.372300, + "us-east-1|r8gn.16xlarge": 5.829800, + "us-east-1|r8gn.24xlarge": 8.744600, + "us-east-1|r8gn.2xlarge": 0.728700, + "us-east-1|r8gn.48xlarge": 17.489300, + "us-east-1|r8gn.4xlarge": 1.457400, + "us-east-1|r8gn.8xlarge": 2.914900, + "us-east-1|r8gn.large": 0.182200, + "us-east-1|r8gn.medium": 0.091100, + "us-east-1|r8gn.metal-24xl": 8.744600, + "us-east-1|r8gn.metal-48xl": 17.489300, + "us-east-1|r8gn.xlarge": 0.364400, + "us-east-1|r8i-flex.12xlarge": 3.167280, + "us-east-1|r8i-flex.16xlarge": 4.223040, + "us-east-1|r8i-flex.2xlarge": 0.527880, + "us-east-1|r8i-flex.4xlarge": 1.055760, + "us-east-1|r8i-flex.8xlarge": 2.111520, + "us-east-1|r8i-flex.large": 0.131970, + "us-east-1|r8i-flex.xlarge": 0.263940, + "us-east-1|r8i.12xlarge": 3.334080, + "us-east-1|r8i.16xlarge": 4.445440, + "us-east-1|r8i.24xlarge": 6.668160, + "us-east-1|r8i.2xlarge": 0.555680, + "us-east-1|r8i.32xlarge": 8.890880, + "us-east-1|r8i.48xlarge": 13.336320, + "us-east-1|r8i.4xlarge": 1.111360, + "us-east-1|r8i.8xlarge": 2.222720, + "us-east-1|r8i.96xlarge": 26.672640, + "us-east-1|r8i.large": 0.138920, + "us-east-1|r8i.metal-48xl": 13.336320, + "us-east-1|r8i.metal-96xl": 26.672640, + "us-east-1|r8i.xlarge": 0.277840, + "us-east-1|t1.micro": 0.020000, + "us-east-1|t2.2xlarge": 0.371200, + "us-east-1|t2.large": 0.092800, + "us-east-1|t2.medium": 0.046400, + "us-east-1|t2.micro": 0.011600, + "us-east-1|t2.nano": 0.005800, + "us-east-1|t2.small": 0.023000, + "us-east-1|t2.xlarge": 0.185600, + "us-east-1|t3.2xlarge": 0.332800, + "us-east-1|t3.large": 0.083200, + "us-east-1|t3.medium": 0.041600, + "us-east-1|t3.micro": 0.010400, + "us-east-1|t3.nano": 0.005200, + "us-east-1|t3.small": 0.020800, + "us-east-1|t3.xlarge": 0.166400, + "us-east-1|t3a.2xlarge": 0.300800, + "us-east-1|t3a.large": 0.075200, + "us-east-1|t3a.medium": 0.037600, + "us-east-1|t3a.micro": 0.009400, + "us-east-1|t3a.nano": 0.004700, + "us-east-1|t3a.small": 0.018800, + "us-east-1|t3a.xlarge": 0.150400, + "us-east-1|t4g.2xlarge": 0.268800, + "us-east-1|t4g.large": 0.067200, + "us-east-1|t4g.medium": 0.033600, + "us-east-1|t4g.micro": 0.008400, + "us-east-1|t4g.nano": 0.004200, + "us-east-1|t4g.small": 0.016800, + "us-east-1|t4g.xlarge": 0.134400, + "us-east-1|trn1.2xlarge": 1.343750, + "us-east-1|trn1.32xlarge": 21.500000, + "us-east-1|trn1n.32xlarge": 24.780000, + "us-east-1|u-12tb1.112xlarge": 109.200000, + "us-east-1|u-18tb1.112xlarge": 163.800000, + "us-east-1|u-24tb1.112xlarge": 218.400000, + "us-east-1|u-3tb1.56xlarge": 27.300000, + "us-east-1|u-6tb1.112xlarge": 54.600000, + "us-east-1|u-6tb1.56xlarge": 46.403910, + "us-east-1|u-9tb1.112xlarge": 81.900000, + "us-east-1|u7i-12tb.224xlarge": 125.581820, + "us-east-1|u7i-6tb.112xlarge": 62.790000, + "us-east-1|u7i-8tb.112xlarge": 83.720000, + "us-east-1|u7in-16tb.224xlarge": 180.475580, + "us-east-1|u7in-24tb.224xlarge": 270.731280, + "us-east-1|u7in-32tb.224xlarge": 360.986950, + "us-east-1|vt1.24xlarge": 5.200000, + "us-east-1|vt1.3xlarge": 0.650000, + "us-east-1|vt1.6xlarge": 1.300000, + "us-east-1|x1.16xlarge": 6.669000, + "us-east-1|x1.32xlarge": 13.338000, + "us-east-1|x1e.16xlarge": 13.344000, + "us-east-1|x1e.2xlarge": 1.668000, + "us-east-1|x1e.32xlarge": 26.688000, + "us-east-1|x1e.4xlarge": 3.336000, + "us-east-1|x1e.8xlarge": 6.672000, + "us-east-1|x1e.xlarge": 0.834000, + "us-east-1|x2gd.12xlarge": 4.008000, + "us-east-1|x2gd.16xlarge": 5.344000, + "us-east-1|x2gd.2xlarge": 0.668000, + "us-east-1|x2gd.4xlarge": 1.336000, + "us-east-1|x2gd.8xlarge": 2.672000, + "us-east-1|x2gd.large": 0.167000, + "us-east-1|x2gd.medium": 0.083500, + "us-east-1|x2gd.metal": 5.344000, + "us-east-1|x2gd.xlarge": 0.334000, + "us-east-1|x2idn.16xlarge": 6.669000, + "us-east-1|x2idn.24xlarge": 10.003500, + "us-east-1|x2idn.32xlarge": 13.338000, + "us-east-1|x2idn.metal": 13.338000, + "us-east-1|x2iedn.16xlarge": 13.338000, + "us-east-1|x2iedn.24xlarge": 20.007000, + "us-east-1|x2iedn.2xlarge": 1.667250, + "us-east-1|x2iedn.32xlarge": 26.676000, + "us-east-1|x2iedn.4xlarge": 3.334500, + "us-east-1|x2iedn.8xlarge": 6.669000, + "us-east-1|x2iedn.metal": 26.676000, + "us-east-1|x2iedn.xlarge": 0.833630, + "us-east-1|x2iezn.12xlarge": 10.008000, + "us-east-1|x2iezn.2xlarge": 1.668000, + "us-east-1|x2iezn.4xlarge": 3.336000, + "us-east-1|x2iezn.6xlarge": 5.004000, + "us-east-1|x2iezn.8xlarge": 6.672000, + "us-east-1|x2iezn.metal": 10.008000, + "us-east-1|x8g.12xlarge": 4.689600, + "us-east-1|x8g.16xlarge": 6.252800, + "us-east-1|x8g.24xlarge": 9.379200, + "us-east-1|x8g.2xlarge": 0.781600, + "us-east-1|x8g.48xlarge": 18.758400, + "us-east-1|x8g.4xlarge": 1.563200, + "us-east-1|x8g.8xlarge": 3.126400, + "us-east-1|x8g.large": 0.195400, + "us-east-1|x8g.medium": 0.097700, + "us-east-1|x8g.metal-24xl": 9.379200, + "us-east-1|x8g.metal-48xl": 18.758400, + "us-east-1|x8g.xlarge": 0.390800, + "us-east-1|z1d.12xlarge": 4.464000, + "us-east-1|z1d.2xlarge": 0.744000, + "us-east-1|z1d.3xlarge": 1.116000, + "us-east-1|z1d.6xlarge": 2.232000, + "us-east-1|z1d.large": 0.186000, + "us-east-1|z1d.metal": 4.464000, + "us-east-1|z1d.xlarge": 0.372000, + "us-east-2|a1.2xlarge": 0.204000, + "us-east-2|a1.4xlarge": 0.408000, + "us-east-2|a1.large": 0.051000, + "us-east-2|a1.medium": 0.025500, + "us-east-2|a1.metal": 0.408000, + "us-east-2|a1.xlarge": 0.102000, + "us-east-2|c4.2xlarge": 0.398000, + "us-east-2|c4.4xlarge": 0.796000, + "us-east-2|c4.8xlarge": 1.591000, + "us-east-2|c4.large": 0.100000, + "us-east-2|c4.xlarge": 0.199000, + "us-east-2|c5.12xlarge": 2.040000, + "us-east-2|c5.18xlarge": 3.060000, + "us-east-2|c5.24xlarge": 4.080000, + "us-east-2|c5.2xlarge": 0.340000, + "us-east-2|c5.4xlarge": 0.680000, + "us-east-2|c5.9xlarge": 1.530000, + "us-east-2|c5.large": 0.085000, + "us-east-2|c5.metal": 4.080000, + "us-east-2|c5.xlarge": 0.170000, + "us-east-2|c5a.12xlarge": 1.848000, + "us-east-2|c5a.16xlarge": 2.464000, + "us-east-2|c5a.24xlarge": 3.696000, + "us-east-2|c5a.2xlarge": 0.308000, + "us-east-2|c5a.4xlarge": 0.616000, + "us-east-2|c5a.8xlarge": 1.232000, + "us-east-2|c5a.large": 0.077000, + "us-east-2|c5a.xlarge": 0.154000, + "us-east-2|c5ad.12xlarge": 2.064000, + "us-east-2|c5ad.16xlarge": 2.752000, + "us-east-2|c5ad.24xlarge": 4.128000, + "us-east-2|c5ad.2xlarge": 0.344000, + "us-east-2|c5ad.4xlarge": 0.688000, + "us-east-2|c5ad.8xlarge": 1.376000, + "us-east-2|c5ad.large": 0.086000, + "us-east-2|c5ad.xlarge": 0.172000, + "us-east-2|c5d.12xlarge": 2.304000, + "us-east-2|c5d.18xlarge": 3.456000, + "us-east-2|c5d.24xlarge": 4.608000, + "us-east-2|c5d.2xlarge": 0.384000, + "us-east-2|c5d.4xlarge": 0.768000, + "us-east-2|c5d.9xlarge": 1.728000, + "us-east-2|c5d.large": 0.096000, + "us-east-2|c5d.metal": 4.608000, + "us-east-2|c5d.xlarge": 0.192000, + "us-east-2|c5n.18xlarge": 3.888000, + "us-east-2|c5n.2xlarge": 0.432000, + "us-east-2|c5n.4xlarge": 0.864000, + "us-east-2|c5n.9xlarge": 1.944000, + "us-east-2|c5n.large": 0.108000, + "us-east-2|c5n.metal": 3.888000, + "us-east-2|c5n.xlarge": 0.216000, + "us-east-2|c6a.12xlarge": 1.836000, + "us-east-2|c6a.16xlarge": 2.448000, + "us-east-2|c6a.24xlarge": 3.672000, + "us-east-2|c6a.2xlarge": 0.306000, + "us-east-2|c6a.32xlarge": 4.896000, + "us-east-2|c6a.48xlarge": 7.344000, + "us-east-2|c6a.4xlarge": 0.612000, + "us-east-2|c6a.8xlarge": 1.224000, + "us-east-2|c6a.large": 0.076500, + "us-east-2|c6a.metal": 7.344000, + "us-east-2|c6a.xlarge": 0.153000, + "us-east-2|c6g.12xlarge": 1.632000, + "us-east-2|c6g.16xlarge": 2.176000, + "us-east-2|c6g.2xlarge": 0.272000, + "us-east-2|c6g.4xlarge": 0.544000, + "us-east-2|c6g.8xlarge": 1.088000, + "us-east-2|c6g.large": 0.068000, + "us-east-2|c6g.medium": 0.034000, + "us-east-2|c6g.metal": 2.176000, + "us-east-2|c6g.xlarge": 0.136000, + "us-east-2|c6gd.12xlarge": 1.843200, + "us-east-2|c6gd.16xlarge": 2.457600, + "us-east-2|c6gd.2xlarge": 0.307200, + "us-east-2|c6gd.4xlarge": 0.614400, + "us-east-2|c6gd.8xlarge": 1.228800, + "us-east-2|c6gd.large": 0.076800, + "us-east-2|c6gd.medium": 0.038400, + "us-east-2|c6gd.metal": 2.457600, + "us-east-2|c6gd.xlarge": 0.153600, + "us-east-2|c6gn.12xlarge": 2.073600, + "us-east-2|c6gn.16xlarge": 2.764800, + "us-east-2|c6gn.2xlarge": 0.345600, + "us-east-2|c6gn.4xlarge": 0.691200, + "us-east-2|c6gn.8xlarge": 1.382400, + "us-east-2|c6gn.large": 0.086400, + "us-east-2|c6gn.medium": 0.043200, + "us-east-2|c6gn.xlarge": 0.172800, + "us-east-2|c6i.12xlarge": 2.040000, + "us-east-2|c6i.16xlarge": 2.720000, + "us-east-2|c6i.24xlarge": 4.080000, + "us-east-2|c6i.2xlarge": 0.340000, + "us-east-2|c6i.32xlarge": 5.440000, + "us-east-2|c6i.4xlarge": 0.680000, + "us-east-2|c6i.8xlarge": 1.360000, + "us-east-2|c6i.large": 0.085000, + "us-east-2|c6i.metal": 5.440000, + "us-east-2|c6i.xlarge": 0.170000, + "us-east-2|c6id.12xlarge": 2.419200, + "us-east-2|c6id.16xlarge": 3.225600, + "us-east-2|c6id.24xlarge": 4.838400, + "us-east-2|c6id.2xlarge": 0.403200, + "us-east-2|c6id.32xlarge": 6.451200, + "us-east-2|c6id.4xlarge": 0.806400, + "us-east-2|c6id.8xlarge": 1.612800, + "us-east-2|c6id.large": 0.100800, + "us-east-2|c6id.metal": 6.451200, + "us-east-2|c6id.xlarge": 0.201600, + "us-east-2|c6in.12xlarge": 2.721600, + "us-east-2|c6in.16xlarge": 3.628800, + "us-east-2|c6in.24xlarge": 5.443200, + "us-east-2|c6in.2xlarge": 0.453600, + "us-east-2|c6in.32xlarge": 7.257600, + "us-east-2|c6in.4xlarge": 0.907200, + "us-east-2|c6in.8xlarge": 1.814400, + "us-east-2|c6in.large": 0.113400, + "us-east-2|c6in.metal": 7.257600, + "us-east-2|c6in.xlarge": 0.226800, + "us-east-2|c7a.12xlarge": 2.463360, + "us-east-2|c7a.16xlarge": 3.284480, + "us-east-2|c7a.24xlarge": 4.926720, + "us-east-2|c7a.2xlarge": 0.410560, + "us-east-2|c7a.32xlarge": 6.568960, + "us-east-2|c7a.48xlarge": 9.853440, + "us-east-2|c7a.4xlarge": 0.821120, + "us-east-2|c7a.8xlarge": 1.642240, + "us-east-2|c7a.large": 0.102640, + "us-east-2|c7a.medium": 0.051320, + "us-east-2|c7a.metal-48xl": 9.853440, + "us-east-2|c7a.xlarge": 0.205280, + "us-east-2|c7g.12xlarge": 1.734200, + "us-east-2|c7g.16xlarge": 2.312300, + "us-east-2|c7g.2xlarge": 0.289000, + "us-east-2|c7g.4xlarge": 0.578100, + "us-east-2|c7g.8xlarge": 1.156200, + "us-east-2|c7g.large": 0.072300, + "us-east-2|c7g.medium": 0.036100, + "us-east-2|c7g.metal": 2.312300, + "us-east-2|c7g.xlarge": 0.144500, + "us-east-2|c7gd.12xlarge": 2.177300, + "us-east-2|c7gd.16xlarge": 2.903000, + "us-east-2|c7gd.2xlarge": 0.362900, + "us-east-2|c7gd.4xlarge": 0.725800, + "us-east-2|c7gd.8xlarge": 1.451500, + "us-east-2|c7gd.large": 0.090700, + "us-east-2|c7gd.medium": 0.045400, + "us-east-2|c7gd.metal": 2.903000, + "us-east-2|c7gd.xlarge": 0.181400, + "us-east-2|c7gn.12xlarge": 2.995200, + "us-east-2|c7gn.16xlarge": 3.993600, + "us-east-2|c7gn.2xlarge": 0.499200, + "us-east-2|c7gn.4xlarge": 0.998400, + "us-east-2|c7gn.8xlarge": 1.996800, + "us-east-2|c7gn.large": 0.124800, + "us-east-2|c7gn.medium": 0.062400, + "us-east-2|c7gn.metal": 3.993600, + "us-east-2|c7gn.xlarge": 0.249600, + "us-east-2|c7i-flex.12xlarge": 2.034900, + "us-east-2|c7i-flex.16xlarge": 2.713200, + "us-east-2|c7i-flex.2xlarge": 0.339150, + "us-east-2|c7i-flex.4xlarge": 0.678300, + "us-east-2|c7i-flex.8xlarge": 1.356600, + "us-east-2|c7i-flex.large": 0.084790, + "us-east-2|c7i-flex.xlarge": 0.169580, + "us-east-2|c7i.12xlarge": 2.142000, + "us-east-2|c7i.16xlarge": 2.856000, + "us-east-2|c7i.24xlarge": 4.284000, + "us-east-2|c7i.2xlarge": 0.357000, + "us-east-2|c7i.48xlarge": 8.568000, + "us-east-2|c7i.4xlarge": 0.714000, + "us-east-2|c7i.8xlarge": 1.428000, + "us-east-2|c7i.large": 0.089250, + "us-east-2|c7i.metal-24xl": 4.284000, + "us-east-2|c7i.metal-48xl": 8.568000, + "us-east-2|c7i.xlarge": 0.178500, + "us-east-2|c8a.12xlarge": 2.586480, + "us-east-2|c8a.16xlarge": 3.448640, + "us-east-2|c8a.24xlarge": 5.172960, + "us-east-2|c8a.2xlarge": 0.431080, + "us-east-2|c8a.48xlarge": 10.345920, + "us-east-2|c8a.4xlarge": 0.862160, + "us-east-2|c8a.8xlarge": 1.724320, + "us-east-2|c8a.large": 0.107770, + "us-east-2|c8a.medium": 0.053890, + "us-east-2|c8a.metal-24xl": 5.172960, + "us-east-2|c8a.metal-48xl": 10.345920, + "us-east-2|c8a.xlarge": 0.215540, + "us-east-2|c8g.12xlarge": 1.907520, + "us-east-2|c8g.16xlarge": 2.543360, + "us-east-2|c8g.24xlarge": 3.815040, + "us-east-2|c8g.2xlarge": 0.317920, + "us-east-2|c8g.48xlarge": 7.630080, + "us-east-2|c8g.4xlarge": 0.635840, + "us-east-2|c8g.8xlarge": 1.271680, + "us-east-2|c8g.large": 0.079480, + "us-east-2|c8g.medium": 0.039740, + "us-east-2|c8g.metal-24xl": 3.815040, + "us-east-2|c8g.metal-48xl": 7.630080, + "us-east-2|c8g.xlarge": 0.158960, + "us-east-2|c8gd.12xlarge": 2.351520, + "us-east-2|c8gd.16xlarge": 3.135360, + "us-east-2|c8gd.24xlarge": 4.703040, + "us-east-2|c8gd.2xlarge": 0.391920, + "us-east-2|c8gd.48xlarge": 9.406080, + "us-east-2|c8gd.4xlarge": 0.783840, + "us-east-2|c8gd.8xlarge": 1.567680, + "us-east-2|c8gd.large": 0.097980, + "us-east-2|c8gd.medium": 0.048990, + "us-east-2|c8gd.metal-24xl": 4.703040, + "us-east-2|c8gd.metal-48xl": 9.406080, + "us-east-2|c8gd.xlarge": 0.195960, + "us-east-2|c8gn.12xlarge": 2.844000, + "us-east-2|c8gn.16xlarge": 3.792000, + "us-east-2|c8gn.24xlarge": 5.688000, + "us-east-2|c8gn.2xlarge": 0.474000, + "us-east-2|c8gn.48xlarge": 11.376000, + "us-east-2|c8gn.4xlarge": 0.948000, + "us-east-2|c8gn.8xlarge": 1.896000, + "us-east-2|c8gn.large": 0.118500, + "us-east-2|c8gn.medium": 0.059300, + "us-east-2|c8gn.xlarge": 0.237000, + "us-east-2|c8i-flex.12xlarge": 2.136480, + "us-east-2|c8i-flex.16xlarge": 2.848640, + "us-east-2|c8i-flex.2xlarge": 0.356080, + "us-east-2|c8i-flex.4xlarge": 0.712160, + "us-east-2|c8i-flex.8xlarge": 1.424320, + "us-east-2|c8i-flex.large": 0.089020, + "us-east-2|c8i-flex.xlarge": 0.178040, + "us-east-2|c8i.12xlarge": 2.249040, + "us-east-2|c8i.16xlarge": 2.998720, + "us-east-2|c8i.24xlarge": 4.498080, + "us-east-2|c8i.2xlarge": 0.374840, + "us-east-2|c8i.32xlarge": 5.997440, + "us-east-2|c8i.48xlarge": 8.996160, + "us-east-2|c8i.4xlarge": 0.749680, + "us-east-2|c8i.8xlarge": 1.499360, + "us-east-2|c8i.96xlarge": 17.992320, + "us-east-2|c8i.large": 0.093710, + "us-east-2|c8i.metal-48xl": 8.996160, + "us-east-2|c8i.metal-96xl": 17.992320, + "us-east-2|c8i.xlarge": 0.187420, + "us-east-2|d2.2xlarge": 1.380000, + "us-east-2|d2.4xlarge": 2.760000, + "us-east-2|d2.8xlarge": 5.520000, + "us-east-2|d2.xlarge": 0.690000, + "us-east-2|d3.2xlarge": 0.999000, + "us-east-2|d3.4xlarge": 1.998000, + "us-east-2|d3.8xlarge": 3.995520, + "us-east-2|d3.xlarge": 0.499000, + "us-east-2|g3.16xlarge": 4.560000, + "us-east-2|g3.4xlarge": 1.140000, + "us-east-2|g3.8xlarge": 2.280000, + "us-east-2|g3s.xlarge": 0.750000, + "us-east-2|g4ad.16xlarge": 3.468000, + "us-east-2|g4ad.2xlarge": 0.541170, + "us-east-2|g4ad.4xlarge": 0.867000, + "us-east-2|g4ad.8xlarge": 1.734000, + "us-east-2|g4ad.xlarge": 0.378530, + "us-east-2|g4dn.12xlarge": 3.912000, + "us-east-2|g4dn.16xlarge": 4.352000, + "us-east-2|g4dn.2xlarge": 0.752000, + "us-east-2|g4dn.4xlarge": 1.204000, + "us-east-2|g4dn.8xlarge": 2.176000, + "us-east-2|g4dn.metal": 7.824000, + "us-east-2|g4dn.xlarge": 0.526000, + "us-east-2|g5.12xlarge": 5.672000, + "us-east-2|g5.16xlarge": 4.096000, + "us-east-2|g5.24xlarge": 8.144000, + "us-east-2|g5.2xlarge": 1.212000, + "us-east-2|g5.48xlarge": 16.288000, + "us-east-2|g5.4xlarge": 1.624000, + "us-east-2|g5.8xlarge": 2.448000, + "us-east-2|g5.xlarge": 1.006000, + "us-east-2|g6.12xlarge": 4.601600, + "us-east-2|g6.16xlarge": 3.396800, + "us-east-2|g6.24xlarge": 6.675200, + "us-east-2|g6.2xlarge": 0.977600, + "us-east-2|g6.48xlarge": 13.350400, + "us-east-2|g6.4xlarge": 1.323200, + "us-east-2|g6.8xlarge": 2.014400, + "us-east-2|g6.xlarge": 0.804800, + "us-east-2|g6e.12xlarge": 10.492640, + "us-east-2|g6e.16xlarge": 7.577190, + "us-east-2|g6e.24xlarge": 15.065590, + "us-east-2|g6e.2xlarge": 2.242080, + "us-east-2|g6e.48xlarge": 30.131180, + "us-east-2|g6e.4xlarge": 3.004240, + "us-east-2|g6e.8xlarge": 4.528560, + "us-east-2|g6e.xlarge": 1.861000, + "us-east-2|g6f.2xlarge": 0.475000, + "us-east-2|g6f.4xlarge": 0.950000, + "us-east-2|g6f.large": 0.202000, + "us-east-2|g6f.xlarge": 0.237500, + "us-east-2|gr6.4xlarge": 1.539200, + "us-east-2|gr6.8xlarge": 2.446400, + "us-east-2|gr6f.4xlarge": 1.066000, + "us-east-2|h1.16xlarge": 3.744000, + "us-east-2|h1.2xlarge": 0.468000, + "us-east-2|h1.4xlarge": 0.936000, + "us-east-2|h1.8xlarge": 1.872000, + "us-east-2|hpc6a.48xlarge": 2.880000, + "us-east-2|hpc6id.32xlarge": 5.700000, + "us-east-2|hpc7a.12xlarge": 7.200000, + "us-east-2|hpc7a.24xlarge": 7.200000, + "us-east-2|hpc7a.48xlarge": 7.200000, + "us-east-2|hpc7a.96xlarge": 7.200000, + "us-east-2|i2.2xlarge": 1.705000, + "us-east-2|i2.4xlarge": 3.410000, + "us-east-2|i2.8xlarge": 6.820000, + "us-east-2|i2.xlarge": 0.853000, + "us-east-2|i3.16xlarge": 4.992000, + "us-east-2|i3.2xlarge": 0.624000, + "us-east-2|i3.4xlarge": 1.248000, + "us-east-2|i3.8xlarge": 2.496000, + "us-east-2|i3.large": 0.156000, + "us-east-2|i3.metal": 4.992000, + "us-east-2|i3.xlarge": 0.312000, + "us-east-2|i3en.12xlarge": 5.424000, + "us-east-2|i3en.24xlarge": 10.848000, + "us-east-2|i3en.2xlarge": 0.904000, + "us-east-2|i3en.3xlarge": 1.356000, + "us-east-2|i3en.6xlarge": 2.712000, + "us-east-2|i3en.large": 0.226000, + "us-east-2|i3en.metal": 10.848000, + "us-east-2|i3en.xlarge": 0.452000, + "us-east-2|i4g.16xlarge": 4.942080, + "us-east-2|i4g.2xlarge": 0.617760, + "us-east-2|i4g.4xlarge": 1.235520, + "us-east-2|i4g.8xlarge": 2.471040, + "us-east-2|i4g.large": 0.154440, + "us-east-2|i4g.xlarge": 0.308880, + "us-east-2|i4i.12xlarge": 4.118000, + "us-east-2|i4i.16xlarge": 5.491000, + "us-east-2|i4i.24xlarge": 8.236800, + "us-east-2|i4i.2xlarge": 0.686000, + "us-east-2|i4i.32xlarge": 10.982400, + "us-east-2|i4i.4xlarge": 1.373000, + "us-east-2|i4i.8xlarge": 2.746000, + "us-east-2|i4i.large": 0.172000, + "us-east-2|i4i.metal": 10.982000, + "us-east-2|i4i.xlarge": 0.343000, + "us-east-2|i7i.12xlarge": 4.530200, + "us-east-2|i7i.16xlarge": 6.040300, + "us-east-2|i7i.24xlarge": 9.060500, + "us-east-2|i7i.2xlarge": 0.755000, + "us-east-2|i7i.48xlarge": 18.121000, + "us-east-2|i7i.4xlarge": 1.510100, + "us-east-2|i7i.8xlarge": 3.020200, + "us-east-2|i7i.large": 0.188800, + "us-east-2|i7i.metal-24xl": 9.060500, + "us-east-2|i7i.metal-48xl": 18.121000, + "us-east-2|i7i.xlarge": 0.377500, + "us-east-2|i7ie.12xlarge": 6.237600, + "us-east-2|i7ie.18xlarge": 9.356400, + "us-east-2|i7ie.24xlarge": 12.475200, + "us-east-2|i7ie.2xlarge": 1.039600, + "us-east-2|i7ie.3xlarge": 1.559400, + "us-east-2|i7ie.48xlarge": 24.950400, + "us-east-2|i7ie.6xlarge": 3.118800, + "us-east-2|i7ie.large": 0.259900, + "us-east-2|i7ie.metal-24xl": 12.475200, + "us-east-2|i7ie.metal-48xl": 24.950400, + "us-east-2|i7ie.xlarge": 0.519800, + "us-east-2|i8g.12xlarge": 4.118400, + "us-east-2|i8g.16xlarge": 5.491200, + "us-east-2|i8g.24xlarge": 8.236800, + "us-east-2|i8g.2xlarge": 0.686400, + "us-east-2|i8g.48xlarge": 16.473600, + "us-east-2|i8g.4xlarge": 1.372800, + "us-east-2|i8g.8xlarge": 2.745600, + "us-east-2|i8g.large": 0.171600, + "us-east-2|i8g.metal-24xl": 8.236800, + "us-east-2|i8g.xlarge": 0.343200, + "us-east-2|i8ge.12xlarge": 5.695200, + "us-east-2|i8ge.18xlarge": 8.542800, + "us-east-2|i8ge.24xlarge": 11.390400, + "us-east-2|i8ge.2xlarge": 0.949200, + "us-east-2|i8ge.3xlarge": 1.423800, + "us-east-2|i8ge.48xlarge": 22.780800, + "us-east-2|i8ge.6xlarge": 2.847600, + "us-east-2|i8ge.large": 0.237300, + "us-east-2|i8ge.metal-24xl": 11.390400, + "us-east-2|i8ge.metal-48xl": 22.780800, + "us-east-2|i8ge.xlarge": 0.474600, + "us-east-2|im4gn.16xlarge": 5.820670, + "us-east-2|im4gn.2xlarge": 0.727580, + "us-east-2|im4gn.4xlarge": 1.455170, + "us-east-2|im4gn.8xlarge": 2.910340, + "us-east-2|im4gn.large": 0.181900, + "us-east-2|im4gn.xlarge": 0.363790, + "us-east-2|inf1.24xlarge": 4.721000, + "us-east-2|inf1.2xlarge": 0.362000, + "us-east-2|inf1.6xlarge": 1.180000, + "us-east-2|inf1.xlarge": 0.228000, + "us-east-2|inf2.24xlarge": 6.490630, + "us-east-2|inf2.48xlarge": 12.981270, + "us-east-2|inf2.8xlarge": 1.967860, + "us-east-2|inf2.xlarge": 0.758200, + "us-east-2|is4gen.2xlarge": 1.152600, + "us-east-2|is4gen.4xlarge": 2.305200, + "us-east-2|is4gen.8xlarge": 4.610400, + "us-east-2|is4gen.large": 0.288150, + "us-east-2|is4gen.medium": 0.144080, + "us-east-2|is4gen.xlarge": 0.576300, + "us-east-2|m4.10xlarge": 2.000000, + "us-east-2|m4.16xlarge": 3.200000, + "us-east-2|m4.2xlarge": 0.400000, + "us-east-2|m4.4xlarge": 0.800000, + "us-east-2|m4.large": 0.100000, + "us-east-2|m4.xlarge": 0.200000, + "us-east-2|m5.12xlarge": 2.304000, + "us-east-2|m5.16xlarge": 3.072000, + "us-east-2|m5.24xlarge": 4.608000, + "us-east-2|m5.2xlarge": 0.384000, + "us-east-2|m5.4xlarge": 0.768000, + "us-east-2|m5.8xlarge": 1.536000, + "us-east-2|m5.large": 0.096000, + "us-east-2|m5.metal": 4.608000, + "us-east-2|m5.xlarge": 0.192000, + "us-east-2|m5a.12xlarge": 2.064000, + "us-east-2|m5a.16xlarge": 2.752000, + "us-east-2|m5a.24xlarge": 4.128000, + "us-east-2|m5a.2xlarge": 0.344000, + "us-east-2|m5a.4xlarge": 0.688000, + "us-east-2|m5a.8xlarge": 1.376000, + "us-east-2|m5a.large": 0.086000, + "us-east-2|m5a.xlarge": 0.172000, + "us-east-2|m5ad.12xlarge": 2.472000, + "us-east-2|m5ad.16xlarge": 3.296000, + "us-east-2|m5ad.24xlarge": 4.944000, + "us-east-2|m5ad.2xlarge": 0.412000, + "us-east-2|m5ad.4xlarge": 0.824000, + "us-east-2|m5ad.8xlarge": 1.648000, + "us-east-2|m5ad.large": 0.103000, + "us-east-2|m5ad.xlarge": 0.206000, + "us-east-2|m5d.12xlarge": 2.712000, + "us-east-2|m5d.16xlarge": 3.616000, + "us-east-2|m5d.24xlarge": 5.424000, + "us-east-2|m5d.2xlarge": 0.452000, + "us-east-2|m5d.4xlarge": 0.904000, + "us-east-2|m5d.8xlarge": 1.808000, + "us-east-2|m5d.large": 0.113000, + "us-east-2|m5d.metal": 5.424000, + "us-east-2|m5d.xlarge": 0.226000, + "us-east-2|m5dn.12xlarge": 3.264000, + "us-east-2|m5dn.16xlarge": 4.352000, + "us-east-2|m5dn.24xlarge": 6.528000, + "us-east-2|m5dn.2xlarge": 0.544000, + "us-east-2|m5dn.4xlarge": 1.088000, + "us-east-2|m5dn.8xlarge": 2.176000, + "us-east-2|m5dn.large": 0.136000, + "us-east-2|m5dn.metal": 6.528000, + "us-east-2|m5dn.xlarge": 0.272000, + "us-east-2|m5n.12xlarge": 2.856000, + "us-east-2|m5n.16xlarge": 3.808000, + "us-east-2|m5n.24xlarge": 5.712000, + "us-east-2|m5n.2xlarge": 0.476000, + "us-east-2|m5n.4xlarge": 0.952000, + "us-east-2|m5n.8xlarge": 1.904000, + "us-east-2|m5n.large": 0.119000, + "us-east-2|m5n.metal": 5.712000, + "us-east-2|m5n.xlarge": 0.238000, + "us-east-2|m5zn.12xlarge": 3.964100, + "us-east-2|m5zn.2xlarge": 0.660700, + "us-east-2|m5zn.3xlarge": 0.991000, + "us-east-2|m5zn.6xlarge": 1.982000, + "us-east-2|m5zn.large": 0.165200, + "us-east-2|m5zn.metal": 3.964100, + "us-east-2|m5zn.xlarge": 0.330300, + "us-east-2|m6a.12xlarge": 2.073600, + "us-east-2|m6a.16xlarge": 2.764800, + "us-east-2|m6a.24xlarge": 4.147200, + "us-east-2|m6a.2xlarge": 0.345600, + "us-east-2|m6a.32xlarge": 5.529600, + "us-east-2|m6a.48xlarge": 8.294400, + "us-east-2|m6a.4xlarge": 0.691200, + "us-east-2|m6a.8xlarge": 1.382400, + "us-east-2|m6a.large": 0.086400, + "us-east-2|m6a.metal": 8.294400, + "us-east-2|m6a.xlarge": 0.172800, + "us-east-2|m6g.12xlarge": 1.848000, + "us-east-2|m6g.16xlarge": 2.464000, + "us-east-2|m6g.2xlarge": 0.308000, + "us-east-2|m6g.4xlarge": 0.616000, + "us-east-2|m6g.8xlarge": 1.232000, + "us-east-2|m6g.large": 0.077000, + "us-east-2|m6g.medium": 0.038500, + "us-east-2|m6g.metal": 2.464000, + "us-east-2|m6g.xlarge": 0.154000, + "us-east-2|m6gd.12xlarge": 2.169600, + "us-east-2|m6gd.16xlarge": 2.892800, + "us-east-2|m6gd.2xlarge": 0.361600, + "us-east-2|m6gd.4xlarge": 0.723200, + "us-east-2|m6gd.8xlarge": 1.446400, + "us-east-2|m6gd.large": 0.090400, + "us-east-2|m6gd.medium": 0.045200, + "us-east-2|m6gd.metal": 2.892800, + "us-east-2|m6gd.xlarge": 0.180800, + "us-east-2|m6i.12xlarge": 2.304000, + "us-east-2|m6i.16xlarge": 3.072000, + "us-east-2|m6i.24xlarge": 4.608000, + "us-east-2|m6i.2xlarge": 0.384000, + "us-east-2|m6i.32xlarge": 6.144000, + "us-east-2|m6i.4xlarge": 0.768000, + "us-east-2|m6i.8xlarge": 1.536000, + "us-east-2|m6i.large": 0.096000, + "us-east-2|m6i.metal": 6.144000, + "us-east-2|m6i.xlarge": 0.192000, + "us-east-2|m6id.12xlarge": 2.847600, + "us-east-2|m6id.16xlarge": 3.796800, + "us-east-2|m6id.24xlarge": 5.695200, + "us-east-2|m6id.2xlarge": 0.474600, + "us-east-2|m6id.32xlarge": 7.593600, + "us-east-2|m6id.4xlarge": 0.949200, + "us-east-2|m6id.8xlarge": 1.898400, + "us-east-2|m6id.large": 0.118650, + "us-east-2|m6id.metal": 7.593600, + "us-east-2|m6id.xlarge": 0.237300, + "us-east-2|m6idn.12xlarge": 3.818880, + "us-east-2|m6idn.16xlarge": 5.091840, + "us-east-2|m6idn.24xlarge": 7.637760, + "us-east-2|m6idn.2xlarge": 0.636480, + "us-east-2|m6idn.32xlarge": 10.183680, + "us-east-2|m6idn.4xlarge": 1.272960, + "us-east-2|m6idn.8xlarge": 2.545920, + "us-east-2|m6idn.large": 0.159120, + "us-east-2|m6idn.metal": 10.183680, + "us-east-2|m6idn.xlarge": 0.318240, + "us-east-2|m6in.12xlarge": 3.341520, + "us-east-2|m6in.16xlarge": 4.455360, + "us-east-2|m6in.24xlarge": 6.683040, + "us-east-2|m6in.2xlarge": 0.556920, + "us-east-2|m6in.32xlarge": 8.910720, + "us-east-2|m6in.4xlarge": 1.113840, + "us-east-2|m6in.8xlarge": 2.227680, + "us-east-2|m6in.large": 0.139230, + "us-east-2|m6in.metal": 8.910720, + "us-east-2|m6in.xlarge": 0.278460, + "us-east-2|m7a.12xlarge": 2.782080, + "us-east-2|m7a.16xlarge": 3.709440, + "us-east-2|m7a.24xlarge": 5.564160, + "us-east-2|m7a.2xlarge": 0.463680, + "us-east-2|m7a.32xlarge": 7.418880, + "us-east-2|m7a.48xlarge": 11.128320, + "us-east-2|m7a.4xlarge": 0.927360, + "us-east-2|m7a.8xlarge": 1.854720, + "us-east-2|m7a.large": 0.115920, + "us-east-2|m7a.medium": 0.057960, + "us-east-2|m7a.metal-48xl": 11.128320, + "us-east-2|m7a.xlarge": 0.231840, + "us-east-2|m7g.12xlarge": 1.958400, + "us-east-2|m7g.16xlarge": 2.611200, + "us-east-2|m7g.2xlarge": 0.326400, + "us-east-2|m7g.4xlarge": 0.652800, + "us-east-2|m7g.8xlarge": 1.305600, + "us-east-2|m7g.large": 0.081600, + "us-east-2|m7g.medium": 0.040800, + "us-east-2|m7g.metal": 2.611200, + "us-east-2|m7g.xlarge": 0.163200, + "us-east-2|m7gd.12xlarge": 2.562800, + "us-east-2|m7gd.16xlarge": 3.417100, + "us-east-2|m7gd.2xlarge": 0.427100, + "us-east-2|m7gd.4xlarge": 0.854300, + "us-east-2|m7gd.8xlarge": 1.708600, + "us-east-2|m7gd.large": 0.106800, + "us-east-2|m7gd.medium": 0.053400, + "us-east-2|m7gd.metal": 3.417100, + "us-east-2|m7gd.xlarge": 0.213600, + "us-east-2|m7i-flex.12xlarge": 2.298240, + "us-east-2|m7i-flex.16xlarge": 3.064320, + "us-east-2|m7i-flex.2xlarge": 0.383040, + "us-east-2|m7i-flex.4xlarge": 0.766080, + "us-east-2|m7i-flex.8xlarge": 1.532160, + "us-east-2|m7i-flex.large": 0.095760, + "us-east-2|m7i-flex.xlarge": 0.191520, + "us-east-2|m7i.12xlarge": 2.419200, + "us-east-2|m7i.16xlarge": 3.225600, + "us-east-2|m7i.24xlarge": 4.838400, + "us-east-2|m7i.2xlarge": 0.403200, + "us-east-2|m7i.48xlarge": 9.676800, + "us-east-2|m7i.4xlarge": 0.806400, + "us-east-2|m7i.8xlarge": 1.612800, + "us-east-2|m7i.large": 0.100800, + "us-east-2|m7i.metal-24xl": 4.838400, + "us-east-2|m7i.metal-48xl": 9.676800, + "us-east-2|m7i.xlarge": 0.201600, + "us-east-2|m8a.12xlarge": 2.921280, + "us-east-2|m8a.16xlarge": 3.895040, + "us-east-2|m8a.24xlarge": 5.842560, + "us-east-2|m8a.2xlarge": 0.486880, + "us-east-2|m8a.48xlarge": 11.685120, + "us-east-2|m8a.4xlarge": 0.973760, + "us-east-2|m8a.8xlarge": 1.947520, + "us-east-2|m8a.large": 0.121720, + "us-east-2|m8a.medium": 0.060860, + "us-east-2|m8a.metal-24xl": 5.842560, + "us-east-2|m8a.metal-48xl": 11.685120, + "us-east-2|m8a.xlarge": 0.243440, + "us-east-2|m8g.12xlarge": 2.154240, + "us-east-2|m8g.16xlarge": 2.872320, + "us-east-2|m8g.24xlarge": 4.308480, + "us-east-2|m8g.2xlarge": 0.359040, + "us-east-2|m8g.48xlarge": 8.616960, + "us-east-2|m8g.4xlarge": 0.718080, + "us-east-2|m8g.8xlarge": 1.436160, + "us-east-2|m8g.large": 0.089760, + "us-east-2|m8g.medium": 0.044880, + "us-east-2|m8g.metal-24xl": 4.308480, + "us-east-2|m8g.metal-48xl": 8.616960, + "us-east-2|m8g.xlarge": 0.179520, + "us-east-2|m8gd.12xlarge": 2.767680, + "us-east-2|m8gd.16xlarge": 3.690240, + "us-east-2|m8gd.24xlarge": 5.535360, + "us-east-2|m8gd.2xlarge": 0.461280, + "us-east-2|m8gd.48xlarge": 11.070720, + "us-east-2|m8gd.4xlarge": 0.922560, + "us-east-2|m8gd.8xlarge": 1.845120, + "us-east-2|m8gd.large": 0.115320, + "us-east-2|m8gd.medium": 0.057660, + "us-east-2|m8gd.metal-24xl": 5.535360, + "us-east-2|m8gd.metal-48xl": 11.070720, + "us-east-2|m8gd.xlarge": 0.230640, + "us-east-2|m8i-flex.12xlarge": 2.413200, + "us-east-2|m8i-flex.16xlarge": 3.217600, + "us-east-2|m8i-flex.2xlarge": 0.402200, + "us-east-2|m8i-flex.4xlarge": 0.804400, + "us-east-2|m8i-flex.8xlarge": 1.608800, + "us-east-2|m8i-flex.large": 0.100550, + "us-east-2|m8i-flex.xlarge": 0.201100, + "us-east-2|m8i.12xlarge": 2.540160, + "us-east-2|m8i.16xlarge": 3.386880, + "us-east-2|m8i.24xlarge": 5.080320, + "us-east-2|m8i.2xlarge": 0.423360, + "us-east-2|m8i.32xlarge": 6.773760, + "us-east-2|m8i.48xlarge": 10.160640, + "us-east-2|m8i.4xlarge": 0.846720, + "us-east-2|m8i.8xlarge": 1.693440, + "us-east-2|m8i.96xlarge": 20.321280, + "us-east-2|m8i.large": 0.105840, + "us-east-2|m8i.metal-48xl": 10.160640, + "us-east-2|m8i.metal-96xl": 20.321280, + "us-east-2|m8i.xlarge": 0.211680, + "us-east-2|p2.16xlarge": 14.400000, + "us-east-2|p2.8xlarge": 7.200000, + "us-east-2|p2.xlarge": 0.900000, + "us-east-2|p3.16xlarge": 24.480000, + "us-east-2|p3.2xlarge": 3.060000, + "us-east-2|p3.8xlarge": 12.240000, + "us-east-2|p4d.24xlarge": 21.957640, + "us-east-2|p5.48xlarge": 55.040000, + "us-east-2|p5.4xlarge": 6.880000, + "us-east-2|p5en.48xlarge": 63.296000, + "us-east-2|p6-b200.48xlarge": 113.932800, + "us-east-2|r3.2xlarge": 0.664000, + "us-east-2|r3.4xlarge": 1.328000, + "us-east-2|r3.8xlarge": 2.656000, + "us-east-2|r3.large": 0.166000, + "us-east-2|r3.xlarge": 0.332000, + "us-east-2|r4.16xlarge": 4.256000, + "us-east-2|r4.2xlarge": 0.532000, + "us-east-2|r4.4xlarge": 1.064000, + "us-east-2|r4.8xlarge": 2.128000, + "us-east-2|r4.large": 0.133000, + "us-east-2|r4.xlarge": 0.266000, + "us-east-2|r5.12xlarge": 3.024000, + "us-east-2|r5.16xlarge": 4.032000, + "us-east-2|r5.24xlarge": 6.048000, + "us-east-2|r5.2xlarge": 0.504000, + "us-east-2|r5.4xlarge": 1.008000, + "us-east-2|r5.8xlarge": 2.016000, + "us-east-2|r5.large": 0.126000, + "us-east-2|r5.metal": 6.048000, + "us-east-2|r5.xlarge": 0.252000, + "us-east-2|r5a.12xlarge": 2.712000, + "us-east-2|r5a.16xlarge": 3.616000, + "us-east-2|r5a.24xlarge": 5.424000, + "us-east-2|r5a.2xlarge": 0.452000, + "us-east-2|r5a.4xlarge": 0.904000, + "us-east-2|r5a.8xlarge": 1.808000, + "us-east-2|r5a.large": 0.113000, + "us-east-2|r5a.xlarge": 0.226000, + "us-east-2|r5ad.12xlarge": 3.144000, + "us-east-2|r5ad.16xlarge": 4.192000, + "us-east-2|r5ad.24xlarge": 6.288000, + "us-east-2|r5ad.2xlarge": 0.524000, + "us-east-2|r5ad.4xlarge": 1.048000, + "us-east-2|r5ad.8xlarge": 2.096000, + "us-east-2|r5ad.large": 0.131000, + "us-east-2|r5ad.xlarge": 0.262000, + "us-east-2|r5b.12xlarge": 3.576000, + "us-east-2|r5b.16xlarge": 4.768000, + "us-east-2|r5b.24xlarge": 7.152000, + "us-east-2|r5b.2xlarge": 0.596000, + "us-east-2|r5b.4xlarge": 1.192000, + "us-east-2|r5b.8xlarge": 2.384000, + "us-east-2|r5b.large": 0.149000, + "us-east-2|r5b.metal": 7.152000, + "us-east-2|r5b.xlarge": 0.298000, + "us-east-2|r5d.12xlarge": 3.456000, + "us-east-2|r5d.16xlarge": 4.608000, + "us-east-2|r5d.24xlarge": 6.912000, + "us-east-2|r5d.2xlarge": 0.576000, + "us-east-2|r5d.4xlarge": 1.152000, + "us-east-2|r5d.8xlarge": 2.304000, + "us-east-2|r5d.large": 0.144000, + "us-east-2|r5d.metal": 6.912000, + "us-east-2|r5d.xlarge": 0.288000, + "us-east-2|r5dn.12xlarge": 4.008000, + "us-east-2|r5dn.16xlarge": 5.344000, + "us-east-2|r5dn.24xlarge": 8.016000, + "us-east-2|r5dn.2xlarge": 0.668000, + "us-east-2|r5dn.4xlarge": 1.336000, + "us-east-2|r5dn.8xlarge": 2.672000, + "us-east-2|r5dn.large": 0.167000, + "us-east-2|r5dn.metal": 8.016000, + "us-east-2|r5dn.xlarge": 0.334000, + "us-east-2|r5n.12xlarge": 3.576000, + "us-east-2|r5n.16xlarge": 4.768000, + "us-east-2|r5n.24xlarge": 7.152000, + "us-east-2|r5n.2xlarge": 0.596000, + "us-east-2|r5n.4xlarge": 1.192000, + "us-east-2|r5n.8xlarge": 2.384000, + "us-east-2|r5n.large": 0.149000, + "us-east-2|r5n.metal": 7.152000, + "us-east-2|r5n.xlarge": 0.298000, + "us-east-2|r6a.12xlarge": 2.721600, + "us-east-2|r6a.16xlarge": 3.628800, + "us-east-2|r6a.24xlarge": 5.443200, + "us-east-2|r6a.2xlarge": 0.453600, + "us-east-2|r6a.32xlarge": 7.257600, + "us-east-2|r6a.48xlarge": 10.886400, + "us-east-2|r6a.4xlarge": 0.907200, + "us-east-2|r6a.8xlarge": 1.814400, + "us-east-2|r6a.large": 0.113400, + "us-east-2|r6a.metal": 10.886400, + "us-east-2|r6a.xlarge": 0.226800, + "us-east-2|r6g.12xlarge": 2.419200, + "us-east-2|r6g.16xlarge": 3.225600, + "us-east-2|r6g.2xlarge": 0.403200, + "us-east-2|r6g.4xlarge": 0.806400, + "us-east-2|r6g.8xlarge": 1.612800, + "us-east-2|r6g.large": 0.100800, + "us-east-2|r6g.medium": 0.050400, + "us-east-2|r6g.metal": 3.225600, + "us-east-2|r6g.xlarge": 0.201600, + "us-east-2|r6gd.12xlarge": 2.764800, + "us-east-2|r6gd.16xlarge": 3.686400, + "us-east-2|r6gd.2xlarge": 0.460800, + "us-east-2|r6gd.4xlarge": 0.921600, + "us-east-2|r6gd.8xlarge": 1.843200, + "us-east-2|r6gd.large": 0.115200, + "us-east-2|r6gd.medium": 0.057600, + "us-east-2|r6gd.metal": 3.686400, + "us-east-2|r6gd.xlarge": 0.230400, + "us-east-2|r6i.12xlarge": 3.024000, + "us-east-2|r6i.16xlarge": 4.032000, + "us-east-2|r6i.24xlarge": 6.048000, + "us-east-2|r6i.2xlarge": 0.504000, + "us-east-2|r6i.32xlarge": 8.064000, + "us-east-2|r6i.4xlarge": 1.008000, + "us-east-2|r6i.8xlarge": 2.016000, + "us-east-2|r6i.large": 0.126000, + "us-east-2|r6i.metal": 8.064000, + "us-east-2|r6i.xlarge": 0.252000, + "us-east-2|r6id.12xlarge": 3.628800, + "us-east-2|r6id.16xlarge": 4.838400, + "us-east-2|r6id.24xlarge": 7.257600, + "us-east-2|r6id.2xlarge": 0.604800, + "us-east-2|r6id.32xlarge": 9.676800, + "us-east-2|r6id.4xlarge": 1.209600, + "us-east-2|r6id.8xlarge": 2.419200, + "us-east-2|r6id.large": 0.151200, + "us-east-2|r6id.metal": 9.676800, + "us-east-2|r6id.xlarge": 0.302400, + "us-east-2|r6idn.12xlarge": 4.689360, + "us-east-2|r6idn.16xlarge": 6.252480, + "us-east-2|r6idn.24xlarge": 9.378720, + "us-east-2|r6idn.2xlarge": 0.781560, + "us-east-2|r6idn.32xlarge": 12.504960, + "us-east-2|r6idn.4xlarge": 1.563120, + "us-east-2|r6idn.8xlarge": 3.126240, + "us-east-2|r6idn.large": 0.195390, + "us-east-2|r6idn.metal": 12.504960, + "us-east-2|r6idn.xlarge": 0.390780, + "us-east-2|r6in.12xlarge": 4.183920, + "us-east-2|r6in.16xlarge": 5.578560, + "us-east-2|r6in.24xlarge": 8.367840, + "us-east-2|r6in.2xlarge": 0.697320, + "us-east-2|r6in.32xlarge": 11.157120, + "us-east-2|r6in.4xlarge": 1.394640, + "us-east-2|r6in.8xlarge": 2.789280, + "us-east-2|r6in.large": 0.174330, + "us-east-2|r6in.metal": 11.157120, + "us-east-2|r6in.xlarge": 0.348660, + "us-east-2|r7a.12xlarge": 3.651600, + "us-east-2|r7a.16xlarge": 4.868800, + "us-east-2|r7a.24xlarge": 7.303200, + "us-east-2|r7a.2xlarge": 0.608600, + "us-east-2|r7a.32xlarge": 9.737600, + "us-east-2|r7a.48xlarge": 14.606400, + "us-east-2|r7a.4xlarge": 1.217200, + "us-east-2|r7a.8xlarge": 2.434400, + "us-east-2|r7a.large": 0.152150, + "us-east-2|r7a.medium": 0.076080, + "us-east-2|r7a.metal-48xl": 14.606400, + "us-east-2|r7a.xlarge": 0.304300, + "us-east-2|r7g.12xlarge": 2.570400, + "us-east-2|r7g.16xlarge": 3.427200, + "us-east-2|r7g.2xlarge": 0.428400, + "us-east-2|r7g.4xlarge": 0.856800, + "us-east-2|r7g.8xlarge": 1.713600, + "us-east-2|r7g.large": 0.107100, + "us-east-2|r7g.medium": 0.053600, + "us-east-2|r7g.metal": 3.427200, + "us-east-2|r7g.xlarge": 0.214200, + "us-east-2|r7gd.12xlarge": 3.265900, + "us-east-2|r7gd.16xlarge": 4.354600, + "us-east-2|r7gd.2xlarge": 0.544300, + "us-east-2|r7gd.4xlarge": 1.088600, + "us-east-2|r7gd.8xlarge": 2.177300, + "us-east-2|r7gd.large": 0.136100, + "us-east-2|r7gd.medium": 0.068000, + "us-east-2|r7gd.metal": 4.354600, + "us-east-2|r7gd.xlarge": 0.272200, + "us-east-2|r7i.12xlarge": 3.175200, + "us-east-2|r7i.16xlarge": 4.233600, + "us-east-2|r7i.24xlarge": 6.350400, + "us-east-2|r7i.2xlarge": 0.529200, + "us-east-2|r7i.48xlarge": 12.700800, + "us-east-2|r7i.4xlarge": 1.058400, + "us-east-2|r7i.8xlarge": 2.116800, + "us-east-2|r7i.large": 0.132300, + "us-east-2|r7i.metal-24xl": 6.350400, + "us-east-2|r7i.metal-48xl": 12.700800, + "us-east-2|r7i.xlarge": 0.264600, + "us-east-2|r7iz.12xlarge": 4.464000, + "us-east-2|r7iz.16xlarge": 5.952000, + "us-east-2|r7iz.2xlarge": 0.744000, + "us-east-2|r7iz.32xlarge": 11.904000, + "us-east-2|r7iz.4xlarge": 1.488000, + "us-east-2|r7iz.8xlarge": 2.976000, + "us-east-2|r7iz.large": 0.186000, + "us-east-2|r7iz.metal-16xl": 5.952000, + "us-east-2|r7iz.metal-32xl": 11.904000, + "us-east-2|r7iz.xlarge": 0.372000, + "us-east-2|r8a.12xlarge": 3.834240, + "us-east-2|r8a.16xlarge": 5.112320, + "us-east-2|r8a.24xlarge": 7.668480, + "us-east-2|r8a.2xlarge": 0.639040, + "us-east-2|r8a.48xlarge": 15.336960, + "us-east-2|r8a.4xlarge": 1.278080, + "us-east-2|r8a.8xlarge": 2.556160, + "us-east-2|r8a.large": 0.159760, + "us-east-2|r8a.medium": 0.079880, + "us-east-2|r8a.metal-24xl": 7.668480, + "us-east-2|r8a.metal-48xl": 15.336960, + "us-east-2|r8a.xlarge": 0.319520, + "us-east-2|r8g.12xlarge": 2.827680, + "us-east-2|r8g.16xlarge": 3.770240, + "us-east-2|r8g.24xlarge": 5.655360, + "us-east-2|r8g.2xlarge": 0.471280, + "us-east-2|r8g.48xlarge": 11.310720, + "us-east-2|r8g.4xlarge": 0.942560, + "us-east-2|r8g.8xlarge": 1.885120, + "us-east-2|r8g.large": 0.117820, + "us-east-2|r8g.medium": 0.058910, + "us-east-2|r8g.metal-24xl": 5.655360, + "us-east-2|r8g.metal-48xl": 11.310720, + "us-east-2|r8g.xlarge": 0.235640, + "us-east-2|r8gd.12xlarge": 3.527040, + "us-east-2|r8gd.16xlarge": 4.702720, + "us-east-2|r8gd.24xlarge": 7.054080, + "us-east-2|r8gd.2xlarge": 0.587840, + "us-east-2|r8gd.48xlarge": 14.108160, + "us-east-2|r8gd.4xlarge": 1.175680, + "us-east-2|r8gd.8xlarge": 2.351360, + "us-east-2|r8gd.large": 0.146960, + "us-east-2|r8gd.medium": 0.073480, + "us-east-2|r8gd.metal-24xl": 7.054080, + "us-east-2|r8gd.metal-48xl": 14.108160, + "us-east-2|r8gd.xlarge": 0.293920, + "us-east-2|r8i-flex.12xlarge": 3.167280, + "us-east-2|r8i-flex.16xlarge": 4.223040, + "us-east-2|r8i-flex.2xlarge": 0.527880, + "us-east-2|r8i-flex.4xlarge": 1.055760, + "us-east-2|r8i-flex.8xlarge": 2.111520, + "us-east-2|r8i-flex.large": 0.131970, + "us-east-2|r8i-flex.xlarge": 0.263940, + "us-east-2|r8i.12xlarge": 3.334080, + "us-east-2|r8i.16xlarge": 4.445440, + "us-east-2|r8i.24xlarge": 6.668160, + "us-east-2|r8i.2xlarge": 0.555680, + "us-east-2|r8i.32xlarge": 8.890880, + "us-east-2|r8i.48xlarge": 13.336320, + "us-east-2|r8i.4xlarge": 1.111360, + "us-east-2|r8i.8xlarge": 2.222720, + "us-east-2|r8i.96xlarge": 26.672640, + "us-east-2|r8i.large": 0.138920, + "us-east-2|r8i.metal-48xl": 13.336320, + "us-east-2|r8i.metal-96xl": 26.672640, + "us-east-2|r8i.xlarge": 0.277840, + "us-east-2|t2.2xlarge": 0.371200, + "us-east-2|t2.large": 0.092800, + "us-east-2|t2.medium": 0.046400, + "us-east-2|t2.micro": 0.011600, + "us-east-2|t2.nano": 0.005800, + "us-east-2|t2.small": 0.023000, + "us-east-2|t2.xlarge": 0.185600, + "us-east-2|t3.2xlarge": 0.332800, + "us-east-2|t3.large": 0.083200, + "us-east-2|t3.medium": 0.041600, + "us-east-2|t3.micro": 0.010400, + "us-east-2|t3.nano": 0.005200, + "us-east-2|t3.small": 0.020800, + "us-east-2|t3.xlarge": 0.166400, + "us-east-2|t3a.2xlarge": 0.300800, + "us-east-2|t3a.large": 0.075200, + "us-east-2|t3a.medium": 0.037600, + "us-east-2|t3a.micro": 0.009400, + "us-east-2|t3a.nano": 0.004700, + "us-east-2|t3a.small": 0.018800, + "us-east-2|t3a.xlarge": 0.150400, + "us-east-2|t4g.2xlarge": 0.268800, + "us-east-2|t4g.large": 0.067200, + "us-east-2|t4g.medium": 0.033600, + "us-east-2|t4g.micro": 0.008400, + "us-east-2|t4g.nano": 0.004200, + "us-east-2|t4g.small": 0.016800, + "us-east-2|t4g.xlarge": 0.134400, + "us-east-2|trn1.2xlarge": 1.343750, + "us-east-2|trn1.32xlarge": 21.500000, + "us-east-2|trn1n.32xlarge": 24.780000, + "us-east-2|u-12tb1.112xlarge": 109.200000, + "us-east-2|u-18tb1.112xlarge": 163.800000, + "us-east-2|u-24tb1.112xlarge": 218.400000, + "us-east-2|u-3tb1.56xlarge": 27.300000, + "us-east-2|u-6tb1.112xlarge": 54.600000, + "us-east-2|u-6tb1.56xlarge": 46.403910, + "us-east-2|u-9tb1.112xlarge": 81.900000, + "us-east-2|u7i-12tb.224xlarge": 125.581820, + "us-east-2|u7i-6tb.112xlarge": 62.790000, + "us-east-2|u7i-8tb.112xlarge": 83.720000, + "us-east-2|u7in-24tb.224xlarge": 270.731280, + "us-east-2|x1.16xlarge": 6.669000, + "us-east-2|x1.32xlarge": 13.338000, + "us-east-2|x1e.16xlarge": 13.344000, + "us-east-2|x1e.2xlarge": 1.668000, + "us-east-2|x1e.32xlarge": 26.688000, + "us-east-2|x1e.4xlarge": 3.336000, + "us-east-2|x1e.8xlarge": 6.672000, + "us-east-2|x1e.xlarge": 0.834000, + "us-east-2|x2gd.12xlarge": 4.008000, + "us-east-2|x2gd.16xlarge": 5.344000, + "us-east-2|x2gd.2xlarge": 0.668000, + "us-east-2|x2gd.4xlarge": 1.336000, + "us-east-2|x2gd.8xlarge": 2.672000, + "us-east-2|x2gd.large": 0.167000, + "us-east-2|x2gd.medium": 0.083500, + "us-east-2|x2gd.metal": 5.344000, + "us-east-2|x2gd.xlarge": 0.334000, + "us-east-2|x2idn.16xlarge": 6.669000, + "us-east-2|x2idn.24xlarge": 10.003500, + "us-east-2|x2idn.32xlarge": 13.338000, + "us-east-2|x2idn.metal": 13.338000, + "us-east-2|x2iedn.16xlarge": 13.338000, + "us-east-2|x2iedn.24xlarge": 20.007000, + "us-east-2|x2iedn.2xlarge": 1.667250, + "us-east-2|x2iedn.32xlarge": 26.676000, + "us-east-2|x2iedn.4xlarge": 3.334500, + "us-east-2|x2iedn.8xlarge": 6.669000, + "us-east-2|x2iedn.metal": 26.676000, + "us-east-2|x2iedn.xlarge": 0.833630, + "us-east-2|x8g.12xlarge": 4.689600, + "us-east-2|x8g.16xlarge": 6.252800, + "us-east-2|x8g.24xlarge": 9.379200, + "us-east-2|x8g.2xlarge": 0.781600, + "us-east-2|x8g.48xlarge": 18.758400, + "us-east-2|x8g.4xlarge": 1.563200, + "us-east-2|x8g.8xlarge": 3.126400, + "us-east-2|x8g.large": 0.195400, + "us-east-2|x8g.medium": 0.097700, + "us-east-2|x8g.metal-24xl": 9.379200, + "us-east-2|x8g.metal-48xl": 18.758400, + "us-east-2|x8g.xlarge": 0.390800, + "us-east-2|z1d.12xlarge": 4.464000, + "us-east-2|z1d.2xlarge": 0.744000, + "us-east-2|z1d.3xlarge": 1.116000, + "us-east-2|z1d.6xlarge": 2.232000, + "us-east-2|z1d.large": 0.186000, + "us-east-2|z1d.metal": 4.464000, + "us-east-2|z1d.xlarge": 0.372000, + "us-west-1|c1.medium": 0.148000, + "us-west-1|c1.xlarge": 0.592000, + "us-west-1|c3.2xlarge": 0.478000, + "us-west-1|c3.4xlarge": 0.956000, + "us-west-1|c3.8xlarge": 1.912000, + "us-west-1|c3.large": 0.120000, + "us-west-1|c3.xlarge": 0.239000, + "us-west-1|c4.2xlarge": 0.498000, + "us-west-1|c4.4xlarge": 0.997000, + "us-west-1|c4.8xlarge": 1.993000, + "us-west-1|c4.large": 0.124000, + "us-west-1|c4.xlarge": 0.249000, + "us-west-1|c5.12xlarge": 2.544000, + "us-west-1|c5.18xlarge": 3.816000, + "us-west-1|c5.24xlarge": 5.088000, + "us-west-1|c5.2xlarge": 0.424000, + "us-west-1|c5.4xlarge": 0.848000, + "us-west-1|c5.9xlarge": 1.908000, + "us-west-1|c5.large": 0.106000, + "us-west-1|c5.metal": 5.088000, + "us-west-1|c5.xlarge": 0.212000, + "us-west-1|c5a.12xlarge": 2.280000, + "us-west-1|c5a.16xlarge": 3.040000, + "us-west-1|c5a.24xlarge": 4.560000, + "us-west-1|c5a.2xlarge": 0.380000, + "us-west-1|c5a.4xlarge": 0.760000, + "us-west-1|c5a.8xlarge": 1.520000, + "us-west-1|c5a.large": 0.095000, + "us-west-1|c5a.xlarge": 0.190000, + "us-west-1|c5d.12xlarge": 2.880000, + "us-west-1|c5d.18xlarge": 4.320000, + "us-west-1|c5d.24xlarge": 5.760000, + "us-west-1|c5d.2xlarge": 0.480000, + "us-west-1|c5d.4xlarge": 0.960000, + "us-west-1|c5d.9xlarge": 2.160000, + "us-west-1|c5d.large": 0.120000, + "us-west-1|c5d.metal": 5.760000, + "us-west-1|c5d.xlarge": 0.240000, + "us-west-1|c5n.18xlarge": 4.860000, + "us-west-1|c5n.2xlarge": 0.540000, + "us-west-1|c5n.4xlarge": 1.080000, + "us-west-1|c5n.9xlarge": 2.430000, + "us-west-1|c5n.large": 0.135000, + "us-west-1|c5n.metal": 4.860000, + "us-west-1|c5n.xlarge": 0.270000, + "us-west-1|c6a.12xlarge": 2.289600, + "us-west-1|c6a.16xlarge": 3.052800, + "us-west-1|c6a.24xlarge": 4.579200, + "us-west-1|c6a.2xlarge": 0.381600, + "us-west-1|c6a.32xlarge": 6.105600, + "us-west-1|c6a.48xlarge": 9.158400, + "us-west-1|c6a.4xlarge": 0.763200, + "us-west-1|c6a.8xlarge": 1.526400, + "us-west-1|c6a.large": 0.095400, + "us-west-1|c6a.metal": 9.158400, + "us-west-1|c6a.xlarge": 0.190800, + "us-west-1|c6g.12xlarge": 2.035200, + "us-west-1|c6g.16xlarge": 2.713600, + "us-west-1|c6g.2xlarge": 0.339200, + "us-west-1|c6g.4xlarge": 0.678400, + "us-west-1|c6g.8xlarge": 1.356800, + "us-west-1|c6g.large": 0.084800, + "us-west-1|c6g.medium": 0.042400, + "us-west-1|c6g.metal": 2.713600, + "us-west-1|c6g.xlarge": 0.169600, + "us-west-1|c6gd.12xlarge": 2.304000, + "us-west-1|c6gd.16xlarge": 3.072000, + "us-west-1|c6gd.2xlarge": 0.384000, + "us-west-1|c6gd.4xlarge": 0.768000, + "us-west-1|c6gd.8xlarge": 1.536000, + "us-west-1|c6gd.large": 0.096000, + "us-west-1|c6gd.medium": 0.048000, + "us-west-1|c6gd.metal": 3.072000, + "us-west-1|c6gd.xlarge": 0.192000, + "us-west-1|c6gn.12xlarge": 2.592000, + "us-west-1|c6gn.16xlarge": 3.456000, + "us-west-1|c6gn.2xlarge": 0.432000, + "us-west-1|c6gn.4xlarge": 0.864000, + "us-west-1|c6gn.8xlarge": 1.728000, + "us-west-1|c6gn.large": 0.108000, + "us-west-1|c6gn.medium": 0.054000, + "us-west-1|c6gn.xlarge": 0.216000, + "us-west-1|c6i.12xlarge": 2.544000, + "us-west-1|c6i.16xlarge": 3.392000, + "us-west-1|c6i.24xlarge": 5.088000, + "us-west-1|c6i.2xlarge": 0.424000, + "us-west-1|c6i.32xlarge": 6.784000, + "us-west-1|c6i.4xlarge": 0.848000, + "us-west-1|c6i.8xlarge": 1.696000, + "us-west-1|c6i.large": 0.106000, + "us-west-1|c6i.metal": 6.784000, + "us-west-1|c6i.xlarge": 0.212000, + "us-west-1|c6in.12xlarge": 3.402000, + "us-west-1|c6in.16xlarge": 4.536000, + "us-west-1|c6in.24xlarge": 6.804000, + "us-west-1|c6in.2xlarge": 0.567000, + "us-west-1|c6in.32xlarge": 9.072000, + "us-west-1|c6in.4xlarge": 1.134000, + "us-west-1|c6in.8xlarge": 2.268000, + "us-west-1|c6in.large": 0.141750, + "us-west-1|c6in.metal": 9.072000, + "us-west-1|c6in.xlarge": 0.283500, + "us-west-1|c7g.12xlarge": 2.162400, + "us-west-1|c7g.16xlarge": 2.883200, + "us-west-1|c7g.2xlarge": 0.360400, + "us-west-1|c7g.4xlarge": 0.720800, + "us-west-1|c7g.8xlarge": 1.441600, + "us-west-1|c7g.large": 0.090100, + "us-west-1|c7g.medium": 0.045100, + "us-west-1|c7g.metal": 2.883200, + "us-west-1|c7g.xlarge": 0.180200, + "us-west-1|c7gd.12xlarge": 2.721600, + "us-west-1|c7gd.16xlarge": 3.628800, + "us-west-1|c7gd.2xlarge": 0.453600, + "us-west-1|c7gd.4xlarge": 0.907200, + "us-west-1|c7gd.8xlarge": 1.814400, + "us-west-1|c7gd.large": 0.113400, + "us-west-1|c7gd.medium": 0.056700, + "us-west-1|c7gd.metal": 3.628800, + "us-west-1|c7gd.xlarge": 0.226800, + "us-west-1|c7i-flex.12xlarge": 2.537640, + "us-west-1|c7i-flex.16xlarge": 3.383520, + "us-west-1|c7i-flex.2xlarge": 0.422940, + "us-west-1|c7i-flex.4xlarge": 0.845880, + "us-west-1|c7i-flex.8xlarge": 1.691760, + "us-west-1|c7i-flex.large": 0.105740, + "us-west-1|c7i-flex.xlarge": 0.211470, + "us-west-1|c7i.12xlarge": 2.671200, + "us-west-1|c7i.16xlarge": 3.561600, + "us-west-1|c7i.24xlarge": 5.342400, + "us-west-1|c7i.2xlarge": 0.445200, + "us-west-1|c7i.48xlarge": 10.684800, + "us-west-1|c7i.4xlarge": 0.890400, + "us-west-1|c7i.8xlarge": 1.780800, + "us-west-1|c7i.large": 0.111300, + "us-west-1|c7i.metal-24xl": 5.342400, + "us-west-1|c7i.metal-48xl": 10.684800, + "us-west-1|c7i.xlarge": 0.222600, + "us-west-1|c8g.12xlarge": 2.378880, + "us-west-1|c8g.16xlarge": 3.171840, + "us-west-1|c8g.24xlarge": 4.757760, + "us-west-1|c8g.2xlarge": 0.396480, + "us-west-1|c8g.48xlarge": 9.515520, + "us-west-1|c8g.4xlarge": 0.792960, + "us-west-1|c8g.8xlarge": 1.585920, + "us-west-1|c8g.large": 0.099120, + "us-west-1|c8g.medium": 0.049560, + "us-west-1|c8g.metal-24xl": 4.757760, + "us-west-1|c8g.metal-48xl": 9.515520, + "us-west-1|c8g.xlarge": 0.198240, + "us-west-1|c8gn.12xlarge": 3.554900, + "us-west-1|c8gn.16xlarge": 4.739800, + "us-west-1|c8gn.24xlarge": 7.109800, + "us-west-1|c8gn.2xlarge": 0.592500, + "us-west-1|c8gn.48xlarge": 14.219500, + "us-west-1|c8gn.4xlarge": 1.185000, + "us-west-1|c8gn.8xlarge": 2.369900, + "us-west-1|c8gn.large": 0.148100, + "us-west-1|c8gn.medium": 0.074100, + "us-west-1|c8gn.xlarge": 0.296200, + "us-west-1|d2.2xlarge": 1.563000, + "us-west-1|d2.4xlarge": 3.125000, + "us-west-1|d2.8xlarge": 6.250000, + "us-west-1|d2.xlarge": 0.781000, + "us-west-1|g2.2xlarge": 0.702000, + "us-west-1|g2.8xlarge": 2.808000, + "us-west-1|g3.16xlarge": 6.136000, + "us-west-1|g3.4xlarge": 1.534000, + "us-west-1|g3.8xlarge": 3.068000, + "us-west-1|g4dn.12xlarge": 4.694000, + "us-west-1|g4dn.16xlarge": 5.222000, + "us-west-1|g4dn.2xlarge": 0.902000, + "us-west-1|g4dn.4xlarge": 1.445000, + "us-west-1|g4dn.8xlarge": 2.611000, + "us-west-1|g4dn.metal": 9.389000, + "us-west-1|g4dn.xlarge": 0.631000, + "us-west-1|i2.2xlarge": 1.876000, + "us-west-1|i2.4xlarge": 3.751000, + "us-west-1|i2.8xlarge": 7.502000, + "us-west-1|i2.xlarge": 0.938000, + "us-west-1|i3.16xlarge": 5.504000, + "us-west-1|i3.2xlarge": 0.688000, + "us-west-1|i3.4xlarge": 1.376000, + "us-west-1|i3.8xlarge": 2.752000, + "us-west-1|i3.large": 0.172000, + "us-west-1|i3.metal": 5.504000, + "us-west-1|i3.xlarge": 0.344000, + "us-west-1|i3en.12xlarge": 6.000000, + "us-west-1|i3en.24xlarge": 12.000000, + "us-west-1|i3en.2xlarge": 1.000000, + "us-west-1|i3en.3xlarge": 1.500000, + "us-west-1|i3en.6xlarge": 3.000000, + "us-west-1|i3en.large": 0.250000, + "us-west-1|i3en.metal": 12.000000, + "us-west-1|i3en.xlarge": 0.500000, + "us-west-1|i4i.12xlarge": 4.541000, + "us-west-1|i4i.16xlarge": 6.054000, + "us-west-1|i4i.24xlarge": 9.081600, + "us-west-1|i4i.2xlarge": 0.757000, + "us-west-1|i4i.32xlarge": 12.108800, + "us-west-1|i4i.4xlarge": 1.514000, + "us-west-1|i4i.8xlarge": 3.027000, + "us-west-1|i4i.large": 0.189000, + "us-west-1|i4i.metal": 12.109000, + "us-west-1|i4i.xlarge": 0.378000, + "us-west-1|i7i.12xlarge": 4.994900, + "us-west-1|i7i.16xlarge": 6.659800, + "us-west-1|i7i.24xlarge": 9.989800, + "us-west-1|i7i.2xlarge": 0.832500, + "us-west-1|i7i.48xlarge": 19.979500, + "us-west-1|i7i.4xlarge": 1.665000, + "us-west-1|i7i.8xlarge": 3.329900, + "us-west-1|i7i.large": 0.208100, + "us-west-1|i7i.metal-24xl": 9.989800, + "us-west-1|i7i.metal-48xl": 19.979500, + "us-west-1|i7i.xlarge": 0.416200, + "us-west-1|i7ie.12xlarge": 6.900000, + "us-west-1|i7ie.18xlarge": 10.350000, + "us-west-1|i7ie.24xlarge": 13.800000, + "us-west-1|i7ie.2xlarge": 1.150000, + "us-west-1|i7ie.3xlarge": 1.725000, + "us-west-1|i7ie.48xlarge": 27.600000, + "us-west-1|i7ie.6xlarge": 3.450000, + "us-west-1|i7ie.large": 0.287500, + "us-west-1|i7ie.metal-24xl": 13.800000, + "us-west-1|i7ie.metal-48xl": 27.600000, + "us-west-1|i7ie.xlarge": 0.575000, + "us-west-1|inf1.24xlarge": 5.671000, + "us-west-1|inf1.2xlarge": 0.435000, + "us-west-1|inf1.6xlarge": 1.418000, + "us-west-1|inf1.xlarge": 0.274000, + "us-west-1|m1.large": 0.190000, + "us-west-1|m1.medium": 0.095000, + "us-west-1|m1.small": 0.047000, + "us-west-1|m1.xlarge": 0.379000, + "us-west-1|m2.2xlarge": 0.550000, + "us-west-1|m2.4xlarge": 1.100000, + "us-west-1|m2.xlarge": 0.275000, + "us-west-1|m3.2xlarge": 0.616000, + "us-west-1|m3.large": 0.154000, + "us-west-1|m3.medium": 0.077000, + "us-west-1|m3.xlarge": 0.308000, + "us-west-1|m4.10xlarge": 2.340000, + "us-west-1|m4.16xlarge": 3.744000, + "us-west-1|m4.2xlarge": 0.468000, + "us-west-1|m4.4xlarge": 0.936000, + "us-west-1|m4.large": 0.117000, + "us-west-1|m4.xlarge": 0.234000, + "us-west-1|m5.12xlarge": 2.688000, + "us-west-1|m5.16xlarge": 3.584000, + "us-west-1|m5.24xlarge": 5.376000, + "us-west-1|m5.2xlarge": 0.448000, + "us-west-1|m5.4xlarge": 0.896000, + "us-west-1|m5.8xlarge": 1.792000, + "us-west-1|m5.large": 0.112000, + "us-west-1|m5.metal": 5.376000, + "us-west-1|m5.xlarge": 0.224000, + "us-west-1|m5a.12xlarge": 2.424000, + "us-west-1|m5a.16xlarge": 3.232000, + "us-west-1|m5a.24xlarge": 4.848000, + "us-west-1|m5a.2xlarge": 0.404000, + "us-west-1|m5a.4xlarge": 0.808000, + "us-west-1|m5a.8xlarge": 1.616000, + "us-west-1|m5a.large": 0.101000, + "us-west-1|m5a.xlarge": 0.202000, + "us-west-1|m5ad.12xlarge": 2.928000, + "us-west-1|m5ad.16xlarge": 3.904000, + "us-west-1|m5ad.24xlarge": 5.856000, + "us-west-1|m5ad.2xlarge": 0.488000, + "us-west-1|m5ad.4xlarge": 0.976000, + "us-west-1|m5ad.8xlarge": 1.952000, + "us-west-1|m5ad.large": 0.122000, + "us-west-1|m5ad.xlarge": 0.244000, + "us-west-1|m5d.12xlarge": 3.192000, + "us-west-1|m5d.16xlarge": 4.256000, + "us-west-1|m5d.24xlarge": 6.384000, + "us-west-1|m5d.2xlarge": 0.532000, + "us-west-1|m5d.4xlarge": 1.064000, + "us-west-1|m5d.8xlarge": 2.128000, + "us-west-1|m5d.large": 0.133000, + "us-west-1|m5d.metal": 6.384000, + "us-west-1|m5d.xlarge": 0.266000, + "us-west-1|m5zn.12xlarge": 4.624800, + "us-west-1|m5zn.2xlarge": 0.770800, + "us-west-1|m5zn.3xlarge": 1.156200, + "us-west-1|m5zn.6xlarge": 2.312400, + "us-west-1|m5zn.large": 0.192700, + "us-west-1|m5zn.metal": 4.624800, + "us-west-1|m5zn.xlarge": 0.385400, + "us-west-1|m6a.12xlarge": 2.419200, + "us-west-1|m6a.16xlarge": 3.225600, + "us-west-1|m6a.24xlarge": 4.838400, + "us-west-1|m6a.2xlarge": 0.403200, + "us-west-1|m6a.32xlarge": 6.451200, + "us-west-1|m6a.48xlarge": 9.676800, + "us-west-1|m6a.4xlarge": 0.806400, + "us-west-1|m6a.8xlarge": 1.612800, + "us-west-1|m6a.large": 0.100800, + "us-west-1|m6a.metal": 9.676800, + "us-west-1|m6a.xlarge": 0.201600, + "us-west-1|m6g.12xlarge": 2.150400, + "us-west-1|m6g.16xlarge": 2.867200, + "us-west-1|m6g.2xlarge": 0.358400, + "us-west-1|m6g.4xlarge": 0.716800, + "us-west-1|m6g.8xlarge": 1.433600, + "us-west-1|m6g.large": 0.089600, + "us-west-1|m6g.medium": 0.044800, + "us-west-1|m6g.metal": 2.867200, + "us-west-1|m6g.xlarge": 0.179200, + "us-west-1|m6gd.12xlarge": 2.544000, + "us-west-1|m6gd.16xlarge": 3.392000, + "us-west-1|m6gd.2xlarge": 0.424000, + "us-west-1|m6gd.4xlarge": 0.848000, + "us-west-1|m6gd.8xlarge": 1.696000, + "us-west-1|m6gd.large": 0.106000, + "us-west-1|m6gd.medium": 0.053000, + "us-west-1|m6gd.metal": 3.392000, + "us-west-1|m6gd.xlarge": 0.212000, + "us-west-1|m6i.12xlarge": 2.688000, + "us-west-1|m6i.16xlarge": 3.584000, + "us-west-1|m6i.24xlarge": 5.376000, + "us-west-1|m6i.2xlarge": 0.448000, + "us-west-1|m6i.32xlarge": 7.168000, + "us-west-1|m6i.4xlarge": 0.896000, + "us-west-1|m6i.8xlarge": 1.792000, + "us-west-1|m6i.large": 0.112000, + "us-west-1|m6i.metal": 7.168000, + "us-west-1|m6i.xlarge": 0.224000, + "us-west-1|m6id.12xlarge": 3.351600, + "us-west-1|m6id.16xlarge": 4.468800, + "us-west-1|m6id.24xlarge": 6.703200, + "us-west-1|m6id.2xlarge": 0.558600, + "us-west-1|m6id.32xlarge": 8.937600, + "us-west-1|m6id.4xlarge": 1.117200, + "us-west-1|m6id.8xlarge": 2.234400, + "us-west-1|m6id.large": 0.139650, + "us-west-1|m6id.metal": 8.937600, + "us-west-1|m6id.xlarge": 0.279300, + "us-west-1|m6idn.12xlarge": 4.402560, + "us-west-1|m6idn.16xlarge": 5.870080, + "us-west-1|m6idn.24xlarge": 8.805120, + "us-west-1|m6idn.2xlarge": 0.733760, + "us-west-1|m6idn.32xlarge": 11.740160, + "us-west-1|m6idn.4xlarge": 1.467520, + "us-west-1|m6idn.8xlarge": 2.935040, + "us-west-1|m6idn.large": 0.183440, + "us-west-1|m6idn.metal": 11.740160, + "us-west-1|m6idn.xlarge": 0.366880, + "us-west-1|m6in.12xlarge": 3.898560, + "us-west-1|m6in.16xlarge": 5.198080, + "us-west-1|m6in.24xlarge": 7.797120, + "us-west-1|m6in.2xlarge": 0.649760, + "us-west-1|m6in.32xlarge": 10.396160, + "us-west-1|m6in.4xlarge": 1.299520, + "us-west-1|m6in.8xlarge": 2.599040, + "us-west-1|m6in.large": 0.162440, + "us-west-1|m6in.metal": 10.396160, + "us-west-1|m6in.xlarge": 0.324880, + "us-west-1|m7g.12xlarge": 2.284800, + "us-west-1|m7g.16xlarge": 3.046400, + "us-west-1|m7g.2xlarge": 0.380800, + "us-west-1|m7g.4xlarge": 0.761600, + "us-west-1|m7g.8xlarge": 1.523200, + "us-west-1|m7g.large": 0.095200, + "us-west-1|m7g.medium": 0.047600, + "us-west-1|m7g.metal": 3.046400, + "us-west-1|m7g.xlarge": 0.190400, + "us-west-1|m7gd.12xlarge": 3.016400, + "us-west-1|m7gd.16xlarge": 4.021900, + "us-west-1|m7gd.2xlarge": 0.502700, + "us-west-1|m7gd.4xlarge": 1.005500, + "us-west-1|m7gd.8xlarge": 2.011000, + "us-west-1|m7gd.large": 0.125700, + "us-west-1|m7gd.medium": 0.062800, + "us-west-1|m7gd.metal": 4.021900, + "us-west-1|m7gd.xlarge": 0.251400, + "us-west-1|m7i-flex.12xlarge": 2.681280, + "us-west-1|m7i-flex.16xlarge": 3.575040, + "us-west-1|m7i-flex.2xlarge": 0.446880, + "us-west-1|m7i-flex.4xlarge": 0.893760, + "us-west-1|m7i-flex.8xlarge": 1.787520, + "us-west-1|m7i-flex.large": 0.111720, + "us-west-1|m7i-flex.xlarge": 0.223440, + "us-west-1|m7i.12xlarge": 2.822400, + "us-west-1|m7i.16xlarge": 3.763200, + "us-west-1|m7i.24xlarge": 5.644800, + "us-west-1|m7i.2xlarge": 0.470400, + "us-west-1|m7i.48xlarge": 11.289600, + "us-west-1|m7i.4xlarge": 0.940800, + "us-west-1|m7i.8xlarge": 1.881600, + "us-west-1|m7i.large": 0.117600, + "us-west-1|m7i.metal-24xl": 5.644800, + "us-west-1|m7i.metal-48xl": 11.289600, + "us-west-1|m7i.xlarge": 0.235200, + "us-west-1|m8g.12xlarge": 2.513280, + "us-west-1|m8g.16xlarge": 3.351040, + "us-west-1|m8g.24xlarge": 5.026560, + "us-west-1|m8g.2xlarge": 0.418880, + "us-west-1|m8g.48xlarge": 10.053120, + "us-west-1|m8g.4xlarge": 0.837760, + "us-west-1|m8g.8xlarge": 1.675520, + "us-west-1|m8g.large": 0.104720, + "us-west-1|m8g.medium": 0.052360, + "us-west-1|m8g.metal-24xl": 5.026560, + "us-west-1|m8g.metal-48xl": 10.053120, + "us-west-1|m8g.xlarge": 0.209440, + "us-west-1|p5.48xlarge": 68.800000, + "us-west-1|p5en.48xlarge": 79.120000, + "us-west-1|r3.2xlarge": 0.741000, + "us-west-1|r3.4xlarge": 1.482000, + "us-west-1|r3.8xlarge": 2.964000, + "us-west-1|r3.large": 0.185000, + "us-west-1|r3.xlarge": 0.371000, + "us-west-1|r4.16xlarge": 4.742400, + "us-west-1|r4.2xlarge": 0.592800, + "us-west-1|r4.4xlarge": 1.185600, + "us-west-1|r4.8xlarge": 2.371200, + "us-west-1|r4.large": 0.148200, + "us-west-1|r4.xlarge": 0.296400, + "us-west-1|r5.12xlarge": 3.360000, + "us-west-1|r5.16xlarge": 4.480000, + "us-west-1|r5.24xlarge": 6.720000, + "us-west-1|r5.2xlarge": 0.560000, + "us-west-1|r5.4xlarge": 1.120000, + "us-west-1|r5.8xlarge": 2.240000, + "us-west-1|r5.large": 0.140000, + "us-west-1|r5.metal": 6.720000, + "us-west-1|r5.xlarge": 0.280000, + "us-west-1|r5a.12xlarge": 3.024000, + "us-west-1|r5a.16xlarge": 4.032000, + "us-west-1|r5a.24xlarge": 6.048000, + "us-west-1|r5a.2xlarge": 0.504000, + "us-west-1|r5a.4xlarge": 1.008000, + "us-west-1|r5a.8xlarge": 2.016000, + "us-west-1|r5a.large": 0.126000, + "us-west-1|r5a.xlarge": 0.252000, + "us-west-1|r5ad.12xlarge": 3.552000, + "us-west-1|r5ad.16xlarge": 4.736000, + "us-west-1|r5ad.24xlarge": 7.104000, + "us-west-1|r5ad.2xlarge": 0.592000, + "us-west-1|r5ad.4xlarge": 1.184000, + "us-west-1|r5ad.8xlarge": 2.368000, + "us-west-1|r5ad.large": 0.148000, + "us-west-1|r5ad.xlarge": 0.296000, + "us-west-1|r5d.12xlarge": 3.888000, + "us-west-1|r5d.16xlarge": 5.184000, + "us-west-1|r5d.24xlarge": 7.776000, + "us-west-1|r5d.2xlarge": 0.648000, + "us-west-1|r5d.4xlarge": 1.296000, + "us-west-1|r5d.8xlarge": 2.592000, + "us-west-1|r5d.large": 0.162000, + "us-west-1|r5d.metal": 7.776000, + "us-west-1|r5d.xlarge": 0.324000, + "us-west-1|r5n.12xlarge": 4.056000, + "us-west-1|r5n.16xlarge": 5.408000, + "us-west-1|r5n.24xlarge": 8.112000, + "us-west-1|r5n.2xlarge": 0.676000, + "us-west-1|r5n.4xlarge": 1.352000, + "us-west-1|r5n.8xlarge": 2.704000, + "us-west-1|r5n.large": 0.169000, + "us-west-1|r5n.metal": 8.112000, + "us-west-1|r5n.xlarge": 0.338000, + "us-west-1|r6a.12xlarge": 3.024000, + "us-west-1|r6a.16xlarge": 4.032000, + "us-west-1|r6a.24xlarge": 6.048000, + "us-west-1|r6a.2xlarge": 0.504000, + "us-west-1|r6a.32xlarge": 8.064000, + "us-west-1|r6a.48xlarge": 12.096000, + "us-west-1|r6a.4xlarge": 1.008000, + "us-west-1|r6a.8xlarge": 2.016000, + "us-west-1|r6a.large": 0.126000, + "us-west-1|r6a.metal": 12.096000, + "us-west-1|r6a.xlarge": 0.252000, + "us-west-1|r6g.12xlarge": 2.688000, + "us-west-1|r6g.16xlarge": 3.584000, + "us-west-1|r6g.2xlarge": 0.448000, + "us-west-1|r6g.4xlarge": 0.896000, + "us-west-1|r6g.8xlarge": 1.792000, + "us-west-1|r6g.large": 0.112000, + "us-west-1|r6g.medium": 0.056000, + "us-west-1|r6g.metal": 3.584000, + "us-west-1|r6g.xlarge": 0.224000, + "us-west-1|r6gd.12xlarge": 3.120000, + "us-west-1|r6gd.16xlarge": 4.160000, + "us-west-1|r6gd.2xlarge": 0.520000, + "us-west-1|r6gd.4xlarge": 1.040000, + "us-west-1|r6gd.8xlarge": 2.080000, + "us-west-1|r6gd.large": 0.130000, + "us-west-1|r6gd.medium": 0.065000, + "us-west-1|r6gd.metal": 4.160000, + "us-west-1|r6gd.xlarge": 0.260000, + "us-west-1|r6i.12xlarge": 3.360000, + "us-west-1|r6i.16xlarge": 4.480000, + "us-west-1|r6i.24xlarge": 6.720000, + "us-west-1|r6i.2xlarge": 0.560000, + "us-west-1|r6i.32xlarge": 8.960000, + "us-west-1|r6i.4xlarge": 1.120000, + "us-west-1|r6i.8xlarge": 2.240000, + "us-west-1|r6i.large": 0.140000, + "us-west-1|r6i.metal": 8.960000, + "us-west-1|r6i.xlarge": 0.280000, + "us-west-1|r7g.12xlarge": 2.856000, + "us-west-1|r7g.16xlarge": 3.808000, + "us-west-1|r7g.2xlarge": 0.476000, + "us-west-1|r7g.4xlarge": 0.952000, + "us-west-1|r7g.8xlarge": 1.904000, + "us-west-1|r7g.large": 0.119000, + "us-west-1|r7g.medium": 0.059500, + "us-west-1|r7g.metal": 3.808000, + "us-west-1|r7g.xlarge": 0.238000, + "us-west-1|r7gd.12xlarge": 3.674200, + "us-west-1|r7gd.16xlarge": 4.898900, + "us-west-1|r7gd.2xlarge": 0.612400, + "us-west-1|r7gd.4xlarge": 1.224700, + "us-west-1|r7gd.8xlarge": 2.449400, + "us-west-1|r7gd.large": 0.153100, + "us-west-1|r7gd.medium": 0.076500, + "us-west-1|r7gd.metal": 4.898900, + "us-west-1|r7gd.xlarge": 0.306200, + "us-west-1|r7i.12xlarge": 3.528000, + "us-west-1|r7i.16xlarge": 4.704000, + "us-west-1|r7i.24xlarge": 7.056000, + "us-west-1|r7i.2xlarge": 0.588000, + "us-west-1|r7i.48xlarge": 14.112000, + "us-west-1|r7i.4xlarge": 1.176000, + "us-west-1|r7i.8xlarge": 2.352000, + "us-west-1|r7i.large": 0.147000, + "us-west-1|r7i.metal-24xl": 7.056000, + "us-west-1|r7i.metal-48xl": 14.112000, + "us-west-1|r7i.xlarge": 0.294000, + "us-west-1|r8g.12xlarge": 3.141600, + "us-west-1|r8g.16xlarge": 4.188800, + "us-west-1|r8g.24xlarge": 6.283200, + "us-west-1|r8g.2xlarge": 0.523600, + "us-west-1|r8g.48xlarge": 12.566400, + "us-west-1|r8g.4xlarge": 1.047200, + "us-west-1|r8g.8xlarge": 2.094400, + "us-west-1|r8g.large": 0.130900, + "us-west-1|r8g.medium": 0.065450, + "us-west-1|r8g.metal-24xl": 6.283200, + "us-west-1|r8g.metal-48xl": 12.566400, + "us-west-1|r8g.xlarge": 0.261800, + "us-west-1|r8i-flex.12xlarge": 3.519120, + "us-west-1|r8i-flex.16xlarge": 4.692160, + "us-west-1|r8i-flex.2xlarge": 0.586520, + "us-west-1|r8i-flex.4xlarge": 1.173040, + "us-west-1|r8i-flex.8xlarge": 2.346080, + "us-west-1|r8i-flex.large": 0.146630, + "us-west-1|r8i-flex.xlarge": 0.293260, + "us-west-1|r8i.12xlarge": 3.704400, + "us-west-1|r8i.16xlarge": 4.939200, + "us-west-1|r8i.24xlarge": 7.408800, + "us-west-1|r8i.2xlarge": 0.617400, + "us-west-1|r8i.32xlarge": 9.878400, + "us-west-1|r8i.48xlarge": 14.817600, + "us-west-1|r8i.4xlarge": 1.234800, + "us-west-1|r8i.8xlarge": 2.469600, + "us-west-1|r8i.96xlarge": 29.635200, + "us-west-1|r8i.large": 0.154350, + "us-west-1|r8i.metal-48xl": 14.817600, + "us-west-1|r8i.metal-96xl": 29.635200, + "us-west-1|r8i.xlarge": 0.308700, + "us-west-1|t1.micro": 0.025000, + "us-west-1|t2.2xlarge": 0.441600, + "us-west-1|t2.large": 0.110400, + "us-west-1|t2.medium": 0.055200, + "us-west-1|t2.micro": 0.013800, + "us-west-1|t2.nano": 0.006900, + "us-west-1|t2.small": 0.027600, + "us-west-1|t2.xlarge": 0.220800, + "us-west-1|t3.2xlarge": 0.396800, + "us-west-1|t3.large": 0.099200, + "us-west-1|t3.medium": 0.049600, + "us-west-1|t3.micro": 0.012400, + "us-west-1|t3.nano": 0.006200, + "us-west-1|t3.small": 0.024800, + "us-west-1|t3.xlarge": 0.198400, + "us-west-1|t3a.2xlarge": 0.357100, + "us-west-1|t3a.large": 0.089300, + "us-west-1|t3a.medium": 0.044600, + "us-west-1|t3a.micro": 0.011200, + "us-west-1|t3a.nano": 0.005600, + "us-west-1|t3a.small": 0.022300, + "us-west-1|t3a.xlarge": 0.178600, + "us-west-1|t4g.2xlarge": 0.320000, + "us-west-1|t4g.large": 0.080000, + "us-west-1|t4g.medium": 0.040000, + "us-west-1|t4g.micro": 0.010000, + "us-west-1|t4g.nano": 0.005000, + "us-west-1|t4g.small": 0.020000, + "us-west-1|t4g.xlarge": 0.160000, + "us-west-1|x2idn.16xlarge": 8.670000, + "us-west-1|x2idn.24xlarge": 13.005000, + "us-west-1|x2idn.32xlarge": 17.340000, + "us-west-1|x2idn.metal": 17.340000, + "us-west-1|x2iedn.16xlarge": 17.340000, + "us-west-1|x2iedn.24xlarge": 26.010000, + "us-west-1|x2iedn.2xlarge": 2.167500, + "us-west-1|x2iedn.32xlarge": 34.680000, + "us-west-1|x2iedn.4xlarge": 4.335000, + "us-west-1|x2iedn.8xlarge": 8.670000, + "us-west-1|x2iedn.metal": 34.680000, + "us-west-1|x2iedn.xlarge": 1.083750, + "us-west-1|z1d.12xlarge": 5.064000, + "us-west-1|z1d.2xlarge": 0.844000, + "us-west-1|z1d.3xlarge": 1.266000, + "us-west-1|z1d.6xlarge": 2.532000, + "us-west-1|z1d.large": 0.211000, + "us-west-1|z1d.metal": 5.064000, + "us-west-1|z1d.xlarge": 0.422000, + "us-west-2|a1.2xlarge": 0.204000, + "us-west-2|a1.4xlarge": 0.408000, + "us-west-2|a1.large": 0.051000, + "us-west-2|a1.medium": 0.025500, + "us-west-2|a1.metal": 0.408000, + "us-west-2|a1.xlarge": 0.102000, + "us-west-2|c1.medium": 0.130000, + "us-west-2|c1.xlarge": 0.520000, + "us-west-2|c3.2xlarge": 0.420000, + "us-west-2|c3.4xlarge": 0.840000, + "us-west-2|c3.8xlarge": 1.680000, + "us-west-2|c3.large": 0.105000, + "us-west-2|c3.xlarge": 0.210000, + "us-west-2|c4.2xlarge": 0.398000, + "us-west-2|c4.4xlarge": 0.796000, + "us-west-2|c4.8xlarge": 1.591000, + "us-west-2|c4.large": 0.100000, + "us-west-2|c4.xlarge": 0.199000, + "us-west-2|c5.12xlarge": 2.040000, + "us-west-2|c5.18xlarge": 3.060000, + "us-west-2|c5.24xlarge": 4.080000, + "us-west-2|c5.2xlarge": 0.340000, + "us-west-2|c5.4xlarge": 0.680000, + "us-west-2|c5.9xlarge": 1.530000, + "us-west-2|c5.large": 0.085000, + "us-west-2|c5.metal": 4.080000, + "us-west-2|c5.xlarge": 0.170000, + "us-west-2|c5a.12xlarge": 1.848000, + "us-west-2|c5a.16xlarge": 2.464000, + "us-west-2|c5a.24xlarge": 3.696000, + "us-west-2|c5a.2xlarge": 0.308000, + "us-west-2|c5a.4xlarge": 0.616000, + "us-west-2|c5a.8xlarge": 1.232000, + "us-west-2|c5a.large": 0.077000, + "us-west-2|c5a.xlarge": 0.154000, + "us-west-2|c5ad.12xlarge": 2.064000, + "us-west-2|c5ad.16xlarge": 2.752000, + "us-west-2|c5ad.24xlarge": 4.128000, + "us-west-2|c5ad.2xlarge": 0.344000, + "us-west-2|c5ad.4xlarge": 0.688000, + "us-west-2|c5ad.8xlarge": 1.376000, + "us-west-2|c5ad.large": 0.086000, + "us-west-2|c5ad.xlarge": 0.172000, + "us-west-2|c5d.12xlarge": 2.304000, + "us-west-2|c5d.18xlarge": 3.456000, + "us-west-2|c5d.24xlarge": 4.608000, + "us-west-2|c5d.2xlarge": 0.384000, + "us-west-2|c5d.4xlarge": 0.768000, + "us-west-2|c5d.9xlarge": 1.728000, + "us-west-2|c5d.large": 0.096000, + "us-west-2|c5d.metal": 4.608000, + "us-west-2|c5d.xlarge": 0.192000, + "us-west-2|c5n.18xlarge": 3.888000, + "us-west-2|c5n.2xlarge": 0.432000, + "us-west-2|c5n.4xlarge": 0.864000, + "us-west-2|c5n.9xlarge": 1.944000, + "us-west-2|c5n.large": 0.108000, + "us-west-2|c5n.metal": 3.888000, + "us-west-2|c5n.xlarge": 0.216000, + "us-west-2|c6a.12xlarge": 1.836000, + "us-west-2|c6a.16xlarge": 2.448000, + "us-west-2|c6a.24xlarge": 3.672000, + "us-west-2|c6a.2xlarge": 0.306000, + "us-west-2|c6a.32xlarge": 4.896000, + "us-west-2|c6a.48xlarge": 7.344000, + "us-west-2|c6a.4xlarge": 0.612000, + "us-west-2|c6a.8xlarge": 1.224000, + "us-west-2|c6a.large": 0.076500, + "us-west-2|c6a.metal": 7.344000, + "us-west-2|c6a.xlarge": 0.153000, + "us-west-2|c6g.12xlarge": 1.632000, + "us-west-2|c6g.16xlarge": 2.176000, + "us-west-2|c6g.2xlarge": 0.272000, + "us-west-2|c6g.4xlarge": 0.544000, + "us-west-2|c6g.8xlarge": 1.088000, + "us-west-2|c6g.large": 0.068000, + "us-west-2|c6g.medium": 0.034000, + "us-west-2|c6g.metal": 2.176000, + "us-west-2|c6g.xlarge": 0.136000, + "us-west-2|c6gd.12xlarge": 1.843200, + "us-west-2|c6gd.16xlarge": 2.457600, + "us-west-2|c6gd.2xlarge": 0.307200, + "us-west-2|c6gd.4xlarge": 0.614400, + "us-west-2|c6gd.8xlarge": 1.228800, + "us-west-2|c6gd.large": 0.076800, + "us-west-2|c6gd.medium": 0.038400, + "us-west-2|c6gd.metal": 2.457600, + "us-west-2|c6gd.xlarge": 0.153600, + "us-west-2|c6gn.12xlarge": 2.073600, + "us-west-2|c6gn.16xlarge": 2.764800, + "us-west-2|c6gn.2xlarge": 0.345600, + "us-west-2|c6gn.4xlarge": 0.691200, + "us-west-2|c6gn.8xlarge": 1.382400, + "us-west-2|c6gn.large": 0.086400, + "us-west-2|c6gn.medium": 0.043200, + "us-west-2|c6gn.xlarge": 0.172800, + "us-west-2|c6i.12xlarge": 2.040000, + "us-west-2|c6i.16xlarge": 2.720000, + "us-west-2|c6i.24xlarge": 4.080000, + "us-west-2|c6i.2xlarge": 0.340000, + "us-west-2|c6i.32xlarge": 5.440000, + "us-west-2|c6i.4xlarge": 0.680000, + "us-west-2|c6i.8xlarge": 1.360000, + "us-west-2|c6i.large": 0.085000, + "us-west-2|c6i.metal": 5.440000, + "us-west-2|c6i.xlarge": 0.170000, + "us-west-2|c6id.12xlarge": 2.419200, + "us-west-2|c6id.16xlarge": 3.225600, + "us-west-2|c6id.24xlarge": 4.838400, + "us-west-2|c6id.2xlarge": 0.403200, + "us-west-2|c6id.32xlarge": 6.451200, + "us-west-2|c6id.4xlarge": 0.806400, + "us-west-2|c6id.8xlarge": 1.612800, + "us-west-2|c6id.large": 0.100800, + "us-west-2|c6id.metal": 6.451200, + "us-west-2|c6id.xlarge": 0.201600, + "us-west-2|c6in.12xlarge": 2.721600, + "us-west-2|c6in.16xlarge": 3.628800, + "us-west-2|c6in.24xlarge": 5.443200, + "us-west-2|c6in.2xlarge": 0.453600, + "us-west-2|c6in.32xlarge": 7.257600, + "us-west-2|c6in.4xlarge": 0.907200, + "us-west-2|c6in.8xlarge": 1.814400, + "us-west-2|c6in.large": 0.113400, + "us-west-2|c6in.metal": 7.257600, + "us-west-2|c6in.xlarge": 0.226800, + "us-west-2|c7a.12xlarge": 2.463360, + "us-west-2|c7a.16xlarge": 3.284480, + "us-west-2|c7a.24xlarge": 4.926720, + "us-west-2|c7a.2xlarge": 0.410560, + "us-west-2|c7a.32xlarge": 6.568960, + "us-west-2|c7a.48xlarge": 9.853440, + "us-west-2|c7a.4xlarge": 0.821120, + "us-west-2|c7a.8xlarge": 1.642240, + "us-west-2|c7a.large": 0.102640, + "us-west-2|c7a.medium": 0.051320, + "us-west-2|c7a.metal-48xl": 9.853440, + "us-west-2|c7a.xlarge": 0.205280, + "us-west-2|c7g.12xlarge": 1.740000, + "us-west-2|c7g.16xlarge": 2.320000, + "us-west-2|c7g.2xlarge": 0.290000, + "us-west-2|c7g.4xlarge": 0.580000, + "us-west-2|c7g.8xlarge": 1.160000, + "us-west-2|c7g.large": 0.072500, + "us-west-2|c7g.medium": 0.036300, + "us-west-2|c7g.metal": 2.320000, + "us-west-2|c7g.xlarge": 0.145000, + "us-west-2|c7gd.12xlarge": 2.177300, + "us-west-2|c7gd.16xlarge": 2.903000, + "us-west-2|c7gd.2xlarge": 0.362900, + "us-west-2|c7gd.4xlarge": 0.725800, + "us-west-2|c7gd.8xlarge": 1.451500, + "us-west-2|c7gd.large": 0.090700, + "us-west-2|c7gd.medium": 0.045400, + "us-west-2|c7gd.metal": 2.903000, + "us-west-2|c7gd.xlarge": 0.181400, + "us-west-2|c7gn.12xlarge": 2.995200, + "us-west-2|c7gn.16xlarge": 3.993600, + "us-west-2|c7gn.2xlarge": 0.499200, + "us-west-2|c7gn.4xlarge": 0.998400, + "us-west-2|c7gn.8xlarge": 1.996800, + "us-west-2|c7gn.large": 0.124800, + "us-west-2|c7gn.medium": 0.062400, + "us-west-2|c7gn.metal": 3.993600, + "us-west-2|c7gn.xlarge": 0.249600, + "us-west-2|c7i-flex.12xlarge": 2.034900, + "us-west-2|c7i-flex.16xlarge": 2.713200, + "us-west-2|c7i-flex.2xlarge": 0.339150, + "us-west-2|c7i-flex.4xlarge": 0.678300, + "us-west-2|c7i-flex.8xlarge": 1.356600, + "us-west-2|c7i-flex.large": 0.084790, + "us-west-2|c7i-flex.xlarge": 0.169580, + "us-west-2|c7i.12xlarge": 2.142000, + "us-west-2|c7i.16xlarge": 2.856000, + "us-west-2|c7i.24xlarge": 4.284000, + "us-west-2|c7i.2xlarge": 0.357000, + "us-west-2|c7i.48xlarge": 8.568000, + "us-west-2|c7i.4xlarge": 0.714000, + "us-west-2|c7i.8xlarge": 1.428000, + "us-west-2|c7i.large": 0.089250, + "us-west-2|c7i.metal-24xl": 4.284000, + "us-west-2|c7i.metal-48xl": 8.568000, + "us-west-2|c7i.xlarge": 0.178500, + "us-west-2|c8a.12xlarge": 2.586480, + "us-west-2|c8a.16xlarge": 3.448640, + "us-west-2|c8a.24xlarge": 5.172960, + "us-west-2|c8a.2xlarge": 0.431080, + "us-west-2|c8a.48xlarge": 10.345920, + "us-west-2|c8a.4xlarge": 0.862160, + "us-west-2|c8a.8xlarge": 1.724320, + "us-west-2|c8a.large": 0.107770, + "us-west-2|c8a.medium": 0.053890, + "us-west-2|c8a.metal-24xl": 5.172960, + "us-west-2|c8a.metal-48xl": 10.345920, + "us-west-2|c8a.xlarge": 0.215540, + "us-west-2|c8g.12xlarge": 1.914240, + "us-west-2|c8g.16xlarge": 2.552320, + "us-west-2|c8g.24xlarge": 3.828480, + "us-west-2|c8g.2xlarge": 0.319040, + "us-west-2|c8g.48xlarge": 7.656960, + "us-west-2|c8g.4xlarge": 0.638080, + "us-west-2|c8g.8xlarge": 1.276160, + "us-west-2|c8g.large": 0.079760, + "us-west-2|c8g.medium": 0.039880, + "us-west-2|c8g.metal-24xl": 3.828480, + "us-west-2|c8g.metal-48xl": 7.656960, + "us-west-2|c8g.xlarge": 0.159520, + "us-west-2|c8gb.12xlarge": 2.844000, + "us-west-2|c8gb.16xlarge": 3.792000, + "us-west-2|c8gb.24xlarge": 5.688000, + "us-west-2|c8gb.2xlarge": 0.474000, + "us-west-2|c8gb.4xlarge": 0.948000, + "us-west-2|c8gb.8xlarge": 1.896000, + "us-west-2|c8gb.large": 0.118500, + "us-west-2|c8gb.medium": 0.059250, + "us-west-2|c8gb.xlarge": 0.237000, + "us-west-2|c8gd.12xlarge": 2.351520, + "us-west-2|c8gd.16xlarge": 3.135360, + "us-west-2|c8gd.24xlarge": 4.703040, + "us-west-2|c8gd.2xlarge": 0.391920, + "us-west-2|c8gd.48xlarge": 9.406080, + "us-west-2|c8gd.4xlarge": 0.783840, + "us-west-2|c8gd.8xlarge": 1.567680, + "us-west-2|c8gd.large": 0.097980, + "us-west-2|c8gd.medium": 0.048990, + "us-west-2|c8gd.metal-24xl": 4.703040, + "us-west-2|c8gd.metal-48xl": 9.406080, + "us-west-2|c8gd.xlarge": 0.195960, + "us-west-2|c8gn.12xlarge": 2.844000, + "us-west-2|c8gn.16xlarge": 3.792000, + "us-west-2|c8gn.24xlarge": 5.688000, + "us-west-2|c8gn.2xlarge": 0.474000, + "us-west-2|c8gn.48xlarge": 11.376000, + "us-west-2|c8gn.4xlarge": 0.948000, + "us-west-2|c8gn.8xlarge": 1.896000, + "us-west-2|c8gn.large": 0.118500, + "us-west-2|c8gn.medium": 0.059300, + "us-west-2|c8gn.xlarge": 0.237000, + "us-west-2|c8i-flex.12xlarge": 2.136480, + "us-west-2|c8i-flex.16xlarge": 2.848640, + "us-west-2|c8i-flex.2xlarge": 0.356080, + "us-west-2|c8i-flex.4xlarge": 0.712160, + "us-west-2|c8i-flex.8xlarge": 1.424320, + "us-west-2|c8i-flex.large": 0.089020, + "us-west-2|c8i-flex.xlarge": 0.178040, + "us-west-2|c8i.12xlarge": 2.249040, + "us-west-2|c8i.16xlarge": 2.998720, + "us-west-2|c8i.24xlarge": 4.498080, + "us-west-2|c8i.2xlarge": 0.374840, + "us-west-2|c8i.32xlarge": 5.997440, + "us-west-2|c8i.48xlarge": 8.996160, + "us-west-2|c8i.4xlarge": 0.749680, + "us-west-2|c8i.8xlarge": 1.499360, + "us-west-2|c8i.96xlarge": 17.992320, + "us-west-2|c8i.large": 0.093710, + "us-west-2|c8i.metal-48xl": 8.996160, + "us-west-2|c8i.metal-96xl": 17.992320, + "us-west-2|c8i.xlarge": 0.187420, + "us-west-2|cr1.8xlarge": 3.500000, + "us-west-2|d2.2xlarge": 1.380000, + "us-west-2|d2.4xlarge": 2.760000, + "us-west-2|d2.8xlarge": 5.520000, + "us-west-2|d2.xlarge": 0.690000, + "us-west-2|d3.2xlarge": 0.999000, + "us-west-2|d3.4xlarge": 1.998000, + "us-west-2|d3.8xlarge": 3.995520, + "us-west-2|d3.xlarge": 0.499000, + "us-west-2|d3en.12xlarge": 6.308640, + "us-west-2|d3en.2xlarge": 1.051000, + "us-west-2|d3en.4xlarge": 2.103000, + "us-west-2|d3en.6xlarge": 3.154000, + "us-west-2|d3en.8xlarge": 4.205760, + "us-west-2|d3en.xlarge": 0.526000, + "us-west-2|dl1.24xlarge": 13.109040, + "us-west-2|dl2q.24xlarge": 8.919400, + "us-west-2|f1.16xlarge": 13.200000, + "us-west-2|f1.2xlarge": 1.650000, + "us-west-2|f1.4xlarge": 3.300000, + "us-west-2|f2.12xlarge": 3.960000, + "us-west-2|f2.48xlarge": 15.840000, + "us-west-2|f2.6xlarge": 1.980000, + "us-west-2|g2.2xlarge": 0.650000, + "us-west-2|g2.8xlarge": 2.600000, + "us-west-2|g3.16xlarge": 4.560000, + "us-west-2|g3.4xlarge": 1.140000, + "us-west-2|g3.8xlarge": 2.280000, + "us-west-2|g3s.xlarge": 0.750000, + "us-west-2|g4ad.16xlarge": 3.468000, + "us-west-2|g4ad.2xlarge": 0.541170, + "us-west-2|g4ad.4xlarge": 0.867000, + "us-west-2|g4ad.8xlarge": 1.734000, + "us-west-2|g4ad.xlarge": 0.378530, + "us-west-2|g4dn.12xlarge": 3.912000, + "us-west-2|g4dn.16xlarge": 4.352000, + "us-west-2|g4dn.2xlarge": 0.752000, + "us-west-2|g4dn.4xlarge": 1.204000, + "us-west-2|g4dn.8xlarge": 2.176000, + "us-west-2|g4dn.metal": 7.824000, + "us-west-2|g4dn.xlarge": 0.526000, + "us-west-2|g5.12xlarge": 5.672000, + "us-west-2|g5.16xlarge": 4.096000, + "us-west-2|g5.24xlarge": 8.144000, + "us-west-2|g5.2xlarge": 1.212000, + "us-west-2|g5.48xlarge": 16.288000, + "us-west-2|g5.4xlarge": 1.624000, + "us-west-2|g5.8xlarge": 2.448000, + "us-west-2|g5.xlarge": 1.006000, + "us-west-2|g5g.16xlarge": 2.744000, + "us-west-2|g5g.2xlarge": 0.556000, + "us-west-2|g5g.4xlarge": 0.828000, + "us-west-2|g5g.8xlarge": 1.372000, + "us-west-2|g5g.metal": 2.744000, + "us-west-2|g5g.xlarge": 0.420000, + "us-west-2|g6.12xlarge": 4.601600, + "us-west-2|g6.16xlarge": 3.396800, + "us-west-2|g6.24xlarge": 6.675200, + "us-west-2|g6.2xlarge": 0.977600, + "us-west-2|g6.48xlarge": 13.350400, + "us-west-2|g6.4xlarge": 1.323200, + "us-west-2|g6.8xlarge": 2.014400, + "us-west-2|g6.xlarge": 0.804800, + "us-west-2|g6e.12xlarge": 10.492640, + "us-west-2|g6e.16xlarge": 7.577190, + "us-west-2|g6e.24xlarge": 15.065590, + "us-west-2|g6e.2xlarge": 2.242080, + "us-west-2|g6e.48xlarge": 30.131180, + "us-west-2|g6e.4xlarge": 3.004240, + "us-west-2|g6e.8xlarge": 4.528560, + "us-west-2|g6e.xlarge": 1.861000, + "us-west-2|g6f.2xlarge": 0.475000, + "us-west-2|g6f.4xlarge": 0.950000, + "us-west-2|g6f.large": 0.202000, + "us-west-2|g6f.xlarge": 0.237500, + "us-west-2|gr6.4xlarge": 1.539200, + "us-west-2|gr6.8xlarge": 2.446400, + "us-west-2|gr6f.4xlarge": 1.066000, + "us-west-2|h1.16xlarge": 3.744000, + "us-west-2|h1.2xlarge": 0.468000, + "us-west-2|h1.4xlarge": 0.936000, + "us-west-2|h1.8xlarge": 1.872000, + "us-west-2|i2.2xlarge": 1.705000, + "us-west-2|i2.4xlarge": 3.410000, + "us-west-2|i2.8xlarge": 6.820000, + "us-west-2|i2.xlarge": 0.853000, + "us-west-2|i3.16xlarge": 4.992000, + "us-west-2|i3.2xlarge": 0.624000, + "us-west-2|i3.4xlarge": 1.248000, + "us-west-2|i3.8xlarge": 2.496000, + "us-west-2|i3.large": 0.156000, + "us-west-2|i3.metal": 4.992000, + "us-west-2|i3.xlarge": 0.312000, + "us-west-2|i3en.12xlarge": 5.424000, + "us-west-2|i3en.24xlarge": 10.848000, + "us-west-2|i3en.2xlarge": 0.904000, + "us-west-2|i3en.3xlarge": 1.356000, + "us-west-2|i3en.6xlarge": 2.712000, + "us-west-2|i3en.large": 0.226000, + "us-west-2|i3en.metal": 10.848000, + "us-west-2|i3en.xlarge": 0.452000, + "us-west-2|i4g.16xlarge": 4.942080, + "us-west-2|i4g.2xlarge": 0.617760, + "us-west-2|i4g.4xlarge": 1.235520, + "us-west-2|i4g.8xlarge": 2.471040, + "us-west-2|i4g.large": 0.154440, + "us-west-2|i4g.xlarge": 0.308880, + "us-west-2|i4i.12xlarge": 4.118000, + "us-west-2|i4i.16xlarge": 5.491000, + "us-west-2|i4i.24xlarge": 8.236800, + "us-west-2|i4i.2xlarge": 0.686000, + "us-west-2|i4i.32xlarge": 10.982400, + "us-west-2|i4i.4xlarge": 1.373000, + "us-west-2|i4i.8xlarge": 2.746000, + "us-west-2|i4i.large": 0.172000, + "us-west-2|i4i.metal": 10.982000, + "us-west-2|i4i.xlarge": 0.343000, + "us-west-2|i7i.12xlarge": 4.530200, + "us-west-2|i7i.16xlarge": 6.040300, + "us-west-2|i7i.24xlarge": 9.060500, + "us-west-2|i7i.2xlarge": 0.755000, + "us-west-2|i7i.48xlarge": 18.121000, + "us-west-2|i7i.4xlarge": 1.510100, + "us-west-2|i7i.8xlarge": 3.020200, + "us-west-2|i7i.large": 0.188800, + "us-west-2|i7i.metal-24xl": 9.060500, + "us-west-2|i7i.metal-48xl": 18.121000, + "us-west-2|i7i.xlarge": 0.377500, + "us-west-2|i7ie.12xlarge": 6.237600, + "us-west-2|i7ie.18xlarge": 9.356400, + "us-west-2|i7ie.24xlarge": 12.475200, + "us-west-2|i7ie.2xlarge": 1.039600, + "us-west-2|i7ie.3xlarge": 1.559400, + "us-west-2|i7ie.48xlarge": 24.950400, + "us-west-2|i7ie.6xlarge": 3.118800, + "us-west-2|i7ie.large": 0.259900, + "us-west-2|i7ie.metal-24xl": 12.475200, + "us-west-2|i7ie.metal-48xl": 24.950400, + "us-west-2|i7ie.xlarge": 0.519800, + "us-west-2|i8g.12xlarge": 4.118400, + "us-west-2|i8g.16xlarge": 5.491200, + "us-west-2|i8g.24xlarge": 8.236800, + "us-west-2|i8g.2xlarge": 0.686400, + "us-west-2|i8g.48xlarge": 16.473600, + "us-west-2|i8g.4xlarge": 1.372800, + "us-west-2|i8g.8xlarge": 2.745600, + "us-west-2|i8g.large": 0.171600, + "us-west-2|i8g.metal-24xl": 8.236800, + "us-west-2|i8g.xlarge": 0.343200, + "us-west-2|i8ge.12xlarge": 5.695200, + "us-west-2|i8ge.18xlarge": 8.542800, + "us-west-2|i8ge.24xlarge": 11.390400, + "us-west-2|i8ge.2xlarge": 0.949200, + "us-west-2|i8ge.3xlarge": 1.423800, + "us-west-2|i8ge.48xlarge": 22.780800, + "us-west-2|i8ge.6xlarge": 2.847600, + "us-west-2|i8ge.large": 0.237300, + "us-west-2|i8ge.metal-24xl": 11.390400, + "us-west-2|i8ge.metal-48xl": 22.780800, + "us-west-2|i8ge.xlarge": 0.474600, + "us-west-2|im4gn.16xlarge": 5.820670, + "us-west-2|im4gn.2xlarge": 0.727580, + "us-west-2|im4gn.4xlarge": 1.455170, + "us-west-2|im4gn.8xlarge": 2.910340, + "us-west-2|im4gn.large": 0.181900, + "us-west-2|im4gn.xlarge": 0.363790, + "us-west-2|inf1.24xlarge": 4.721000, + "us-west-2|inf1.2xlarge": 0.362000, + "us-west-2|inf1.6xlarge": 1.180000, + "us-west-2|inf1.xlarge": 0.228000, + "us-west-2|inf2.24xlarge": 6.490630, + "us-west-2|inf2.48xlarge": 12.981270, + "us-west-2|inf2.8xlarge": 1.967860, + "us-west-2|inf2.xlarge": 0.758200, + "us-west-2|is4gen.2xlarge": 1.152600, + "us-west-2|is4gen.4xlarge": 2.305200, + "us-west-2|is4gen.8xlarge": 4.610400, + "us-west-2|is4gen.large": 0.288150, + "us-west-2|is4gen.medium": 0.144080, + "us-west-2|is4gen.xlarge": 0.576300, + "us-west-2|m1.large": 0.175000, + "us-west-2|m1.medium": 0.087000, + "us-west-2|m1.small": 0.044000, + "us-west-2|m1.xlarge": 0.350000, + "us-west-2|m2.2xlarge": 0.490000, + "us-west-2|m2.4xlarge": 0.980000, + "us-west-2|m2.xlarge": 0.245000, + "us-west-2|m3.2xlarge": 0.532000, + "us-west-2|m3.large": 0.133000, + "us-west-2|m3.medium": 0.067000, + "us-west-2|m3.xlarge": 0.266000, + "us-west-2|m4.10xlarge": 2.000000, + "us-west-2|m4.16xlarge": 3.200000, + "us-west-2|m4.2xlarge": 0.400000, + "us-west-2|m4.4xlarge": 0.800000, + "us-west-2|m4.large": 0.100000, + "us-west-2|m4.xlarge": 0.200000, + "us-west-2|m5.12xlarge": 2.304000, + "us-west-2|m5.16xlarge": 3.072000, + "us-west-2|m5.24xlarge": 4.608000, + "us-west-2|m5.2xlarge": 0.384000, + "us-west-2|m5.4xlarge": 0.768000, + "us-west-2|m5.8xlarge": 1.536000, + "us-west-2|m5.large": 0.096000, + "us-west-2|m5.metal": 4.608000, + "us-west-2|m5.xlarge": 0.192000, + "us-west-2|m5a.12xlarge": 2.064000, + "us-west-2|m5a.16xlarge": 2.752000, + "us-west-2|m5a.24xlarge": 4.128000, + "us-west-2|m5a.2xlarge": 0.344000, + "us-west-2|m5a.4xlarge": 0.688000, + "us-west-2|m5a.8xlarge": 1.376000, + "us-west-2|m5a.large": 0.086000, + "us-west-2|m5a.xlarge": 0.172000, + "us-west-2|m5ad.12xlarge": 2.472000, + "us-west-2|m5ad.16xlarge": 3.296000, + "us-west-2|m5ad.24xlarge": 4.944000, + "us-west-2|m5ad.2xlarge": 0.412000, + "us-west-2|m5ad.4xlarge": 0.824000, + "us-west-2|m5ad.8xlarge": 1.648000, + "us-west-2|m5ad.large": 0.103000, + "us-west-2|m5ad.xlarge": 0.206000, + "us-west-2|m5d.12xlarge": 2.712000, + "us-west-2|m5d.16xlarge": 3.616000, + "us-west-2|m5d.24xlarge": 5.424000, + "us-west-2|m5d.2xlarge": 0.452000, + "us-west-2|m5d.4xlarge": 0.904000, + "us-west-2|m5d.8xlarge": 1.808000, + "us-west-2|m5d.large": 0.113000, + "us-west-2|m5d.metal": 5.424000, + "us-west-2|m5d.xlarge": 0.226000, + "us-west-2|m5dn.12xlarge": 3.264000, + "us-west-2|m5dn.16xlarge": 4.352000, + "us-west-2|m5dn.24xlarge": 6.528000, + "us-west-2|m5dn.2xlarge": 0.544000, + "us-west-2|m5dn.4xlarge": 1.088000, + "us-west-2|m5dn.8xlarge": 2.176000, + "us-west-2|m5dn.large": 0.136000, + "us-west-2|m5dn.metal": 6.528000, + "us-west-2|m5dn.xlarge": 0.272000, + "us-west-2|m5n.12xlarge": 2.856000, + "us-west-2|m5n.16xlarge": 3.808000, + "us-west-2|m5n.24xlarge": 5.712000, + "us-west-2|m5n.2xlarge": 0.476000, + "us-west-2|m5n.4xlarge": 0.952000, + "us-west-2|m5n.8xlarge": 1.904000, + "us-west-2|m5n.large": 0.119000, + "us-west-2|m5n.metal": 5.712000, + "us-west-2|m5n.xlarge": 0.238000, + "us-west-2|m5zn.12xlarge": 3.964100, + "us-west-2|m5zn.2xlarge": 0.660700, + "us-west-2|m5zn.3xlarge": 0.991000, + "us-west-2|m5zn.6xlarge": 1.982000, + "us-west-2|m5zn.large": 0.165200, + "us-west-2|m5zn.metal": 3.964100, + "us-west-2|m5zn.xlarge": 0.330300, + "us-west-2|m6a.12xlarge": 2.073600, + "us-west-2|m6a.16xlarge": 2.764800, + "us-west-2|m6a.24xlarge": 4.147200, + "us-west-2|m6a.2xlarge": 0.345600, + "us-west-2|m6a.32xlarge": 5.529600, + "us-west-2|m6a.48xlarge": 8.294400, + "us-west-2|m6a.4xlarge": 0.691200, + "us-west-2|m6a.8xlarge": 1.382400, + "us-west-2|m6a.large": 0.086400, + "us-west-2|m6a.metal": 8.294400, + "us-west-2|m6a.xlarge": 0.172800, + "us-west-2|m6g.12xlarge": 1.848000, + "us-west-2|m6g.16xlarge": 2.464000, + "us-west-2|m6g.2xlarge": 0.308000, + "us-west-2|m6g.4xlarge": 0.616000, + "us-west-2|m6g.8xlarge": 1.232000, + "us-west-2|m6g.large": 0.077000, + "us-west-2|m6g.medium": 0.038500, + "us-west-2|m6g.metal": 2.464000, + "us-west-2|m6g.xlarge": 0.154000, + "us-west-2|m6gd.12xlarge": 2.169600, + "us-west-2|m6gd.16xlarge": 2.892800, + "us-west-2|m6gd.2xlarge": 0.361600, + "us-west-2|m6gd.4xlarge": 0.723200, + "us-west-2|m6gd.8xlarge": 1.446400, + "us-west-2|m6gd.large": 0.090400, + "us-west-2|m6gd.medium": 0.045200, + "us-west-2|m6gd.metal": 2.892800, + "us-west-2|m6gd.xlarge": 0.180800, + "us-west-2|m6i.12xlarge": 2.304000, + "us-west-2|m6i.16xlarge": 3.072000, + "us-west-2|m6i.24xlarge": 4.608000, + "us-west-2|m6i.2xlarge": 0.384000, + "us-west-2|m6i.32xlarge": 6.144000, + "us-west-2|m6i.4xlarge": 0.768000, + "us-west-2|m6i.8xlarge": 1.536000, + "us-west-2|m6i.large": 0.096000, + "us-west-2|m6i.metal": 6.144000, + "us-west-2|m6i.xlarge": 0.192000, + "us-west-2|m6id.12xlarge": 2.847600, + "us-west-2|m6id.16xlarge": 3.796800, + "us-west-2|m6id.24xlarge": 5.695200, + "us-west-2|m6id.2xlarge": 0.474600, + "us-west-2|m6id.32xlarge": 7.593600, + "us-west-2|m6id.4xlarge": 0.949200, + "us-west-2|m6id.8xlarge": 1.898400, + "us-west-2|m6id.large": 0.118650, + "us-west-2|m6id.metal": 7.593600, + "us-west-2|m6id.xlarge": 0.237300, + "us-west-2|m6idn.12xlarge": 3.818880, + "us-west-2|m6idn.16xlarge": 5.091840, + "us-west-2|m6idn.24xlarge": 7.637760, + "us-west-2|m6idn.2xlarge": 0.636480, + "us-west-2|m6idn.32xlarge": 10.183680, + "us-west-2|m6idn.4xlarge": 1.272960, + "us-west-2|m6idn.8xlarge": 2.545920, + "us-west-2|m6idn.large": 0.159120, + "us-west-2|m6idn.metal": 10.183680, + "us-west-2|m6idn.xlarge": 0.318240, + "us-west-2|m6in.12xlarge": 3.341520, + "us-west-2|m6in.16xlarge": 4.455360, + "us-west-2|m6in.24xlarge": 6.683040, + "us-west-2|m6in.2xlarge": 0.556920, + "us-west-2|m6in.32xlarge": 8.910720, + "us-west-2|m6in.4xlarge": 1.113840, + "us-west-2|m6in.8xlarge": 2.227680, + "us-west-2|m6in.large": 0.139230, + "us-west-2|m6in.metal": 8.910720, + "us-west-2|m6in.xlarge": 0.278460, + "us-west-2|m7a.12xlarge": 2.782080, + "us-west-2|m7a.16xlarge": 3.709440, + "us-west-2|m7a.24xlarge": 5.564160, + "us-west-2|m7a.2xlarge": 0.463680, + "us-west-2|m7a.32xlarge": 7.418880, + "us-west-2|m7a.48xlarge": 11.128320, + "us-west-2|m7a.4xlarge": 0.927360, + "us-west-2|m7a.8xlarge": 1.854720, + "us-west-2|m7a.large": 0.115920, + "us-west-2|m7a.medium": 0.057960, + "us-west-2|m7a.metal-48xl": 11.128320, + "us-west-2|m7a.xlarge": 0.231840, + "us-west-2|m7g.12xlarge": 1.958400, + "us-west-2|m7g.16xlarge": 2.611200, + "us-west-2|m7g.2xlarge": 0.326400, + "us-west-2|m7g.4xlarge": 0.652800, + "us-west-2|m7g.8xlarge": 1.305600, + "us-west-2|m7g.large": 0.081600, + "us-west-2|m7g.medium": 0.040800, + "us-west-2|m7g.metal": 2.611200, + "us-west-2|m7g.xlarge": 0.163200, + "us-west-2|m7gd.12xlarge": 2.562800, + "us-west-2|m7gd.16xlarge": 3.417100, + "us-west-2|m7gd.2xlarge": 0.427100, + "us-west-2|m7gd.4xlarge": 0.854300, + "us-west-2|m7gd.8xlarge": 1.708600, + "us-west-2|m7gd.large": 0.106800, + "us-west-2|m7gd.medium": 0.053400, + "us-west-2|m7gd.metal": 3.417100, + "us-west-2|m7gd.xlarge": 0.213600, + "us-west-2|m7i-flex.12xlarge": 2.298240, + "us-west-2|m7i-flex.16xlarge": 3.064320, + "us-west-2|m7i-flex.2xlarge": 0.383040, + "us-west-2|m7i-flex.4xlarge": 0.766080, + "us-west-2|m7i-flex.8xlarge": 1.532160, + "us-west-2|m7i-flex.large": 0.095760, + "us-west-2|m7i-flex.xlarge": 0.191520, + "us-west-2|m7i.12xlarge": 2.419200, + "us-west-2|m7i.16xlarge": 3.225600, + "us-west-2|m7i.24xlarge": 4.838400, + "us-west-2|m7i.2xlarge": 0.403200, + "us-west-2|m7i.48xlarge": 9.676800, + "us-west-2|m7i.4xlarge": 0.806400, + "us-west-2|m7i.8xlarge": 1.612800, + "us-west-2|m7i.large": 0.100800, + "us-west-2|m7i.metal-24xl": 4.838400, + "us-west-2|m7i.metal-48xl": 9.676800, + "us-west-2|m7i.xlarge": 0.201600, + "us-west-2|m8a.12xlarge": 2.921280, + "us-west-2|m8a.16xlarge": 3.895040, + "us-west-2|m8a.24xlarge": 5.842560, + "us-west-2|m8a.2xlarge": 0.486880, + "us-west-2|m8a.48xlarge": 11.685120, + "us-west-2|m8a.4xlarge": 0.973760, + "us-west-2|m8a.8xlarge": 1.947520, + "us-west-2|m8a.large": 0.121720, + "us-west-2|m8a.medium": 0.060860, + "us-west-2|m8a.metal-24xl": 5.842560, + "us-west-2|m8a.metal-48xl": 11.685120, + "us-west-2|m8a.xlarge": 0.243440, + "us-west-2|m8g.12xlarge": 2.154240, + "us-west-2|m8g.16xlarge": 2.872320, + "us-west-2|m8g.24xlarge": 4.308480, + "us-west-2|m8g.2xlarge": 0.359040, + "us-west-2|m8g.48xlarge": 8.616960, + "us-west-2|m8g.4xlarge": 0.718080, + "us-west-2|m8g.8xlarge": 1.436160, + "us-west-2|m8g.large": 0.089760, + "us-west-2|m8g.medium": 0.044880, + "us-west-2|m8g.metal-24xl": 4.308480, + "us-west-2|m8g.metal-48xl": 8.616960, + "us-west-2|m8g.xlarge": 0.179520, + "us-west-2|m8gb.12xlarge": 3.492000, + "us-west-2|m8gb.16xlarge": 4.656000, + "us-west-2|m8gb.24xlarge": 6.984000, + "us-west-2|m8gb.2xlarge": 0.582000, + "us-west-2|m8gb.4xlarge": 1.164000, + "us-west-2|m8gb.8xlarge": 2.328000, + "us-west-2|m8gb.large": 0.145500, + "us-west-2|m8gb.medium": 0.072750, + "us-west-2|m8gb.xlarge": 0.291000, + "us-west-2|m8gd.12xlarge": 2.767680, + "us-west-2|m8gd.16xlarge": 3.690240, + "us-west-2|m8gd.24xlarge": 5.535360, + "us-west-2|m8gd.2xlarge": 0.461280, + "us-west-2|m8gd.48xlarge": 11.070720, + "us-west-2|m8gd.4xlarge": 0.922560, + "us-west-2|m8gd.8xlarge": 1.845120, + "us-west-2|m8gd.large": 0.115320, + "us-west-2|m8gd.medium": 0.057660, + "us-west-2|m8gd.metal-24xl": 5.535360, + "us-west-2|m8gd.metal-48xl": 11.070720, + "us-west-2|m8gd.xlarge": 0.230640, + "us-west-2|m8gn.12xlarge": 3.492000, + "us-west-2|m8gn.16xlarge": 4.656000, + "us-west-2|m8gn.24xlarge": 6.984000, + "us-west-2|m8gn.2xlarge": 0.582000, + "us-west-2|m8gn.48xlarge": 13.968000, + "us-west-2|m8gn.4xlarge": 1.164000, + "us-west-2|m8gn.8xlarge": 2.328000, + "us-west-2|m8gn.large": 0.145500, + "us-west-2|m8gn.medium": 0.072800, + "us-west-2|m8gn.xlarge": 0.291000, + "us-west-2|m8i-flex.12xlarge": 2.413200, + "us-west-2|m8i-flex.16xlarge": 3.217600, + "us-west-2|m8i-flex.2xlarge": 0.402200, + "us-west-2|m8i-flex.4xlarge": 0.804400, + "us-west-2|m8i-flex.8xlarge": 1.608800, + "us-west-2|m8i-flex.large": 0.100550, + "us-west-2|m8i-flex.xlarge": 0.201100, + "us-west-2|m8i.12xlarge": 2.540160, + "us-west-2|m8i.16xlarge": 3.386880, + "us-west-2|m8i.24xlarge": 5.080320, + "us-west-2|m8i.2xlarge": 0.423360, + "us-west-2|m8i.32xlarge": 6.773760, + "us-west-2|m8i.48xlarge": 10.160640, + "us-west-2|m8i.4xlarge": 0.846720, + "us-west-2|m8i.8xlarge": 1.693440, + "us-west-2|m8i.96xlarge": 20.321280, + "us-west-2|m8i.large": 0.105840, + "us-west-2|m8i.metal-48xl": 10.160640, + "us-west-2|m8i.metal-96xl": 20.321280, + "us-west-2|m8i.xlarge": 0.211680, + "us-west-2|p2.16xlarge": 14.400000, + "us-west-2|p2.8xlarge": 7.200000, + "us-west-2|p2.xlarge": 0.900000, + "us-west-2|p3.16xlarge": 24.480000, + "us-west-2|p3.2xlarge": 3.060000, + "us-west-2|p3.8xlarge": 12.240000, + "us-west-2|p3dn.24xlarge": 31.212000, + "us-west-2|p4d.24xlarge": 21.957640, + "us-west-2|p4de.24xlarge": 27.447050, + "us-west-2|p5.48xlarge": 55.040000, + "us-west-2|p5.4xlarge": 6.880000, + "us-west-2|p5en.48xlarge": 63.296000, + "us-west-2|p6-b200.48xlarge": 113.932800, + "us-west-2|p6-b300.48xlarge": 142.416000, + "us-west-2|r3.2xlarge": 0.665000, + "us-west-2|r3.4xlarge": 1.330000, + "us-west-2|r3.8xlarge": 2.660000, + "us-west-2|r3.large": 0.166000, + "us-west-2|r3.xlarge": 0.333000, + "us-west-2|r4.16xlarge": 4.256000, + "us-west-2|r4.2xlarge": 0.532000, + "us-west-2|r4.4xlarge": 1.064000, + "us-west-2|r4.8xlarge": 2.128000, + "us-west-2|r4.large": 0.133000, + "us-west-2|r4.xlarge": 0.266000, + "us-west-2|r5.12xlarge": 3.024000, + "us-west-2|r5.16xlarge": 4.032000, + "us-west-2|r5.24xlarge": 6.048000, + "us-west-2|r5.2xlarge": 0.504000, + "us-west-2|r5.4xlarge": 1.008000, + "us-west-2|r5.8xlarge": 2.016000, + "us-west-2|r5.large": 0.126000, + "us-west-2|r5.metal": 6.048000, + "us-west-2|r5.xlarge": 0.252000, + "us-west-2|r5a.12xlarge": 2.712000, + "us-west-2|r5a.16xlarge": 3.616000, + "us-west-2|r5a.24xlarge": 5.424000, + "us-west-2|r5a.2xlarge": 0.452000, + "us-west-2|r5a.4xlarge": 0.904000, + "us-west-2|r5a.8xlarge": 1.808000, + "us-west-2|r5a.large": 0.113000, + "us-west-2|r5a.xlarge": 0.226000, + "us-west-2|r5ad.12xlarge": 3.144000, + "us-west-2|r5ad.16xlarge": 4.192000, + "us-west-2|r5ad.24xlarge": 6.288000, + "us-west-2|r5ad.2xlarge": 0.524000, + "us-west-2|r5ad.4xlarge": 1.048000, + "us-west-2|r5ad.8xlarge": 2.096000, + "us-west-2|r5ad.large": 0.131000, + "us-west-2|r5ad.xlarge": 0.262000, + "us-west-2|r5b.12xlarge": 3.576000, + "us-west-2|r5b.16xlarge": 4.768000, + "us-west-2|r5b.24xlarge": 7.152000, + "us-west-2|r5b.2xlarge": 0.596000, + "us-west-2|r5b.4xlarge": 1.192000, + "us-west-2|r5b.8xlarge": 2.384000, + "us-west-2|r5b.large": 0.149000, + "us-west-2|r5b.metal": 7.152000, + "us-west-2|r5b.xlarge": 0.298000, + "us-west-2|r5d.12xlarge": 3.456000, + "us-west-2|r5d.16xlarge": 4.608000, + "us-west-2|r5d.24xlarge": 6.912000, + "us-west-2|r5d.2xlarge": 0.576000, + "us-west-2|r5d.4xlarge": 1.152000, + "us-west-2|r5d.8xlarge": 2.304000, + "us-west-2|r5d.large": 0.144000, + "us-west-2|r5d.metal": 6.912000, + "us-west-2|r5d.xlarge": 0.288000, + "us-west-2|r5dn.12xlarge": 4.008000, + "us-west-2|r5dn.16xlarge": 5.344000, + "us-west-2|r5dn.24xlarge": 8.016000, + "us-west-2|r5dn.2xlarge": 0.668000, + "us-west-2|r5dn.4xlarge": 1.336000, + "us-west-2|r5dn.8xlarge": 2.672000, + "us-west-2|r5dn.large": 0.167000, + "us-west-2|r5dn.metal": 8.016000, + "us-west-2|r5dn.xlarge": 0.334000, + "us-west-2|r5n.12xlarge": 3.576000, + "us-west-2|r5n.16xlarge": 4.768000, + "us-west-2|r5n.24xlarge": 7.152000, + "us-west-2|r5n.2xlarge": 0.596000, + "us-west-2|r5n.4xlarge": 1.192000, + "us-west-2|r5n.8xlarge": 2.384000, + "us-west-2|r5n.large": 0.149000, + "us-west-2|r5n.metal": 7.152000, + "us-west-2|r5n.xlarge": 0.298000, + "us-west-2|r6a.12xlarge": 2.721600, + "us-west-2|r6a.16xlarge": 3.628800, + "us-west-2|r6a.24xlarge": 5.443200, + "us-west-2|r6a.2xlarge": 0.453600, + "us-west-2|r6a.32xlarge": 7.257600, + "us-west-2|r6a.48xlarge": 10.886400, + "us-west-2|r6a.4xlarge": 0.907200, + "us-west-2|r6a.8xlarge": 1.814400, + "us-west-2|r6a.large": 0.113400, + "us-west-2|r6a.metal": 10.886400, + "us-west-2|r6a.xlarge": 0.226800, + "us-west-2|r6g.12xlarge": 2.419200, + "us-west-2|r6g.16xlarge": 3.225600, + "us-west-2|r6g.2xlarge": 0.403200, + "us-west-2|r6g.4xlarge": 0.806400, + "us-west-2|r6g.8xlarge": 1.612800, + "us-west-2|r6g.large": 0.100800, + "us-west-2|r6g.medium": 0.050400, + "us-west-2|r6g.metal": 3.225600, + "us-west-2|r6g.xlarge": 0.201600, + "us-west-2|r6gd.12xlarge": 2.764800, + "us-west-2|r6gd.16xlarge": 3.686400, + "us-west-2|r6gd.2xlarge": 0.460800, + "us-west-2|r6gd.4xlarge": 0.921600, + "us-west-2|r6gd.8xlarge": 1.843200, + "us-west-2|r6gd.large": 0.115200, + "us-west-2|r6gd.medium": 0.057600, + "us-west-2|r6gd.metal": 3.686400, + "us-west-2|r6gd.xlarge": 0.230400, + "us-west-2|r6i.12xlarge": 3.024000, + "us-west-2|r6i.16xlarge": 4.032000, + "us-west-2|r6i.24xlarge": 6.048000, + "us-west-2|r6i.2xlarge": 0.504000, + "us-west-2|r6i.32xlarge": 8.064000, + "us-west-2|r6i.4xlarge": 1.008000, + "us-west-2|r6i.8xlarge": 2.016000, + "us-west-2|r6i.large": 0.126000, + "us-west-2|r6i.metal": 8.064000, + "us-west-2|r6i.xlarge": 0.252000, + "us-west-2|r6id.12xlarge": 3.628800, + "us-west-2|r6id.16xlarge": 4.838400, + "us-west-2|r6id.24xlarge": 7.257600, + "us-west-2|r6id.2xlarge": 0.604800, + "us-west-2|r6id.32xlarge": 9.676800, + "us-west-2|r6id.4xlarge": 1.209600, + "us-west-2|r6id.8xlarge": 2.419200, + "us-west-2|r6id.large": 0.151200, + "us-west-2|r6id.metal": 9.676800, + "us-west-2|r6id.xlarge": 0.302400, + "us-west-2|r6idn.12xlarge": 4.689360, + "us-west-2|r6idn.16xlarge": 6.252480, + "us-west-2|r6idn.24xlarge": 9.378720, + "us-west-2|r6idn.2xlarge": 0.781560, + "us-west-2|r6idn.32xlarge": 12.504960, + "us-west-2|r6idn.4xlarge": 1.563120, + "us-west-2|r6idn.8xlarge": 3.126240, + "us-west-2|r6idn.large": 0.195390, + "us-west-2|r6idn.metal": 12.504960, + "us-west-2|r6idn.xlarge": 0.390780, + "us-west-2|r6in.12xlarge": 4.183920, + "us-west-2|r6in.16xlarge": 5.578560, + "us-west-2|r6in.24xlarge": 8.367840, + "us-west-2|r6in.2xlarge": 0.697320, + "us-west-2|r6in.32xlarge": 11.157120, + "us-west-2|r6in.4xlarge": 1.394640, + "us-west-2|r6in.8xlarge": 2.789280, + "us-west-2|r6in.large": 0.174330, + "us-west-2|r6in.metal": 11.157120, + "us-west-2|r6in.xlarge": 0.348660, + "us-west-2|r7a.12xlarge": 3.651600, + "us-west-2|r7a.16xlarge": 4.868800, + "us-west-2|r7a.24xlarge": 7.303200, + "us-west-2|r7a.2xlarge": 0.608600, + "us-west-2|r7a.32xlarge": 9.737600, + "us-west-2|r7a.48xlarge": 14.606400, + "us-west-2|r7a.4xlarge": 1.217200, + "us-west-2|r7a.8xlarge": 2.434400, + "us-west-2|r7a.large": 0.152150, + "us-west-2|r7a.medium": 0.076080, + "us-west-2|r7a.metal-48xl": 14.606400, + "us-west-2|r7a.xlarge": 0.304300, + "us-west-2|r7g.12xlarge": 2.570400, + "us-west-2|r7g.16xlarge": 3.427200, + "us-west-2|r7g.2xlarge": 0.428400, + "us-west-2|r7g.4xlarge": 0.856800, + "us-west-2|r7g.8xlarge": 1.713600, + "us-west-2|r7g.large": 0.107100, + "us-west-2|r7g.medium": 0.053600, + "us-west-2|r7g.metal": 3.427200, + "us-west-2|r7g.xlarge": 0.214200, + "us-west-2|r7gd.12xlarge": 3.265900, + "us-west-2|r7gd.16xlarge": 4.354600, + "us-west-2|r7gd.2xlarge": 0.544300, + "us-west-2|r7gd.4xlarge": 1.088600, + "us-west-2|r7gd.8xlarge": 2.177300, + "us-west-2|r7gd.large": 0.136100, + "us-west-2|r7gd.medium": 0.068000, + "us-west-2|r7gd.metal": 4.354600, + "us-west-2|r7gd.xlarge": 0.272200, + "us-west-2|r7i.12xlarge": 3.175200, + "us-west-2|r7i.16xlarge": 4.233600, + "us-west-2|r7i.24xlarge": 6.350400, + "us-west-2|r7i.2xlarge": 0.529200, + "us-west-2|r7i.48xlarge": 12.700800, + "us-west-2|r7i.4xlarge": 1.058400, + "us-west-2|r7i.8xlarge": 2.116800, + "us-west-2|r7i.large": 0.132300, + "us-west-2|r7i.metal-24xl": 6.350400, + "us-west-2|r7i.metal-48xl": 12.700800, + "us-west-2|r7i.xlarge": 0.264600, + "us-west-2|r7iz.12xlarge": 4.464000, + "us-west-2|r7iz.16xlarge": 5.952000, + "us-west-2|r7iz.2xlarge": 0.744000, + "us-west-2|r7iz.32xlarge": 11.904000, + "us-west-2|r7iz.4xlarge": 1.488000, + "us-west-2|r7iz.8xlarge": 2.976000, + "us-west-2|r7iz.large": 0.186000, + "us-west-2|r7iz.metal-16xl": 5.952000, + "us-west-2|r7iz.metal-32xl": 11.904000, + "us-west-2|r7iz.xlarge": 0.372000, + "us-west-2|r8a.12xlarge": 3.834240, + "us-west-2|r8a.16xlarge": 5.112320, + "us-west-2|r8a.24xlarge": 7.668480, + "us-west-2|r8a.2xlarge": 0.639040, + "us-west-2|r8a.48xlarge": 15.336960, + "us-west-2|r8a.4xlarge": 1.278080, + "us-west-2|r8a.8xlarge": 2.556160, + "us-west-2|r8a.large": 0.159760, + "us-west-2|r8a.medium": 0.079880, + "us-west-2|r8a.metal-24xl": 7.668480, + "us-west-2|r8a.metal-48xl": 15.336960, + "us-west-2|r8a.xlarge": 0.319520, + "us-west-2|r8g.12xlarge": 2.827680, + "us-west-2|r8g.16xlarge": 3.770240, + "us-west-2|r8g.24xlarge": 5.655360, + "us-west-2|r8g.2xlarge": 0.471280, + "us-west-2|r8g.48xlarge": 11.310720, + "us-west-2|r8g.4xlarge": 0.942560, + "us-west-2|r8g.8xlarge": 1.885120, + "us-west-2|r8g.large": 0.117820, + "us-west-2|r8g.medium": 0.058910, + "us-west-2|r8g.metal-24xl": 5.655360, + "us-west-2|r8g.metal-48xl": 11.310720, + "us-west-2|r8g.xlarge": 0.235640, + "us-west-2|r8gb.12xlarge": 4.372320, + "us-west-2|r8gb.16xlarge": 5.829760, + "us-west-2|r8gb.24xlarge": 8.744640, + "us-west-2|r8gb.2xlarge": 0.728720, + "us-west-2|r8gb.4xlarge": 1.457440, + "us-west-2|r8gb.8xlarge": 2.914880, + "us-west-2|r8gb.large": 0.182180, + "us-west-2|r8gb.medium": 0.091090, + "us-west-2|r8gb.xlarge": 0.364360, + "us-west-2|r8gd.12xlarge": 3.527040, + "us-west-2|r8gd.16xlarge": 4.702720, + "us-west-2|r8gd.24xlarge": 7.054080, + "us-west-2|r8gd.2xlarge": 0.587840, + "us-west-2|r8gd.48xlarge": 14.108160, + "us-west-2|r8gd.4xlarge": 1.175680, + "us-west-2|r8gd.8xlarge": 2.351360, + "us-west-2|r8gd.large": 0.146960, + "us-west-2|r8gd.medium": 0.073480, + "us-west-2|r8gd.metal-24xl": 7.054080, + "us-west-2|r8gd.metal-48xl": 14.108160, + "us-west-2|r8gd.xlarge": 0.293920, + "us-west-2|r8gn.12xlarge": 4.372300, + "us-west-2|r8gn.16xlarge": 5.829800, + "us-west-2|r8gn.24xlarge": 8.744600, + "us-west-2|r8gn.2xlarge": 0.728700, + "us-west-2|r8gn.48xlarge": 17.489300, + "us-west-2|r8gn.4xlarge": 1.457400, + "us-west-2|r8gn.8xlarge": 2.914900, + "us-west-2|r8gn.large": 0.182200, + "us-west-2|r8gn.medium": 0.091100, + "us-west-2|r8gn.xlarge": 0.364400, + "us-west-2|r8i-flex.12xlarge": 3.167280, + "us-west-2|r8i-flex.16xlarge": 4.223040, + "us-west-2|r8i-flex.2xlarge": 0.527880, + "us-west-2|r8i-flex.4xlarge": 1.055760, + "us-west-2|r8i-flex.8xlarge": 2.111520, + "us-west-2|r8i-flex.large": 0.131970, + "us-west-2|r8i-flex.xlarge": 0.263940, + "us-west-2|r8i.12xlarge": 3.334080, + "us-west-2|r8i.16xlarge": 4.445440, + "us-west-2|r8i.24xlarge": 6.668160, + "us-west-2|r8i.2xlarge": 0.555680, + "us-west-2|r8i.32xlarge": 8.890880, + "us-west-2|r8i.48xlarge": 13.336320, + "us-west-2|r8i.4xlarge": 1.111360, + "us-west-2|r8i.8xlarge": 2.222720, + "us-west-2|r8i.96xlarge": 26.672640, + "us-west-2|r8i.large": 0.138920, + "us-west-2|r8i.metal-48xl": 13.336320, + "us-west-2|r8i.metal-96xl": 26.672640, + "us-west-2|r8i.xlarge": 0.277840, + "us-west-2|t1.micro": 0.020000, + "us-west-2|t2.2xlarge": 0.371200, + "us-west-2|t2.large": 0.092800, + "us-west-2|t2.medium": 0.046400, + "us-west-2|t2.micro": 0.011600, + "us-west-2|t2.nano": 0.005800, + "us-west-2|t2.small": 0.023000, + "us-west-2|t2.xlarge": 0.185600, + "us-west-2|t3.2xlarge": 0.332800, + "us-west-2|t3.large": 0.083200, + "us-west-2|t3.medium": 0.041600, + "us-west-2|t3.micro": 0.010400, + "us-west-2|t3.nano": 0.005200, + "us-west-2|t3.small": 0.020800, + "us-west-2|t3.xlarge": 0.166400, + "us-west-2|t3a.2xlarge": 0.300800, + "us-west-2|t3a.large": 0.075200, + "us-west-2|t3a.medium": 0.037600, + "us-west-2|t3a.micro": 0.009400, + "us-west-2|t3a.nano": 0.004700, + "us-west-2|t3a.small": 0.018800, + "us-west-2|t3a.xlarge": 0.150400, + "us-west-2|t4g.2xlarge": 0.268800, + "us-west-2|t4g.large": 0.067200, + "us-west-2|t4g.medium": 0.033600, + "us-west-2|t4g.micro": 0.008400, + "us-west-2|t4g.nano": 0.004200, + "us-west-2|t4g.small": 0.016800, + "us-west-2|t4g.xlarge": 0.134400, + "us-west-2|trn1.2xlarge": 1.343750, + "us-west-2|trn1.32xlarge": 21.500000, + "us-west-2|trn1n.32xlarge": 24.780000, + "us-west-2|u-12tb1.112xlarge": 109.200000, + "us-west-2|u-18tb1.112xlarge": 163.800000, + "us-west-2|u-24tb1.112xlarge": 218.400000, + "us-west-2|u-3tb1.56xlarge": 27.300000, + "us-west-2|u-6tb1.112xlarge": 54.600000, + "us-west-2|u-6tb1.56xlarge": 46.403910, + "us-west-2|u-9tb1.112xlarge": 81.900000, + "us-west-2|u7i-12tb.224xlarge": 125.581820, + "us-west-2|u7i-6tb.112xlarge": 62.790000, + "us-west-2|u7i-8tb.112xlarge": 83.720000, + "us-west-2|u7in-16tb.224xlarge": 180.475580, + "us-west-2|u7in-24tb.224xlarge": 270.731280, + "us-west-2|u7in-32tb.224xlarge": 360.986950, + "us-west-2|vt1.24xlarge": 5.200000, + "us-west-2|vt1.3xlarge": 0.650000, + "us-west-2|vt1.6xlarge": 1.300000, + "us-west-2|x1.16xlarge": 6.669000, + "us-west-2|x1.32xlarge": 13.338000, + "us-west-2|x1e.16xlarge": 13.344000, + "us-west-2|x1e.2xlarge": 1.668000, + "us-west-2|x1e.32xlarge": 26.688000, + "us-west-2|x1e.4xlarge": 3.336000, + "us-west-2|x1e.8xlarge": 6.672000, + "us-west-2|x1e.xlarge": 0.834000, + "us-west-2|x2gd.12xlarge": 4.008000, + "us-west-2|x2gd.16xlarge": 5.344000, + "us-west-2|x2gd.2xlarge": 0.668000, + "us-west-2|x2gd.4xlarge": 1.336000, + "us-west-2|x2gd.8xlarge": 2.672000, + "us-west-2|x2gd.large": 0.167000, + "us-west-2|x2gd.medium": 0.083500, + "us-west-2|x2gd.metal": 5.344000, + "us-west-2|x2gd.xlarge": 0.334000, + "us-west-2|x2idn.16xlarge": 6.669000, + "us-west-2|x2idn.24xlarge": 10.003500, + "us-west-2|x2idn.32xlarge": 13.338000, + "us-west-2|x2idn.metal": 13.338000, + "us-west-2|x2iedn.16xlarge": 13.338000, + "us-west-2|x2iedn.24xlarge": 20.007000, + "us-west-2|x2iedn.2xlarge": 1.667250, + "us-west-2|x2iedn.32xlarge": 26.676000, + "us-west-2|x2iedn.4xlarge": 3.334500, + "us-west-2|x2iedn.8xlarge": 6.669000, + "us-west-2|x2iedn.metal": 26.676000, + "us-west-2|x2iedn.xlarge": 0.833630, + "us-west-2|x2iezn.12xlarge": 10.008000, + "us-west-2|x2iezn.2xlarge": 1.668000, + "us-west-2|x2iezn.4xlarge": 3.336000, + "us-west-2|x2iezn.6xlarge": 5.004000, + "us-west-2|x2iezn.8xlarge": 6.672000, + "us-west-2|x2iezn.metal": 10.008000, + "us-west-2|x8aedz.12xlarge": 13.807200, + "us-west-2|x8aedz.24xlarge": 27.614400, + "us-west-2|x8aedz.3xlarge": 3.451800, + "us-west-2|x8aedz.6xlarge": 6.903600, + "us-west-2|x8aedz.large": 0.575300, + "us-west-2|x8aedz.metal-12xl": 13.807200, + "us-west-2|x8aedz.metal-24xl": 27.614400, + "us-west-2|x8aedz.xlarge": 1.150600, + "us-west-2|x8g.12xlarge": 4.689600, + "us-west-2|x8g.16xlarge": 6.252800, + "us-west-2|x8g.24xlarge": 9.379200, + "us-west-2|x8g.2xlarge": 0.781600, + "us-west-2|x8g.48xlarge": 18.758400, + "us-west-2|x8g.4xlarge": 1.563200, + "us-west-2|x8g.8xlarge": 3.126400, + "us-west-2|x8g.large": 0.195400, + "us-west-2|x8g.medium": 0.097700, + "us-west-2|x8g.metal-24xl": 9.379200, + "us-west-2|x8g.metal-48xl": 18.758400, + "us-west-2|x8g.xlarge": 0.390800, + "us-west-2|z1d.12xlarge": 4.464000, + "us-west-2|z1d.2xlarge": 0.744000, + "us-west-2|z1d.3xlarge": 1.116000, + "us-west-2|z1d.6xlarge": 2.232000, + "us-west-2|z1d.large": 0.186000, + "us-west-2|z1d.metal": 4.464000, + "us-west-2|z1d.xlarge": 0.372000, +} diff --git a/internal/proto/agent/v1/agent.pb.go b/internal/proto/agent/v1/agent.pb.go new file mode 100644 index 0000000..f5fb516 --- /dev/null +++ b/internal/proto/agent/v1/agent.pb.go @@ -0,0 +1,1403 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc v4.25.3 +// source: agent/v1/agent.proto + +package agentv1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type MetricsReportRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + AgentId string `protobuf:"bytes,1,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"` + ClusterId string `protobuf:"bytes,2,opt,name=cluster_id,json=clusterId,proto3" json:"cluster_id,omitempty"` + NodeName string `protobuf:"bytes,3,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"` + AvailabilityZone string `protobuf:"bytes,4,opt,name=availability_zone,json=availabilityZone,proto3" json:"availability_zone,omitempty"` + TimestampSeconds int64 `protobuf:"varint,5,opt,name=timestamp_seconds,json=timestampSeconds,proto3" json:"timestamp_seconds,omitempty"` + Region string `protobuf:"bytes,6,opt,name=region,proto3" json:"region,omitempty"` + InstanceType string `protobuf:"bytes,7,opt,name=instance_type,json=instanceType,proto3" json:"instance_type,omitempty"` + Pods []*PodMetric `protobuf:"bytes,8,rep,name=pods,proto3" json:"pods,omitempty"` + Nodes []*NodeMetric `protobuf:"bytes,9,rep,name=nodes,proto3" json:"nodes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MetricsReportRequest) Reset() { + *x = MetricsReportRequest{} + mi := &file_agent_v1_agent_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MetricsReportRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MetricsReportRequest) ProtoMessage() {} + +func (x *MetricsReportRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_v1_agent_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MetricsReportRequest.ProtoReflect.Descriptor instead. +func (*MetricsReportRequest) Descriptor() ([]byte, []int) { + return file_agent_v1_agent_proto_rawDescGZIP(), []int{0} +} + +func (x *MetricsReportRequest) GetAgentId() string { + if x != nil { + return x.AgentId + } + return "" +} + +func (x *MetricsReportRequest) GetClusterId() string { + if x != nil { + return x.ClusterId + } + return "" +} + +func (x *MetricsReportRequest) GetNodeName() string { + if x != nil { + return x.NodeName + } + return "" +} + +func (x *MetricsReportRequest) GetAvailabilityZone() string { + if x != nil { + return x.AvailabilityZone + } + return "" +} + +func (x *MetricsReportRequest) GetTimestampSeconds() int64 { + if x != nil { + return x.TimestampSeconds + } + return 0 +} + +func (x *MetricsReportRequest) GetRegion() string { + if x != nil { + return x.Region + } + return "" +} + +func (x *MetricsReportRequest) GetInstanceType() string { + if x != nil { + return x.InstanceType + } + return "" +} + +func (x *MetricsReportRequest) GetPods() []*PodMetric { + if x != nil { + return x.Pods + } + return nil +} + +func (x *MetricsReportRequest) GetNodes() []*NodeMetric { + if x != nil { + return x.Nodes + } + return nil +} + +type NetworkReportRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + AgentId string `protobuf:"bytes,1,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"` + ClusterId string `protobuf:"bytes,2,opt,name=cluster_id,json=clusterId,proto3" json:"cluster_id,omitempty"` + NodeName string `protobuf:"bytes,3,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"` + AvailabilityZone string `protobuf:"bytes,4,opt,name=availability_zone,json=availabilityZone,proto3" json:"availability_zone,omitempty"` + TimestampSeconds int64 `protobuf:"varint,5,opt,name=timestamp_seconds,json=timestampSeconds,proto3" json:"timestamp_seconds,omitempty"` + Region string `protobuf:"bytes,6,opt,name=region,proto3" json:"region,omitempty"` + InstanceType string `protobuf:"bytes,7,opt,name=instance_type,json=instanceType,proto3" json:"instance_type,omitempty"` + // Optimization: Dictionary Encoding + Endpoints []*NetworkEndpoint `protobuf:"bytes,10,rep,name=endpoints,proto3" json:"endpoints,omitempty"` + CompactConnections []*CompactNetworkConnection `protobuf:"bytes,11,rep,name=compact_connections,json=compactConnections,proto3" json:"compact_connections,omitempty"` + // Deprecated: Use endpoints + compact_connections + Connections []*NetworkConnection `protobuf:"bytes,8,rep,name=connections,proto3" json:"connections,omitempty"` + Pods []*PodMetric `protobuf:"bytes,9,rep,name=pods,proto3" json:"pods,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NetworkReportRequest) Reset() { + *x = NetworkReportRequest{} + mi := &file_agent_v1_agent_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NetworkReportRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetworkReportRequest) ProtoMessage() {} + +func (x *NetworkReportRequest) ProtoReflect() protoreflect.Message { + mi := &file_agent_v1_agent_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NetworkReportRequest.ProtoReflect.Descriptor instead. +func (*NetworkReportRequest) Descriptor() ([]byte, []int) { + return file_agent_v1_agent_proto_rawDescGZIP(), []int{1} +} + +func (x *NetworkReportRequest) GetAgentId() string { + if x != nil { + return x.AgentId + } + return "" +} + +func (x *NetworkReportRequest) GetClusterId() string { + if x != nil { + return x.ClusterId + } + return "" +} + +func (x *NetworkReportRequest) GetNodeName() string { + if x != nil { + return x.NodeName + } + return "" +} + +func (x *NetworkReportRequest) GetAvailabilityZone() string { + if x != nil { + return x.AvailabilityZone + } + return "" +} + +func (x *NetworkReportRequest) GetTimestampSeconds() int64 { + if x != nil { + return x.TimestampSeconds + } + return 0 +} + +func (x *NetworkReportRequest) GetRegion() string { + if x != nil { + return x.Region + } + return "" +} + +func (x *NetworkReportRequest) GetInstanceType() string { + if x != nil { + return x.InstanceType + } + return "" +} + +func (x *NetworkReportRequest) GetEndpoints() []*NetworkEndpoint { + if x != nil { + return x.Endpoints + } + return nil +} + +func (x *NetworkReportRequest) GetCompactConnections() []*CompactNetworkConnection { + if x != nil { + return x.CompactConnections + } + return nil +} + +func (x *NetworkReportRequest) GetConnections() []*NetworkConnection { + if x != nil { + return x.Connections + } + return nil +} + +func (x *NetworkReportRequest) GetPods() []*PodMetric { + if x != nil { + return x.Pods + } + return nil +} + +type CompactNetworkConnection struct { + state protoimpl.MessageState `protogen:"open.v1"` + SrcIndex uint32 `protobuf:"varint,1,opt,name=src_index,json=srcIndex,proto3" json:"src_index,omitempty"` // Index into request.endpoints + DstIndex uint32 `protobuf:"varint,2,opt,name=dst_index,json=dstIndex,proto3" json:"dst_index,omitempty"` // Index into request.endpoints + Protocol uint32 `protobuf:"varint,3,opt,name=protocol,proto3" json:"protocol,omitempty"` + BytesSent uint64 `protobuf:"varint,4,opt,name=bytes_sent,json=bytesSent,proto3" json:"bytes_sent,omitempty"` + BytesReceived uint64 `protobuf:"varint,5,opt,name=bytes_received,json=bytesReceived,proto3" json:"bytes_received,omitempty"` + EgressClass string `protobuf:"bytes,6,opt,name=egress_class,json=egressClass,proto3" json:"egress_class,omitempty"` + DstKind string `protobuf:"bytes,8,opt,name=dst_kind,json=dstKind,proto3" json:"dst_kind,omitempty"` + ServiceMatch string `protobuf:"bytes,9,opt,name=service_match,json=serviceMatch,proto3" json:"service_match,omitempty"` + IsEgress bool `protobuf:"varint,10,opt,name=is_egress,json=isEgress,proto3" json:"is_egress,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CompactNetworkConnection) Reset() { + *x = CompactNetworkConnection{} + mi := &file_agent_v1_agent_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CompactNetworkConnection) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CompactNetworkConnection) ProtoMessage() {} + +func (x *CompactNetworkConnection) ProtoReflect() protoreflect.Message { + mi := &file_agent_v1_agent_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CompactNetworkConnection.ProtoReflect.Descriptor instead. +func (*CompactNetworkConnection) Descriptor() ([]byte, []int) { + return file_agent_v1_agent_proto_rawDescGZIP(), []int{2} +} + +func (x *CompactNetworkConnection) GetSrcIndex() uint32 { + if x != nil { + return x.SrcIndex + } + return 0 +} + +func (x *CompactNetworkConnection) GetDstIndex() uint32 { + if x != nil { + return x.DstIndex + } + return 0 +} + +func (x *CompactNetworkConnection) GetProtocol() uint32 { + if x != nil { + return x.Protocol + } + return 0 +} + +func (x *CompactNetworkConnection) GetBytesSent() uint64 { + if x != nil { + return x.BytesSent + } + return 0 +} + +func (x *CompactNetworkConnection) GetBytesReceived() uint64 { + if x != nil { + return x.BytesReceived + } + return 0 +} + +func (x *CompactNetworkConnection) GetEgressClass() string { + if x != nil { + return x.EgressClass + } + return "" +} + +func (x *CompactNetworkConnection) GetDstKind() string { + if x != nil { + return x.DstKind + } + return "" +} + +func (x *CompactNetworkConnection) GetServiceMatch() string { + if x != nil { + return x.ServiceMatch + } + return "" +} + +func (x *CompactNetworkConnection) GetIsEgress() bool { + if x != nil { + return x.IsEgress + } + return false +} + +type ReportResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Accepted bool `protobuf:"varint,1,opt,name=accepted,proto3" json:"accepted,omitempty"` + ErrorMessage string `protobuf:"bytes,2,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ReportResponse) Reset() { + *x = ReportResponse{} + mi := &file_agent_v1_agent_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReportResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReportResponse) ProtoMessage() {} + +func (x *ReportResponse) ProtoReflect() protoreflect.Message { + mi := &file_agent_v1_agent_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReportResponse.ProtoReflect.Descriptor instead. +func (*ReportResponse) Descriptor() ([]byte, []int) { + return file_agent_v1_agent_proto_rawDescGZIP(), []int{3} +} + +func (x *ReportResponse) GetAccepted() bool { + if x != nil { + return x.Accepted + } + return false +} + +func (x *ReportResponse) GetErrorMessage() string { + if x != nil { + return x.ErrorMessage + } + return "" +} + +type PodMetric struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Metadata Context + PodUid string `protobuf:"bytes,1,opt,name=pod_uid,json=podUid,proto3" json:"pod_uid,omitempty"` + ContainerId string `protobuf:"bytes,2,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + PidTgid uint32 `protobuf:"varint,3,opt,name=pid_tgid,json=pidTgid,proto3" json:"pid_tgid,omitempty"` + // Include namespace/pod name to help aggregator if K8s API is lagging, + // but strictly spec just says identifiers. + // "The agent must resolve destination IPs..." -> Agent does heavy lifting for network. + // Let's keep namespace/name as they are cheap and useful. + Namespace string `protobuf:"bytes,4,opt,name=namespace,proto3" json:"namespace,omitempty"` + PodName string `protobuf:"bytes,5,opt,name=pod_name,json=podName,proto3" json:"pod_name,omitempty"` + // Compute Performance + Cpu *CpuMetrics `protobuf:"bytes,6,opt,name=cpu,proto3" json:"cpu,omitempty"` + Memory *MemoryMetrics `protobuf:"bytes,7,opt,name=memory,proto3" json:"memory,omitempty"` + // Cost-Aware Network + Network *NetworkMetrics `protobuf:"bytes,8,opt,name=network,proto3" json:"network,omitempty"` + // Storage I/O + Storage *StorageMetrics `protobuf:"bytes,9,opt,name=storage,proto3" json:"storage,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PodMetric) Reset() { + *x = PodMetric{} + mi := &file_agent_v1_agent_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PodMetric) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PodMetric) ProtoMessage() {} + +func (x *PodMetric) ProtoReflect() protoreflect.Message { + mi := &file_agent_v1_agent_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PodMetric.ProtoReflect.Descriptor instead. +func (*PodMetric) Descriptor() ([]byte, []int) { + return file_agent_v1_agent_proto_rawDescGZIP(), []int{4} +} + +func (x *PodMetric) GetPodUid() string { + if x != nil { + return x.PodUid + } + return "" +} + +func (x *PodMetric) GetContainerId() string { + if x != nil { + return x.ContainerId + } + return "" +} + +func (x *PodMetric) GetPidTgid() uint32 { + if x != nil { + return x.PidTgid + } + return 0 +} + +func (x *PodMetric) GetNamespace() string { + if x != nil { + return x.Namespace + } + return "" +} + +func (x *PodMetric) GetPodName() string { + if x != nil { + return x.PodName + } + return "" +} + +func (x *PodMetric) GetCpu() *CpuMetrics { + if x != nil { + return x.Cpu + } + return nil +} + +func (x *PodMetric) GetMemory() *MemoryMetrics { + if x != nil { + return x.Memory + } + return nil +} + +func (x *PodMetric) GetNetwork() *NetworkMetrics { + if x != nil { + return x.Network + } + return nil +} + +func (x *PodMetric) GetStorage() *StorageMetrics { + if x != nil { + return x.Storage + } + return nil +} + +type CpuMetrics struct { + state protoimpl.MessageState `protogen:"open.v1"` + // K8s Requests (mCPU) + RequestMillicores uint64 `protobuf:"varint,4,opt,name=request_millicores,json=requestMillicores,proto3" json:"request_millicores,omitempty"` + // K8s Limits (mCPU) + LimitMillicores uint64 `protobuf:"varint,5,opt,name=limit_millicores,json=limitMillicores,proto3" json:"limit_millicores,omitempty"` + // Usage (mCPU) + UsageMillicores uint64 `protobuf:"varint,6,opt,name=usage_millicores,json=usageMillicores,proto3" json:"usage_millicores,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CpuMetrics) Reset() { + *x = CpuMetrics{} + mi := &file_agent_v1_agent_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CpuMetrics) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CpuMetrics) ProtoMessage() {} + +func (x *CpuMetrics) ProtoReflect() protoreflect.Message { + mi := &file_agent_v1_agent_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CpuMetrics.ProtoReflect.Descriptor instead. +func (*CpuMetrics) Descriptor() ([]byte, []int) { + return file_agent_v1_agent_proto_rawDescGZIP(), []int{5} +} + +func (x *CpuMetrics) GetRequestMillicores() uint64 { + if x != nil { + return x.RequestMillicores + } + return 0 +} + +func (x *CpuMetrics) GetLimitMillicores() uint64 { + if x != nil { + return x.LimitMillicores + } + return 0 +} + +func (x *CpuMetrics) GetUsageMillicores() uint64 { + if x != nil { + return x.UsageMillicores + } + return 0 +} + +type MemoryMetrics struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Resident Set Size (bytes) + RssBytes uint64 `protobuf:"varint,1,opt,name=rss_bytes,json=rssBytes,proto3" json:"rss_bytes,omitempty"` + // Major page faults + PageFaultsMajor uint64 `protobuf:"varint,2,opt,name=page_faults_major,json=pageFaultsMajor,proto3" json:"page_faults_major,omitempty"` + // K8s Requests (bytes) + RequestBytes uint64 `protobuf:"varint,3,opt,name=request_bytes,json=requestBytes,proto3" json:"request_bytes,omitempty"` + // K8s Limits (bytes) + LimitBytes uint64 `protobuf:"varint,4,opt,name=limit_bytes,json=limitBytes,proto3" json:"limit_bytes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MemoryMetrics) Reset() { + *x = MemoryMetrics{} + mi := &file_agent_v1_agent_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MemoryMetrics) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MemoryMetrics) ProtoMessage() {} + +func (x *MemoryMetrics) ProtoReflect() protoreflect.Message { + mi := &file_agent_v1_agent_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MemoryMetrics.ProtoReflect.Descriptor instead. +func (*MemoryMetrics) Descriptor() ([]byte, []int) { + return file_agent_v1_agent_proto_rawDescGZIP(), []int{6} +} + +func (x *MemoryMetrics) GetRssBytes() uint64 { + if x != nil { + return x.RssBytes + } + return 0 +} + +func (x *MemoryMetrics) GetPageFaultsMajor() uint64 { + if x != nil { + return x.PageFaultsMajor + } + return 0 +} + +func (x *MemoryMetrics) GetRequestBytes() uint64 { + if x != nil { + return x.RequestBytes + } + return 0 +} + +func (x *MemoryMetrics) GetLimitBytes() uint64 { + if x != nil { + return x.LimitBytes + } + return 0 +} + +type NetworkMetrics struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Throughput + BytesSent uint64 `protobuf:"varint,1,opt,name=bytes_sent,json=bytesSent,proto3" json:"bytes_sent,omitempty"` + BytesReceived uint64 `protobuf:"varint,2,opt,name=bytes_received,json=bytesReceived,proto3" json:"bytes_received,omitempty"` + // Traffic Categorization (Egress Analyzer) + EgressPublicBytes uint64 `protobuf:"varint,3,opt,name=egress_public_bytes,json=egressPublicBytes,proto3" json:"egress_public_bytes,omitempty"` + EgressCrossAzBytes uint64 `protobuf:"varint,4,opt,name=egress_cross_az_bytes,json=egressCrossAzBytes,proto3" json:"egress_cross_az_bytes,omitempty"` + EgressInternalBytes uint64 `protobuf:"varint,5,opt,name=egress_internal_bytes,json=egressInternalBytes,proto3" json:"egress_internal_bytes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NetworkMetrics) Reset() { + *x = NetworkMetrics{} + mi := &file_agent_v1_agent_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NetworkMetrics) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetworkMetrics) ProtoMessage() {} + +func (x *NetworkMetrics) ProtoReflect() protoreflect.Message { + mi := &file_agent_v1_agent_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NetworkMetrics.ProtoReflect.Descriptor instead. +func (*NetworkMetrics) Descriptor() ([]byte, []int) { + return file_agent_v1_agent_proto_rawDescGZIP(), []int{7} +} + +func (x *NetworkMetrics) GetBytesSent() uint64 { + if x != nil { + return x.BytesSent + } + return 0 +} + +func (x *NetworkMetrics) GetBytesReceived() uint64 { + if x != nil { + return x.BytesReceived + } + return 0 +} + +func (x *NetworkMetrics) GetEgressPublicBytes() uint64 { + if x != nil { + return x.EgressPublicBytes + } + return 0 +} + +func (x *NetworkMetrics) GetEgressCrossAzBytes() uint64 { + if x != nil { + return x.EgressCrossAzBytes + } + return 0 +} + +func (x *NetworkMetrics) GetEgressInternalBytes() uint64 { + if x != nil { + return x.EgressInternalBytes + } + return 0 +} + +type NetworkConnection struct { + state protoimpl.MessageState `protogen:"open.v1"` + Src *NetworkEndpoint `protobuf:"bytes,1,opt,name=src,proto3" json:"src,omitempty"` + Dst *NetworkEndpoint `protobuf:"bytes,2,opt,name=dst,proto3" json:"dst,omitempty"` + Protocol uint32 `protobuf:"varint,3,opt,name=protocol,proto3" json:"protocol,omitempty"` + BytesSent uint64 `protobuf:"varint,4,opt,name=bytes_sent,json=bytesSent,proto3" json:"bytes_sent,omitempty"` + BytesReceived uint64 `protobuf:"varint,5,opt,name=bytes_received,json=bytesReceived,proto3" json:"bytes_received,omitempty"` + EgressClass string `protobuf:"bytes,6,opt,name=egress_class,json=egressClass,proto3" json:"egress_class,omitempty"` + DstKind string `protobuf:"bytes,8,opt,name=dst_kind,json=dstKind,proto3" json:"dst_kind,omitempty"` + ServiceMatch string `protobuf:"bytes,9,opt,name=service_match,json=serviceMatch,proto3" json:"service_match,omitempty"` + IsEgress bool `protobuf:"varint,10,opt,name=is_egress,json=isEgress,proto3" json:"is_egress,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NetworkConnection) Reset() { + *x = NetworkConnection{} + mi := &file_agent_v1_agent_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NetworkConnection) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetworkConnection) ProtoMessage() {} + +func (x *NetworkConnection) ProtoReflect() protoreflect.Message { + mi := &file_agent_v1_agent_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NetworkConnection.ProtoReflect.Descriptor instead. +func (*NetworkConnection) Descriptor() ([]byte, []int) { + return file_agent_v1_agent_proto_rawDescGZIP(), []int{8} +} + +func (x *NetworkConnection) GetSrc() *NetworkEndpoint { + if x != nil { + return x.Src + } + return nil +} + +func (x *NetworkConnection) GetDst() *NetworkEndpoint { + if x != nil { + return x.Dst + } + return nil +} + +func (x *NetworkConnection) GetProtocol() uint32 { + if x != nil { + return x.Protocol + } + return 0 +} + +func (x *NetworkConnection) GetBytesSent() uint64 { + if x != nil { + return x.BytesSent + } + return 0 +} + +func (x *NetworkConnection) GetBytesReceived() uint64 { + if x != nil { + return x.BytesReceived + } + return 0 +} + +func (x *NetworkConnection) GetEgressClass() string { + if x != nil { + return x.EgressClass + } + return "" +} + +func (x *NetworkConnection) GetDstKind() string { + if x != nil { + return x.DstKind + } + return "" +} + +func (x *NetworkConnection) GetServiceMatch() string { + if x != nil { + return x.ServiceMatch + } + return "" +} + +func (x *NetworkConnection) GetIsEgress() bool { + if x != nil { + return x.IsEgress + } + return false +} + +type NodeMetric struct { + state protoimpl.MessageState `protogen:"open.v1"` + NodeName string `protobuf:"bytes,1,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"` + CpuUsageMillicores uint64 `protobuf:"varint,2,opt,name=cpu_usage_millicores,json=cpuUsageMillicores,proto3" json:"cpu_usage_millicores,omitempty"` + MemoryUsageBytes uint64 `protobuf:"varint,3,opt,name=memory_usage_bytes,json=memoryUsageBytes,proto3" json:"memory_usage_bytes,omitempty"` + CapacityCpuMillicores uint64 `protobuf:"varint,4,opt,name=capacity_cpu_millicores,json=capacityCpuMillicores,proto3" json:"capacity_cpu_millicores,omitempty"` + CapacityMemoryBytes uint64 `protobuf:"varint,5,opt,name=capacity_memory_bytes,json=capacityMemoryBytes,proto3" json:"capacity_memory_bytes,omitempty"` + AllocatableCpuMillicores uint64 `protobuf:"varint,6,opt,name=allocatable_cpu_millicores,json=allocatableCpuMillicores,proto3" json:"allocatable_cpu_millicores,omitempty"` + AllocatableMemoryBytes uint64 `protobuf:"varint,7,opt,name=allocatable_memory_bytes,json=allocatableMemoryBytes,proto3" json:"allocatable_memory_bytes,omitempty"` + RequestedCpuMillicores uint64 `protobuf:"varint,8,opt,name=requested_cpu_millicores,json=requestedCpuMillicores,proto3" json:"requested_cpu_millicores,omitempty"` + RequestedMemoryBytes uint64 `protobuf:"varint,9,opt,name=requested_memory_bytes,json=requestedMemoryBytes,proto3" json:"requested_memory_bytes,omitempty"` + // Total throttled CPU time from cgroup cpu.stat (ns). + ThrottlingNs uint64 `protobuf:"varint,10,opt,name=throttling_ns,json=throttlingNs,proto3" json:"throttling_ns,omitempty"` + // Cost-Aware Network (Host traffic) + Network *NetworkMetrics `protobuf:"bytes,11,opt,name=network,proto3" json:"network,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NodeMetric) Reset() { + *x = NodeMetric{} + mi := &file_agent_v1_agent_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NodeMetric) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NodeMetric) ProtoMessage() {} + +func (x *NodeMetric) ProtoReflect() protoreflect.Message { + mi := &file_agent_v1_agent_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NodeMetric.ProtoReflect.Descriptor instead. +func (*NodeMetric) Descriptor() ([]byte, []int) { + return file_agent_v1_agent_proto_rawDescGZIP(), []int{9} +} + +func (x *NodeMetric) GetNodeName() string { + if x != nil { + return x.NodeName + } + return "" +} + +func (x *NodeMetric) GetCpuUsageMillicores() uint64 { + if x != nil { + return x.CpuUsageMillicores + } + return 0 +} + +func (x *NodeMetric) GetMemoryUsageBytes() uint64 { + if x != nil { + return x.MemoryUsageBytes + } + return 0 +} + +func (x *NodeMetric) GetCapacityCpuMillicores() uint64 { + if x != nil { + return x.CapacityCpuMillicores + } + return 0 +} + +func (x *NodeMetric) GetCapacityMemoryBytes() uint64 { + if x != nil { + return x.CapacityMemoryBytes + } + return 0 +} + +func (x *NodeMetric) GetAllocatableCpuMillicores() uint64 { + if x != nil { + return x.AllocatableCpuMillicores + } + return 0 +} + +func (x *NodeMetric) GetAllocatableMemoryBytes() uint64 { + if x != nil { + return x.AllocatableMemoryBytes + } + return 0 +} + +func (x *NodeMetric) GetRequestedCpuMillicores() uint64 { + if x != nil { + return x.RequestedCpuMillicores + } + return 0 +} + +func (x *NodeMetric) GetRequestedMemoryBytes() uint64 { + if x != nil { + return x.RequestedMemoryBytes + } + return 0 +} + +func (x *NodeMetric) GetThrottlingNs() uint64 { + if x != nil { + return x.ThrottlingNs + } + return 0 +} + +func (x *NodeMetric) GetNetwork() *NetworkMetrics { + if x != nil { + return x.Network + } + return nil +} + +type NetworkEndpoint struct { + state protoimpl.MessageState `protogen:"open.v1"` + Ip string `protobuf:"bytes,1,opt,name=ip,proto3" json:"ip,omitempty"` + Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` + PodName string `protobuf:"bytes,3,opt,name=pod_name,json=podName,proto3" json:"pod_name,omitempty"` + NodeName string `protobuf:"bytes,4,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"` + AvailabilityZone string `protobuf:"bytes,5,opt,name=availability_zone,json=availabilityZone,proto3" json:"availability_zone,omitempty"` + Services []*ServiceRef `protobuf:"bytes,6,rep,name=services,proto3" json:"services,omitempty"` + DnsName string `protobuf:"bytes,7,opt,name=dns_name,json=dnsName,proto3" json:"dns_name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NetworkEndpoint) Reset() { + *x = NetworkEndpoint{} + mi := &file_agent_v1_agent_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NetworkEndpoint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetworkEndpoint) ProtoMessage() {} + +func (x *NetworkEndpoint) ProtoReflect() protoreflect.Message { + mi := &file_agent_v1_agent_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NetworkEndpoint.ProtoReflect.Descriptor instead. +func (*NetworkEndpoint) Descriptor() ([]byte, []int) { + return file_agent_v1_agent_proto_rawDescGZIP(), []int{10} +} + +func (x *NetworkEndpoint) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +func (x *NetworkEndpoint) GetNamespace() string { + if x != nil { + return x.Namespace + } + return "" +} + +func (x *NetworkEndpoint) GetPodName() string { + if x != nil { + return x.PodName + } + return "" +} + +func (x *NetworkEndpoint) GetNodeName() string { + if x != nil { + return x.NodeName + } + return "" +} + +func (x *NetworkEndpoint) GetAvailabilityZone() string { + if x != nil { + return x.AvailabilityZone + } + return "" +} + +func (x *NetworkEndpoint) GetServices() []*ServiceRef { + if x != nil { + return x.Services + } + return nil +} + +func (x *NetworkEndpoint) GetDnsName() string { + if x != nil { + return x.DnsName + } + return "" +} + +type ServiceRef struct { + state protoimpl.MessageState `protogen:"open.v1"` + Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ServiceRef) Reset() { + *x = ServiceRef{} + mi := &file_agent_v1_agent_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ServiceRef) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServiceRef) ProtoMessage() {} + +func (x *ServiceRef) ProtoReflect() protoreflect.Message { + mi := &file_agent_v1_agent_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServiceRef.ProtoReflect.Descriptor instead. +func (*ServiceRef) Descriptor() ([]byte, []int) { + return file_agent_v1_agent_proto_rawDescGZIP(), []int{11} +} + +func (x *ServiceRef) GetNamespace() string { + if x != nil { + return x.Namespace + } + return "" +} + +func (x *ServiceRef) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type StorageMetrics struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Throughput + ReadBytes uint64 `protobuf:"varint,1,opt,name=read_bytes,json=readBytes,proto3" json:"read_bytes,omitempty"` + WriteBytes uint64 `protobuf:"varint,2,opt,name=write_bytes,json=writeBytes,proto3" json:"write_bytes,omitempty"` + // IOPS + ReadOps uint64 `protobuf:"varint,3,opt,name=read_ops,json=readOps,proto3" json:"read_ops,omitempty"` + WriteOps uint64 `protobuf:"varint,4,opt,name=write_ops,json=writeOps,proto3" json:"write_ops,omitempty"` + // Latency + TotalLatencyNs uint64 `protobuf:"varint,5,opt,name=total_latency_ns,json=totalLatencyNs,proto3" json:"total_latency_ns,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StorageMetrics) Reset() { + *x = StorageMetrics{} + mi := &file_agent_v1_agent_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StorageMetrics) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StorageMetrics) ProtoMessage() {} + +func (x *StorageMetrics) ProtoReflect() protoreflect.Message { + mi := &file_agent_v1_agent_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StorageMetrics.ProtoReflect.Descriptor instead. +func (*StorageMetrics) Descriptor() ([]byte, []int) { + return file_agent_v1_agent_proto_rawDescGZIP(), []int{12} +} + +func (x *StorageMetrics) GetReadBytes() uint64 { + if x != nil { + return x.ReadBytes + } + return 0 +} + +func (x *StorageMetrics) GetWriteBytes() uint64 { + if x != nil { + return x.WriteBytes + } + return 0 +} + +func (x *StorageMetrics) GetReadOps() uint64 { + if x != nil { + return x.ReadOps + } + return 0 +} + +func (x *StorageMetrics) GetWriteOps() uint64 { + if x != nil { + return x.WriteOps + } + return 0 +} + +func (x *StorageMetrics) GetTotalLatencyNs() uint64 { + if x != nil { + return x.TotalLatencyNs + } + return 0 +} + +var File_agent_v1_agent_proto protoreflect.FileDescriptor + +const file_agent_v1_agent_proto_rawDesc = "" + + "\n" + + "\x14agent/v1/agent.proto\x12\bagent.v1\"\xd9\x02\n" + + "\x14MetricsReportRequest\x12\x19\n" + + "\bagent_id\x18\x01 \x01(\tR\aagentId\x12\x1d\n" + + "\n" + + "cluster_id\x18\x02 \x01(\tR\tclusterId\x12\x1b\n" + + "\tnode_name\x18\x03 \x01(\tR\bnodeName\x12+\n" + + "\x11availability_zone\x18\x04 \x01(\tR\x10availabilityZone\x12+\n" + + "\x11timestamp_seconds\x18\x05 \x01(\x03R\x10timestampSeconds\x12\x16\n" + + "\x06region\x18\x06 \x01(\tR\x06region\x12#\n" + + "\rinstance_type\x18\a \x01(\tR\finstanceType\x12'\n" + + "\x04pods\x18\b \x03(\v2\x13.agent.v1.PodMetricR\x04pods\x12*\n" + + "\x05nodes\x18\t \x03(\v2\x14.agent.v1.NodeMetricR\x05nodes\"\xfa\x03\n" + + "\x14NetworkReportRequest\x12\x19\n" + + "\bagent_id\x18\x01 \x01(\tR\aagentId\x12\x1d\n" + + "\n" + + "cluster_id\x18\x02 \x01(\tR\tclusterId\x12\x1b\n" + + "\tnode_name\x18\x03 \x01(\tR\bnodeName\x12+\n" + + "\x11availability_zone\x18\x04 \x01(\tR\x10availabilityZone\x12+\n" + + "\x11timestamp_seconds\x18\x05 \x01(\x03R\x10timestampSeconds\x12\x16\n" + + "\x06region\x18\x06 \x01(\tR\x06region\x12#\n" + + "\rinstance_type\x18\a \x01(\tR\finstanceType\x127\n" + + "\tendpoints\x18\n" + + " \x03(\v2\x19.agent.v1.NetworkEndpointR\tendpoints\x12S\n" + + "\x13compact_connections\x18\v \x03(\v2\".agent.v1.CompactNetworkConnectionR\x12compactConnections\x12=\n" + + "\vconnections\x18\b \x03(\v2\x1b.agent.v1.NetworkConnectionR\vconnections\x12'\n" + + "\x04pods\x18\t \x03(\v2\x13.agent.v1.PodMetricR\x04pods\"\xb6\x02\n" + + "\x18CompactNetworkConnection\x12\x1b\n" + + "\tsrc_index\x18\x01 \x01(\rR\bsrcIndex\x12\x1b\n" + + "\tdst_index\x18\x02 \x01(\rR\bdstIndex\x12\x1a\n" + + "\bprotocol\x18\x03 \x01(\rR\bprotocol\x12\x1d\n" + + "\n" + + "bytes_sent\x18\x04 \x01(\x04R\tbytesSent\x12%\n" + + "\x0ebytes_received\x18\x05 \x01(\x04R\rbytesReceived\x12!\n" + + "\fegress_class\x18\x06 \x01(\tR\vegressClass\x12\x19\n" + + "\bdst_kind\x18\b \x01(\tR\adstKind\x12#\n" + + "\rservice_match\x18\t \x01(\tR\fserviceMatch\x12\x1b\n" + + "\tis_egress\x18\n" + + " \x01(\bR\bisEgress\"Q\n" + + "\x0eReportResponse\x12\x1a\n" + + "\baccepted\x18\x01 \x01(\bR\baccepted\x12#\n" + + "\rerror_message\x18\x02 \x01(\tR\ferrorMessage\"\xdc\x02\n" + + "\tPodMetric\x12\x17\n" + + "\apod_uid\x18\x01 \x01(\tR\x06podUid\x12!\n" + + "\fcontainer_id\x18\x02 \x01(\tR\vcontainerId\x12\x19\n" + + "\bpid_tgid\x18\x03 \x01(\rR\apidTgid\x12\x1c\n" + + "\tnamespace\x18\x04 \x01(\tR\tnamespace\x12\x19\n" + + "\bpod_name\x18\x05 \x01(\tR\apodName\x12&\n" + + "\x03cpu\x18\x06 \x01(\v2\x14.agent.v1.CpuMetricsR\x03cpu\x12/\n" + + "\x06memory\x18\a \x01(\v2\x17.agent.v1.MemoryMetricsR\x06memory\x122\n" + + "\anetwork\x18\b \x01(\v2\x18.agent.v1.NetworkMetricsR\anetwork\x122\n" + + "\astorage\x18\t \x01(\v2\x18.agent.v1.StorageMetricsR\astorage\"\x91\x01\n" + + "\n" + + "CpuMetrics\x12-\n" + + "\x12request_millicores\x18\x04 \x01(\x04R\x11requestMillicores\x12)\n" + + "\x10limit_millicores\x18\x05 \x01(\x04R\x0flimitMillicores\x12)\n" + + "\x10usage_millicores\x18\x06 \x01(\x04R\x0fusageMillicores\"\x9e\x01\n" + + "\rMemoryMetrics\x12\x1b\n" + + "\trss_bytes\x18\x01 \x01(\x04R\brssBytes\x12*\n" + + "\x11page_faults_major\x18\x02 \x01(\x04R\x0fpageFaultsMajor\x12#\n" + + "\rrequest_bytes\x18\x03 \x01(\x04R\frequestBytes\x12\x1f\n" + + "\vlimit_bytes\x18\x04 \x01(\x04R\n" + + "limitBytes\"\xed\x01\n" + + "\x0eNetworkMetrics\x12\x1d\n" + + "\n" + + "bytes_sent\x18\x01 \x01(\x04R\tbytesSent\x12%\n" + + "\x0ebytes_received\x18\x02 \x01(\x04R\rbytesReceived\x12.\n" + + "\x13egress_public_bytes\x18\x03 \x01(\x04R\x11egressPublicBytes\x121\n" + + "\x15egress_cross_az_bytes\x18\x04 \x01(\x04R\x12egressCrossAzBytes\x122\n" + + "\x15egress_internal_bytes\x18\x05 \x01(\x04R\x13egressInternalBytes\"\xcf\x02\n" + + "\x11NetworkConnection\x12+\n" + + "\x03src\x18\x01 \x01(\v2\x19.agent.v1.NetworkEndpointR\x03src\x12+\n" + + "\x03dst\x18\x02 \x01(\v2\x19.agent.v1.NetworkEndpointR\x03dst\x12\x1a\n" + + "\bprotocol\x18\x03 \x01(\rR\bprotocol\x12\x1d\n" + + "\n" + + "bytes_sent\x18\x04 \x01(\x04R\tbytesSent\x12%\n" + + "\x0ebytes_received\x18\x05 \x01(\x04R\rbytesReceived\x12!\n" + + "\fegress_class\x18\x06 \x01(\tR\vegressClass\x12\x19\n" + + "\bdst_kind\x18\b \x01(\tR\adstKind\x12#\n" + + "\rservice_match\x18\t \x01(\tR\fserviceMatch\x12\x1b\n" + + "\tis_egress\x18\n" + + " \x01(\bR\bisEgress\"\xb6\x04\n" + + "\n" + + "NodeMetric\x12\x1b\n" + + "\tnode_name\x18\x01 \x01(\tR\bnodeName\x120\n" + + "\x14cpu_usage_millicores\x18\x02 \x01(\x04R\x12cpuUsageMillicores\x12,\n" + + "\x12memory_usage_bytes\x18\x03 \x01(\x04R\x10memoryUsageBytes\x126\n" + + "\x17capacity_cpu_millicores\x18\x04 \x01(\x04R\x15capacityCpuMillicores\x122\n" + + "\x15capacity_memory_bytes\x18\x05 \x01(\x04R\x13capacityMemoryBytes\x12<\n" + + "\x1aallocatable_cpu_millicores\x18\x06 \x01(\x04R\x18allocatableCpuMillicores\x128\n" + + "\x18allocatable_memory_bytes\x18\a \x01(\x04R\x16allocatableMemoryBytes\x128\n" + + "\x18requested_cpu_millicores\x18\b \x01(\x04R\x16requestedCpuMillicores\x124\n" + + "\x16requested_memory_bytes\x18\t \x01(\x04R\x14requestedMemoryBytes\x12#\n" + + "\rthrottling_ns\x18\n" + + " \x01(\x04R\fthrottlingNs\x122\n" + + "\anetwork\x18\v \x01(\v2\x18.agent.v1.NetworkMetricsR\anetwork\"\xf1\x01\n" + + "\x0fNetworkEndpoint\x12\x0e\n" + + "\x02ip\x18\x01 \x01(\tR\x02ip\x12\x1c\n" + + "\tnamespace\x18\x02 \x01(\tR\tnamespace\x12\x19\n" + + "\bpod_name\x18\x03 \x01(\tR\apodName\x12\x1b\n" + + "\tnode_name\x18\x04 \x01(\tR\bnodeName\x12+\n" + + "\x11availability_zone\x18\x05 \x01(\tR\x10availabilityZone\x120\n" + + "\bservices\x18\x06 \x03(\v2\x14.agent.v1.ServiceRefR\bservices\x12\x19\n" + + "\bdns_name\x18\a \x01(\tR\adnsName\">\n" + + "\n" + + "ServiceRef\x12\x1c\n" + + "\tnamespace\x18\x01 \x01(\tR\tnamespace\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\"\xb2\x01\n" + + "\x0eStorageMetrics\x12\x1d\n" + + "\n" + + "read_bytes\x18\x01 \x01(\x04R\treadBytes\x12\x1f\n" + + "\vwrite_bytes\x18\x02 \x01(\x04R\n" + + "writeBytes\x12\x19\n" + + "\bread_ops\x18\x03 \x01(\x04R\areadOps\x12\x1b\n" + + "\twrite_ops\x18\x04 \x01(\x04R\bwriteOps\x12(\n" + + "\x10total_latency_ns\x18\x05 \x01(\x04R\x0etotalLatencyNs2\xa1\x01\n" + + "\tCollector\x12I\n" + + "\rReportMetrics\x12\x1e.agent.v1.MetricsReportRequest\x1a\x18.agent.v1.ReportResponse\x12I\n" + + "\rReportNetwork\x12\x1e.agent.v1.NetworkReportRequest\x1a\x18.agent.v1.ReportResponseB7Z5clustercost-agent-k8s/internal/proto/agent/v1;agentv1b\x06proto3" + +var ( + file_agent_v1_agent_proto_rawDescOnce sync.Once + file_agent_v1_agent_proto_rawDescData []byte +) + +func file_agent_v1_agent_proto_rawDescGZIP() []byte { + file_agent_v1_agent_proto_rawDescOnce.Do(func() { + file_agent_v1_agent_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_agent_v1_agent_proto_rawDesc), len(file_agent_v1_agent_proto_rawDesc))) + }) + return file_agent_v1_agent_proto_rawDescData +} + +var file_agent_v1_agent_proto_msgTypes = make([]protoimpl.MessageInfo, 13) +var file_agent_v1_agent_proto_goTypes = []any{ + (*MetricsReportRequest)(nil), // 0: agent.v1.MetricsReportRequest + (*NetworkReportRequest)(nil), // 1: agent.v1.NetworkReportRequest + (*CompactNetworkConnection)(nil), // 2: agent.v1.CompactNetworkConnection + (*ReportResponse)(nil), // 3: agent.v1.ReportResponse + (*PodMetric)(nil), // 4: agent.v1.PodMetric + (*CpuMetrics)(nil), // 5: agent.v1.CpuMetrics + (*MemoryMetrics)(nil), // 6: agent.v1.MemoryMetrics + (*NetworkMetrics)(nil), // 7: agent.v1.NetworkMetrics + (*NetworkConnection)(nil), // 8: agent.v1.NetworkConnection + (*NodeMetric)(nil), // 9: agent.v1.NodeMetric + (*NetworkEndpoint)(nil), // 10: agent.v1.NetworkEndpoint + (*ServiceRef)(nil), // 11: agent.v1.ServiceRef + (*StorageMetrics)(nil), // 12: agent.v1.StorageMetrics +} +var file_agent_v1_agent_proto_depIdxs = []int32{ + 4, // 0: agent.v1.MetricsReportRequest.pods:type_name -> agent.v1.PodMetric + 9, // 1: agent.v1.MetricsReportRequest.nodes:type_name -> agent.v1.NodeMetric + 10, // 2: agent.v1.NetworkReportRequest.endpoints:type_name -> agent.v1.NetworkEndpoint + 2, // 3: agent.v1.NetworkReportRequest.compact_connections:type_name -> agent.v1.CompactNetworkConnection + 8, // 4: agent.v1.NetworkReportRequest.connections:type_name -> agent.v1.NetworkConnection + 4, // 5: agent.v1.NetworkReportRequest.pods:type_name -> agent.v1.PodMetric + 5, // 6: agent.v1.PodMetric.cpu:type_name -> agent.v1.CpuMetrics + 6, // 7: agent.v1.PodMetric.memory:type_name -> agent.v1.MemoryMetrics + 7, // 8: agent.v1.PodMetric.network:type_name -> agent.v1.NetworkMetrics + 12, // 9: agent.v1.PodMetric.storage:type_name -> agent.v1.StorageMetrics + 10, // 10: agent.v1.NetworkConnection.src:type_name -> agent.v1.NetworkEndpoint + 10, // 11: agent.v1.NetworkConnection.dst:type_name -> agent.v1.NetworkEndpoint + 7, // 12: agent.v1.NodeMetric.network:type_name -> agent.v1.NetworkMetrics + 11, // 13: agent.v1.NetworkEndpoint.services:type_name -> agent.v1.ServiceRef + 0, // 14: agent.v1.Collector.ReportMetrics:input_type -> agent.v1.MetricsReportRequest + 1, // 15: agent.v1.Collector.ReportNetwork:input_type -> agent.v1.NetworkReportRequest + 3, // 16: agent.v1.Collector.ReportMetrics:output_type -> agent.v1.ReportResponse + 3, // 17: agent.v1.Collector.ReportNetwork:output_type -> agent.v1.ReportResponse + 16, // [16:18] is the sub-list for method output_type + 14, // [14:16] is the sub-list for method input_type + 14, // [14:14] is the sub-list for extension type_name + 14, // [14:14] is the sub-list for extension extendee + 0, // [0:14] is the sub-list for field type_name +} + +func init() { file_agent_v1_agent_proto_init() } +func file_agent_v1_agent_proto_init() { + if File_agent_v1_agent_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_agent_v1_agent_proto_rawDesc), len(file_agent_v1_agent_proto_rawDesc)), + NumEnums: 0, + NumMessages: 13, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_agent_v1_agent_proto_goTypes, + DependencyIndexes: file_agent_v1_agent_proto_depIdxs, + MessageInfos: file_agent_v1_agent_proto_msgTypes, + }.Build() + File_agent_v1_agent_proto = out.File + file_agent_v1_agent_proto_goTypes = nil + file_agent_v1_agent_proto_depIdxs = nil +} diff --git a/internal/proto/agent/v1/agent.proto b/internal/proto/agent/v1/agent.proto new file mode 100644 index 0000000..af27b63 --- /dev/null +++ b/internal/proto/agent/v1/agent.proto @@ -0,0 +1,173 @@ +syntax = "proto3"; + +package agent.v1; + +option go_package = "clustercost-agent-k8s/internal/proto/agent/v1;agentv1"; + +service Collector { + // ReportMetrics sends a batch of resource metrics (Pod/Node) from the agent. + rpc ReportMetrics(MetricsReportRequest) returns (ReportResponse); + + // ReportNetwork sends detailed network connection data. + rpc ReportNetwork(NetworkReportRequest) returns (ReportResponse); +} + +message MetricsReportRequest { + string agent_id = 1; + string cluster_id = 2; + string node_name = 3; + string availability_zone = 4; + int64 timestamp_seconds = 5; + string region = 6; + string instance_type = 7; + + repeated PodMetric pods = 8; + repeated NodeMetric nodes = 9; +} + +message NetworkReportRequest { + string agent_id = 1; + string cluster_id = 2; + string node_name = 3; + string availability_zone = 4; + int64 timestamp_seconds = 5; + string region = 6; + string instance_type = 7; + + // Optimization: Dictionary Encoding + repeated NetworkEndpoint endpoints = 10; + repeated CompactNetworkConnection compact_connections = 11; + + // Deprecated: Use endpoints + compact_connections + repeated NetworkConnection connections = 8; + repeated PodMetric pods = 9; +} + +message CompactNetworkConnection { + uint32 src_index = 1; // Index into request.endpoints + uint32 dst_index = 2; // Index into request.endpoints + uint32 protocol = 3; + uint64 bytes_sent = 4; + uint64 bytes_received = 5; + string egress_class = 6; + string dst_kind = 8; + string service_match = 9; + bool is_egress = 10; +} + +message ReportResponse { + bool accepted = 1; + string error_message = 2; +} + +message PodMetric { + // Metadata Context + string pod_uid = 1; + string container_id = 2; + uint32 pid_tgid = 3; + + // Include namespace/pod name to help aggregator if K8s API is lagging, + // but strictly spec just says identifiers. + // "The agent must resolve destination IPs..." -> Agent does heavy lifting for network. + // Let's keep namespace/name as they are cheap and useful. + string namespace = 4; + string pod_name = 5; + + // Compute Performance + CpuMetrics cpu = 6; + MemoryMetrics memory = 7; + + // Cost-Aware Network + NetworkMetrics network = 8; + + // Storage I/O + StorageMetrics storage = 9; +} + +message CpuMetrics { + // K8s Requests (mCPU) + uint64 request_millicores = 4; + // K8s Limits (mCPU) + uint64 limit_millicores = 5; + // Usage (mCPU) + uint64 usage_millicores = 6; +} + +message MemoryMetrics { + // Resident Set Size (bytes) + uint64 rss_bytes = 1; + // Major page faults + uint64 page_faults_major = 2; + // K8s Requests (bytes) + uint64 request_bytes = 3; + // K8s Limits (bytes) + uint64 limit_bytes = 4; +} + +message NetworkMetrics { + // Throughput + uint64 bytes_sent = 1; + uint64 bytes_received = 2; + + // Traffic Categorization (Egress Analyzer) + uint64 egress_public_bytes = 3; + uint64 egress_cross_az_bytes = 4; + uint64 egress_internal_bytes = 5; +} + +message NetworkConnection { + NetworkEndpoint src = 1; + NetworkEndpoint dst = 2; + uint32 protocol = 3; + uint64 bytes_sent = 4; + uint64 bytes_received = 5; + string egress_class = 6; + string dst_kind = 8; + string service_match = 9; + bool is_egress = 10; +} + +message NodeMetric { + string node_name = 1; + uint64 cpu_usage_millicores = 2; + uint64 memory_usage_bytes = 3; + uint64 capacity_cpu_millicores = 4; + uint64 capacity_memory_bytes = 5; + uint64 allocatable_cpu_millicores = 6; + uint64 allocatable_memory_bytes = 7; + uint64 requested_cpu_millicores = 8; + uint64 requested_memory_bytes = 9; + // Total throttled CPU time from cgroup cpu.stat (ns). + uint64 throttling_ns = 10; + + // Cost-Aware Network (Host traffic) + NetworkMetrics network = 11; +} + +message NetworkEndpoint { + string ip = 1; + string namespace = 2; + string pod_name = 3; + string node_name = 4; + string availability_zone = 5; + repeated ServiceRef services = 6; + string dns_name = 7; +} + +message ServiceRef { + string namespace = 1; + string name = 2; +} + +message StorageMetrics { + // Throughput + uint64 read_bytes = 1; + uint64 write_bytes = 2; + + // IOPS + uint64 read_ops = 3; + uint64 write_ops = 4; + + // Latency + uint64 total_latency_ns = 5; +} diff --git a/internal/proto/agent/v1/agent_grpc.pb.go b/internal/proto/agent/v1/agent_grpc.pb.go new file mode 100644 index 0000000..6e3872b --- /dev/null +++ b/internal/proto/agent/v1/agent_grpc.pb.go @@ -0,0 +1,152 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.4.0 +// - protoc v4.25.3 +// source: agent/v1/agent.proto + +package agentv1 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.62.0 or later. +const _ = grpc.SupportPackageIsVersion8 + +const ( + Collector_ReportMetrics_FullMethodName = "/agent.v1.Collector/ReportMetrics" + Collector_ReportNetwork_FullMethodName = "/agent.v1.Collector/ReportNetwork" +) + +// CollectorClient is the client API for Collector service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type CollectorClient interface { + // ReportMetrics sends a batch of resource metrics (Pod/Node) from the agent. + ReportMetrics(ctx context.Context, in *MetricsReportRequest, opts ...grpc.CallOption) (*ReportResponse, error) + // ReportNetwork sends detailed network connection data. + ReportNetwork(ctx context.Context, in *NetworkReportRequest, opts ...grpc.CallOption) (*ReportResponse, error) +} + +type collectorClient struct { + cc grpc.ClientConnInterface +} + +func NewCollectorClient(cc grpc.ClientConnInterface) CollectorClient { + return &collectorClient{cc} +} + +func (c *collectorClient) ReportMetrics(ctx context.Context, in *MetricsReportRequest, opts ...grpc.CallOption) (*ReportResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ReportResponse) + err := c.cc.Invoke(ctx, Collector_ReportMetrics_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *collectorClient) ReportNetwork(ctx context.Context, in *NetworkReportRequest, opts ...grpc.CallOption) (*ReportResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ReportResponse) + err := c.cc.Invoke(ctx, Collector_ReportNetwork_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// CollectorServer is the server API for Collector service. +// All implementations must embed UnimplementedCollectorServer +// for forward compatibility +type CollectorServer interface { + // ReportMetrics sends a batch of resource metrics (Pod/Node) from the agent. + ReportMetrics(context.Context, *MetricsReportRequest) (*ReportResponse, error) + // ReportNetwork sends detailed network connection data. + ReportNetwork(context.Context, *NetworkReportRequest) (*ReportResponse, error) + mustEmbedUnimplementedCollectorServer() +} + +// UnimplementedCollectorServer must be embedded to have forward compatible implementations. +type UnimplementedCollectorServer struct { +} + +func (UnimplementedCollectorServer) ReportMetrics(context.Context, *MetricsReportRequest) (*ReportResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ReportMetrics not implemented") +} +func (UnimplementedCollectorServer) ReportNetwork(context.Context, *NetworkReportRequest) (*ReportResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ReportNetwork not implemented") +} +func (UnimplementedCollectorServer) mustEmbedUnimplementedCollectorServer() {} + +// UnsafeCollectorServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to CollectorServer will +// result in compilation errors. +type UnsafeCollectorServer interface { + mustEmbedUnimplementedCollectorServer() +} + +func RegisterCollectorServer(s grpc.ServiceRegistrar, srv CollectorServer) { + s.RegisterService(&Collector_ServiceDesc, srv) +} + +func _Collector_ReportMetrics_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MetricsReportRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CollectorServer).ReportMetrics(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Collector_ReportMetrics_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CollectorServer).ReportMetrics(ctx, req.(*MetricsReportRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Collector_ReportNetwork_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(NetworkReportRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CollectorServer).ReportNetwork(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Collector_ReportNetwork_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CollectorServer).ReportNetwork(ctx, req.(*NetworkReportRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// Collector_ServiceDesc is the grpc.ServiceDesc for Collector service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Collector_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "agent.v1.Collector", + HandlerType: (*CollectorServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "ReportMetrics", + Handler: _Collector_ReportMetrics_Handler, + }, + { + MethodName: "ReportNetwork", + Handler: _Collector_ReportNetwork_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "agent/v1/agent.proto", +} diff --git a/internal/store/mock_pricing_test.go b/internal/store/mock_pricing_test.go new file mode 100644 index 0000000..669f814 --- /dev/null +++ b/internal/store/mock_pricing_test.go @@ -0,0 +1,13 @@ +package store + +import ( + "context" +) + +// MockPricing implements pricing.Provider for testing +type MockPricing struct{} + +func (m *MockPricing) GetNodePrice(ctx context.Context, region, instanceType string) (float64, error) { + // Return dummy price of $1.00/hr + return 1.0, nil +} diff --git a/internal/store/pricing.go b/internal/store/pricing.go new file mode 100644 index 0000000..3d4e060 --- /dev/null +++ b/internal/store/pricing.go @@ -0,0 +1,95 @@ +package store + +import "context" + +// Pricing constants +const ( + // Egress costs (public internet) + CostEgressPublic = 0.09 // $0.09 per GB + CostEgressCrossAZ = 0.01 // $0.01 per GB + CostEgressInternal = 0.00 // Free +) + +// PricingProvider defines the interface for fetching node pricing. +type PricingProvider interface { + GetNodePrice(ctx context.Context, region, instanceType string) (float64, error) +} + +// PricingCatalog allows looking up node prices. +type PricingCatalog struct { + // Map instance type to hourly price + InstancePrices map[string]float64 + Provider PricingProvider +} + +// NewPricingCatalog returns a catalog with some default mocked pricing. +func NewPricingCatalog(provider PricingProvider) *PricingCatalog { + return &PricingCatalog{ + InstancePrices: map[string]float64{ + "t3.medium": 0.0416, + "t3.large": 0.0832, + "m5.large": 0.096, + "m5.xlarge": 0.192, + "c5.large": 0.085, + "r5.large": 0.126, + "default": 0.05, // Fallback + }, + Provider: provider, + } +} + +// GetTotalNodePrice returns the total hourly cost of a node. +func (pc *PricingCatalog) GetTotalNodePrice(ctx context.Context, region, instanceType string) float64 { + // Try Provider first + if pc.Provider != nil && instanceType != "" && region != "" { + price, err := pc.Provider.GetNodePrice(ctx, region, instanceType) + if err == nil && price > 0 { + pc.InstancePrices[instanceType] = price // Update cache + return price + } + } + + // Fallback to local cache + price, ok := pc.InstancePrices[instanceType] + if !ok { + price = pc.InstancePrices["default"] + } + return price +} + +// GetNodeResourcePrices calculates the cost per vCPU and per GB of RAM based on the instance type. +// Policy: 50% of instance cost allocated to CPU, 50% allocated to RAM. +func (pc *PricingCatalog) GetNodeResourcePrices(ctx context.Context, region, instanceType string, vCPUs int64, ramBytes int64) (cpuPricePerCore, ramPricePerGB float64) { + totalHourlyPrice := pc.GetTotalNodePrice(ctx, region, instanceType) + + if vCPUs <= 0 { + vCPUs = 2 // Default fallback + } + if ramBytes <= 0 { + ramBytes = 4 * 1024 * 1024 * 1024 // Default fallback 4GB + } + ramGB := float64(ramBytes) / (1024 * 1024 * 1024) + + // User Policy: "Divide precio de instancia entre dos, mitad cpu y mitad ram" + cpuPoolCost := totalHourlyPrice * 0.5 + ramPoolCost := totalHourlyPrice * 0.5 + + cpuPricePerCore = cpuPoolCost / float64(vCPUs) + ramPricePerGB = ramPoolCost / ramGB + + return cpuPricePerCore, ramPricePerGB +} + +// Estimated Cost Calculation +// This calculates the *rate* of spend based on current usage. +// cpuUsageCores: Number of cores currently being used (e.g. 0.5 for 500m) +// memUsageGB: Amount of RAM currently used in GB +// monthlyEgressGB: Estimated monthly egress based on current rate/counter +func calculateHourlyCost(cpuUsageCores, memUsageGB, egressPublicGB, egressCrossAZGB float64, cpuPrice, memPrice float64) float64 { + computeCost := (cpuUsageCores * cpuPrice) + memoryCost := (memUsageGB * memPrice) + + networkCost := (egressPublicGB * CostEgressPublic) + (egressCrossAZGB * CostEgressCrossAZ) + + return computeCost + memoryCost + networkCost +} diff --git a/internal/store/pricing_test.go b/internal/store/pricing_test.go new file mode 100644 index 0000000..7ab6916 --- /dev/null +++ b/internal/store/pricing_test.go @@ -0,0 +1,68 @@ +package store + +import ( + "context" + "testing" +) + +func TestPricingCatalog_GetNodeResourcePrices(t *testing.T) { + pc := NewPricingCatalog(nil) + + // Test case 1: m5.large (2 vCPU, 8GB RAM) + // Price: $0.096/hr + // CPU Pool: $0.048 -> Per Core: $0.024 + // RAM Pool: $0.048 -> Per GB: $0.006 + t.Run("m5.large split", func(t *testing.T) { + cpuPrice, ramPrice := pc.GetNodeResourcePrices(context.Background(), "us-east-1", "m5.large", 2, 8*1024*1024*1024) + + expectedCPU := 0.024 + expectedRAM := 0.006 + + if cpuPrice != expectedCPU { + t.Errorf("Expected CPU price %f, got %f", expectedCPU, cpuPrice) + } + if ramPrice != expectedRAM { + t.Errorf("Expected RAM price %f, got %f", expectedRAM, ramPrice) + } + }) + + // Test case 2: Default fallback + // Price: $0.05/hr + // Defaults: 2 vCPU, 4GB RAM + // CPU Pool: $0.025 -> Per Core: $0.0125 + // RAM Pool: $0.025 -> Per GB: $0.00625 + t.Run("Default split", func(t *testing.T) { + cpuPrice, ramPrice := pc.GetNodeResourcePrices(context.Background(), "", "unknown.type", 0, 0) + + expectedCPU := 0.0125 + expectedRAM := 0.00625 + + if cpuPrice != expectedCPU { + t.Errorf("Expected CPU price %f, got %f", expectedCPU, cpuPrice) + } + if ramPrice != expectedRAM { + t.Errorf("Expected RAM price %f, got %f", expectedRAM, ramPrice) + } + }) +} + +func TestCalculateHourlyCost(t *testing.T) { + // 2 vCPU * 0.05/2/2 = 0.025 + // 4 GB * 0.05/2/4 = 0.00625 + cpuPrice := 0.025 // per core + memPrice := 0.00625 // per GB + + // Usage: 1 core, 2 GB + // Network: 1 GB Public, 1 GB CrossAZ + // Cost = (1 * 0.025) + (2 * 0.00625) + (1 * 0.09) + (1 * 0.01) + // Cost = 0.025 + 0.0125 + 0.09 + 0.01 = 0.1375 + + t.Run("Includes Network Costs", func(t *testing.T) { + cost := calculateHourlyCost(1.0, 2.0, 1.0, 1.0, cpuPrice, memPrice) + expected := 0.1375 + + if cost != expected { + t.Errorf("Expected cost %f, got %f", expected, cost) + } + }) +} diff --git a/internal/store/store.go b/internal/store/store.go index e8d910c..9df7b58 100644 --- a/internal/store/store.go +++ b/internal/store/store.go @@ -1,21 +1,32 @@ package store import ( + "context" "errors" "sort" "strings" "sync" "time" - "github.com/clustercost/clustercost-dashboard/internal/agents" + "math" + "github.com/clustercost/clustercost-dashboard/internal/config" + "github.com/clustercost/clustercost-dashboard/internal/pricing" + agentv1 "github.com/clustercost/clustercost-dashboard/internal/proto/agent/v1" ) +func safeInt64(u uint64) int64 { + if u > math.MaxInt64 { + return math.MaxInt64 + } + return int64(u) +} + // ErrNoData indicates that the store has not ingested any data yet. var ErrNoData = errors.New("no data available") const hoursPerMonth = 24 * 30 -const datasetFreshThreshold = 2 * time.Minute + const agentOfflineThreshold = 5 * time.Minute var environments = []string{"production", "nonprod", "system", "unknown"} @@ -26,16 +37,24 @@ type Store struct { agentConfigs map[string]config.AgentConfig snapshots map[string]*AgentSnapshot recommendedAgentVersion string + + pricing *PricingCatalog } // AgentSnapshot contains the most recent data fetched for an agent. type AgentSnapshot struct { - Health *agents.HealthResponse - Namespaces *agents.NamespacesResponse - Nodes *agents.NodesResponse - Resources *agents.ResourcesResponse - LastScrape time.Time - LastError string + // Raw Report from the agent + // Raw Report from the agent + Report *agentv1.MetricsReportRequest + PreviousReport *agentv1.MetricsReportRequest + + // Network Report + Network *agentv1.NetworkReportRequest + PreviousNetwork *agentv1.NetworkReportRequest + + LastScrape time.Time + LastScrapeDur time.Duration // Duration since previous scrape used for rate calc + LastError string } // OverviewPayload matches the payload served by /api/cost/overview. @@ -73,8 +92,10 @@ type NamespaceSummary struct { HourlyCost float64 `json:"hourlyCost"` PodCount int `json:"podCount"` CPURequestMilli int64 `json:"cpuRequestMilli"` + CPULimitMilli int64 `json:"cpuLimitMilli"` MemoryRequestBytes int64 `json:"memoryRequestBytes"` CPUUsageMilli int64 `json:"cpuUsageMilli"` + CPUUsagePercent float64 `json:"cpuUsagePercent"` MemoryUsageBytes int64 `json:"memoryUsageBytes"` Labels map[string]string `json:"labels"` Environment string `json:"environment"` @@ -101,6 +122,12 @@ type NodeSummary struct { InstanceType string `json:"instanceType,omitempty"` Labels map[string]string `json:"labels"` Taints []string `json:"taints"` + // Network (Host Level) + NetTxBytes int64 `json:"netTxBytes"` + NetRxBytes int64 `json:"netRxBytes"` + EgressPublicBytes int64 `json:"egressPublicBytes"` + EgressCrossAZBytes int64 `json:"egressCrossAZBytes"` + EgressInternalBytes int64 `json:"egressInternalBytes"` } // NodeListResponse wraps paginated node results. @@ -126,6 +153,13 @@ type MemoryResource struct { EstimatedHourlyWasteCost float64 `json:"estimatedHourlyWasteCost"` } +// NetworkResource describes network usage metrics. +type NetworkResource struct { + TxBytesTotal int64 `json:"txBytesTotal"` + RxBytesTotal int64 `json:"rxBytesTotal"` + EgressCostHourly float64 `json:"egressCostHourly"` +} + // NamespaceWasteEntry highlights inefficient namespaces. type NamespaceWasteEntry struct { Namespace string `json:"namespace"` @@ -140,9 +174,49 @@ type ResourcesPayload struct { Timestamp time.Time `json:"timestamp"` CPU CPUResource `json:"cpu"` Memory MemoryResource `json:"memory"` + Network NetworkResource `json:"network"` NamespaceWaste []NamespaceWasteEntry `json:"namespaceWaste"` } +// NetworkEdge describes an aggregated network connection for topology graphs. +type NetworkEdge struct { + SrcNamespace string `json:"srcNamespace"` + SrcPodName string `json:"srcPodName"` + SrcNodeName string `json:"srcNodeName"` + SrcIP string `json:"srcIp"` + SrcDNSName string `json:"srcDnsName"` + SrcAZ string `json:"srcAvailabilityZone"` + DstNamespace string `json:"dstNamespace"` + DstPodName string `json:"dstPodName"` + DstNodeName string `json:"dstNodeName"` + DstIP string `json:"dstIp"` + DstDNSName string `json:"dstDnsName"` + DstAZ string `json:"dstAvailabilityZone"` + DstKind string `json:"dstKind"` + ServiceMatch string `json:"serviceMatch"` + DstServices string `json:"dstServices"` + Protocol int64 `json:"protocol"` + BytesSent int64 `json:"bytesSent"` + BytesReceived int64 `json:"bytesReceived"` + EgressCostUSD float64 `json:"egressCostUsd"` + ConnectionCount int64 `json:"connectionCount"` + FirstSeen int64 `json:"firstSeen"` + LastSeen int64 `json:"lastSeen"` +} + +// NetworkTopologyOptions controls topology queries. +type NetworkTopologyOptions struct { + ClusterID string + Namespace string + Namespaces []string + Start time.Time + End time.Time + Limit int + MinCostUSD float64 + MinBytes int64 + MinConnections int64 +} + // AgentDatasetHealth summarizes data availability per dataset. type AgentDatasetHealth struct { Namespaces string `json:"namespaces"` @@ -180,6 +254,8 @@ type AgentInfo struct { Status string `json:"status"` LastScrapeTime time.Time `json:"lastScrapeTime"` Error string `json:"error,omitempty"` + ClusterID string `json:"clusterId,omitempty"` + NodeName string `json:"nodeName,omitempty"` } // NamespaceFilter controls namespaces list filtering. @@ -197,25 +273,126 @@ type NodeFilter struct { Offset int } +// PodContext wraps a PodMetric with its location metadata. +type PodContext struct { + Pod *agentv1.PodMetric + ClusterID string + Region string + AZ string + InstanceType string +} + // New creates a store seeded with agent configurations. func New(cfgs []config.AgentConfig, recommendedAgentVersion string) *Store { agentConfigs := make(map[string]config.AgentConfig, len(cfgs)) for _, c := range cfgs { agentConfigs[c.Name] = c } + + // Initialize Static Pricing Provider + // Context is just placeholder for interface, static client doesn't need it + pricingClient, _ := pricing.NewAWSClient(context.Background()) + return &Store{ agentConfigs: agentConfigs, snapshots: make(map[string]*AgentSnapshot, len(cfgs)), recommendedAgentVersion: recommendedAgentVersion, + pricing: NewPricingCatalog(pricingClient), + } +} + +// PricingCatalog returns the pricing catalog used by the store. +func (s *Store) PricingCatalog() *PricingCatalog { + return s.pricing +} + +// UpdateMetrics stores the latest report for a given agent. +func (s *Store) UpdateMetrics(agentID string, req *agentv1.MetricsReportRequest) { + s.mu.Lock() + defer s.mu.Unlock() + + // Find existing to keep as previous + var prev *agentv1.MetricsReportRequest + var lastScrape time.Time + var existingNetwork *agentv1.NetworkReportRequest + var existingPrevNetwork *agentv1.NetworkReportRequest + + if existing, ok := s.snapshots[agentID]; ok { + prev = existing.Report + lastScrape = existing.LastScrape + existingNetwork = existing.Network + existingPrevNetwork = existing.PreviousNetwork + } + + now := time.Now().UTC() + dur := time.Since(lastScrape) + if lastScrape.IsZero() { + dur = 1 * time.Minute // default for first run + } + + s.snapshots[agentID] = &AgentSnapshot{ + Report: req, + PreviousReport: prev, + LastScrape: now, + LastScrapeDur: dur, + LastError: "", + Network: existingNetwork, + PreviousNetwork: existingPrevNetwork, } } -// Update stores the latest snapshot for a given agent. -func (s *Store) Update(name string, snapshot AgentSnapshot) { +// UpdateNetwork stores the latest network report for a given agent. +func (s *Store) UpdateNetwork(agentID string, req *agentv1.NetworkReportRequest) { s.mu.Lock() defer s.mu.Unlock() - copySnapshot := snapshot - s.snapshots[name] = ©Snapshot + + var prev *agentv1.NetworkReportRequest + if existing, ok := s.snapshots[agentID]; ok { + prev = existing.Network + } else { + // Create placeholder snapshot if metrics haven't arrived yet + s.snapshots[agentID] = &AgentSnapshot{ + LastScrape: time.Now().UTC(), + } + } + + snap := s.snapshots[agentID] + snap.PreviousNetwork = prev + snap.Network = req +} + +// GetAllPods returns all pods from all agents with their context. +func (s *Store) GetAllPods() []PodContext { + s.mu.RLock() + defer s.mu.RUnlock() + + var pods []PodContext + for agentID, snap := range s.snapshots { + if snap == nil || snap.Report == nil { + continue + } + + region := snap.Report.Region + if region == "" { + // Fallback to config or default if missing in report + if cfg, ok := s.agentConfigs[agentID]; ok && cfg.Region != "" { + region = cfg.Region + } else { + region = "us-east-1" + } + } + + for _, pod := range snap.Report.Pods { + pods = append(pods, PodContext{ + Pod: pod, + ClusterID: snap.Report.ClusterId, + Region: region, + AZ: snap.Report.AvailabilityZone, + InstanceType: snap.Report.InstanceType, + }) + } + } + return pods } // Overview aggregates cluster level information for the overview dashboard. @@ -417,46 +594,26 @@ func (s *Store) Resources() (ResourcesPayload, error) { s.mu.RLock() defer s.mu.RUnlock() - resources, resourcesTime := s.latestResourcesLocked() + // Recalculate everything from snapshots + var cpuUsage, cpuRequest, memUsage, memRequest int64 + var estimatedNodeCost float64 namespaces, nsErr := s.aggregateNamespacesLocked() if nsErr != nil && nsErr != ErrNoData { return ResourcesPayload{}, nsErr } - if nsErr == ErrNoData { - namespaces = nil - } - - if resources == nil && len(namespaces) == 0 { - return ResourcesPayload{}, ErrNoData - } - - var cpuUsage, cpuRequest, memUsage, memRequest int64 - var estimatedNodeCost float64 - if resources != nil { - cpuUsage = resources.Snapshot.CPUUsageMilliTotal - cpuRequest = resources.Snapshot.CPURequestMilliTotal - memUsage = resources.Snapshot.MemoryUsageBytesTotal - memRequest = resources.Snapshot.MemoryRequestBytesTotal - estimatedNodeCost = resources.Snapshot.TotalNodeHourlyCost + for _, ns := range namespaces { + cpuUsage += ns.CPUUsageMilli + cpuRequest += ns.CPURequestMilli + memUsage += ns.MemoryUsageBytes + memRequest += ns.MemoryRequestBytes } - if cpuUsage == 0 && cpuRequest == 0 && len(namespaces) > 0 { - for _, ns := range namespaces { - cpuUsage += ns.CPUUsageMilli - cpuRequest += ns.CPURequestMilli - } - } - if memUsage == 0 && memRequest == 0 && len(namespaces) > 0 { - for _, ns := range namespaces { - memUsage += ns.MemoryUsageBytes - memRequest += ns.MemoryRequestBytes - } - } + estimatedNodeCost = s.sumNodeHourlyCostLocked() - if estimatedNodeCost == 0 { - estimatedNodeCost = s.sumNodeHourlyCostLocked() + if cpuUsage == 0 && cpuRequest == 0 && estimatedNodeCost == 0 { + return ResourcesPayload{}, ErrNoData } cpuEfficiency := percent(float64(cpuUsage), float64(cpuRequest)) @@ -467,10 +624,7 @@ func (s *Store) Resources() (ResourcesPayload, error) { namespaceWaste := buildNamespaceWaste(namespaces) - timestamp := resourcesTime - if timestamp.IsZero() { - timestamp = s.latestScrapeLocked() - } + timestamp := s.latestScrapeLocked() if timestamp.IsZero() { timestamp = time.Now().UTC() } @@ -503,26 +657,21 @@ func (s *Store) AgentStatus() (AgentStatusPayload, error) { return AgentStatusPayload{}, ErrNoData } - nsTimestamp := s.latestNamespacesTimestampLocked() - nodeTimestamp := s.latestNodesTimestampLocked() - resourcesSnapshot, resourcesTimestamp := s.latestResourcesLocked() + // Since we stream everything in one report now, if we have a scrape, we have all data. + statusOk := "ok" + if time.Since(lastSync) > agentOfflineThreshold { + statusOk = "stale" + } datasets := AgentDatasetHealth{ - Namespaces: datasetStatus(!nsTimestamp.IsZero(), nsTimestamp, lastSync), - Nodes: datasetStatus(!nodeTimestamp.IsZero(), nodeTimestamp, lastSync), - Resources: datasetStatus(resourcesSnapshot != nil, resourcesTimestamp, lastSync), - } - - status := "offline" - allOK := datasets.Namespaces == "ok" && datasets.Nodes == "ok" && datasets.Resources == "ok" - if !lastSync.IsZero() { - if time.Since(lastSync) > agentOfflineThreshold { - status = "offline" - } else if allOK { - status = "connected" - } else { - status = "partial" - } + Namespaces: statusOk, + Nodes: statusOk, + Resources: statusOk, + } + + status := "connected" + if time.Since(lastSync) > agentOfflineThreshold { + status = "offline" } meta := s.latestAgentMetadataLocked() @@ -530,8 +679,10 @@ func (s *Store) AgentStatus() (AgentStatusPayload, error) { updateAvailable := s.recommendedAgentVersion != "" && version != "" && version != s.recommendedAgentVersion var nodeCount int - if nodes, err := s.aggregateNodesLocked(); err == nil { - nodeCount = len(nodes) + for _, snap := range s.snapshots { + if snap != nil && snap.Report != nil { + nodeCount++ + } } return AgentStatusPayload{ @@ -552,30 +703,41 @@ func (s *Store) Agents() []AgentInfo { s.mu.RLock() defer s.mu.RUnlock() - result := make([]AgentInfo, 0, len(s.agentConfigs)) + agentMap := make(map[string]AgentInfo) for name, cfg := range s.agentConfigs { - snapshot := s.snapshots[name] - info := AgentInfo{ - Name: name, - BaseURL: cfg.BaseURL, - Status: "unknown", + agentMap[name] = AgentInfo{Name: name, BaseURL: cfg.BaseURL, Status: "unknown"} + } + + for id, snapshot := range s.snapshots { + info, exists := agentMap[id] + if !exists { + info = AgentInfo{Name: id, Status: "unknown"} } if snapshot != nil { if snapshot.LastError != "" { info.Status = "error" info.Error = snapshot.LastError - } else if snapshot.Health != nil { - info.Status = snapshot.Health.Status } else { - info.Status = "stale" + if time.Since(snapshot.LastScrape) < agentOfflineThreshold { + info.Status = "ok" + } else { + info.Status = "offline" + } } info.LastScrapeTime = snapshot.LastScrape + if snapshot.Report != nil { + info.ClusterID = snapshot.Report.ClusterId + info.NodeName = snapshot.Report.NodeName + } } + agentMap[id] = info + } + + result := make([]AgentInfo, 0, len(agentMap)) + for _, info := range agentMap { result = append(result, info) } - sort.Slice(result, func(i, j int) bool { - return result[i].Name < result[j].Name - }) + sort.Slice(result, func(i, j int) bool { return result[i].Name < result[j].Name }) return result } @@ -596,13 +758,14 @@ func (s *Store) ClusterMetadata() (ClusterMetadata, error) { if meta.ClusterName == "" { meta.ClusterName = meta.ClusterID } + // ClusterName removed if meta.ClusterType == "" { meta.ClusterType = meta.ClusterID } cluster := ClusterMetadata{ ID: meta.ClusterID, - Name: meta.ClusterName, + Name: "Cluster", // snap.Report.ClusterName removed Type: meta.ClusterType, Region: meta.Region, Version: meta.Version, @@ -640,20 +803,23 @@ type agentMetadata struct { func (s *Store) latestAgentMetadataLocked() agentMetadata { var meta agentMetadata for _, snap := range s.snapshots { - if snap == nil || snap.Health == nil { + if snap == nil || snap.Report == nil { continue } - ts := snap.Health.Timestamp - if ts.IsZero() { - ts = snap.LastScrape + ts := snap.LastScrape + // Prefer Region from report, fallback to AZ + region := snap.Report.Region + if region == "" { + region = snap.Report.AvailabilityZone } + if meta.Timestamp.IsZero() || ts.After(meta.Timestamp) { meta = agentMetadata{ - ClusterID: snap.Health.ClusterID, - ClusterName: snap.Health.ClusterName, - ClusterType: snap.Health.ClusterType, - Region: snap.Health.Region, - Version: snap.Health.Version, + ClusterID: snap.Report.ClusterId, + ClusterName: "Cluster", + ClusterType: "k8s", + Region: region, + Version: "v2.0", Timestamp: ts, } } @@ -667,94 +833,19 @@ func (s *Store) latestAgentMetadataLocked() agentMetadata { return meta } -func (s *Store) latestResourcesLocked() (*agents.ResourcesResponse, time.Time) { - var latest *agents.ResourcesResponse - var ts time.Time - for _, snap := range s.snapshots { - if snap == nil || snap.Resources == nil { - continue - } - cur := snap.Resources.Timestamp - if cur.IsZero() { - cur = snap.LastScrape - } - if cur.After(ts) { - latest = snap.Resources - ts = cur - } - } - return latest, ts -} +// Removed latestResourcesLocked as it returned old response type +// Logic moved to Resources() func (s *Store) latestDataTimestampLocked() time.Time { - var ts time.Time - for _, snap := range s.snapshots { - if snap == nil { - continue - } - if snap.Namespaces != nil { - current := snap.Namespaces.Timestamp - if current.IsZero() { - current = snap.LastScrape - } - if current.After(ts) { - ts = current - } - } - if snap.Nodes != nil { - current := snap.Nodes.Timestamp - if current.IsZero() { - current = snap.LastScrape - } - if current.After(ts) { - ts = current - } - } - if snap.Resources != nil { - current := snap.Resources.Timestamp - if current.IsZero() { - current = snap.LastScrape - } - if current.After(ts) { - ts = current - } - } - } - return ts + return s.latestScrapeLocked() } func (s *Store) latestNamespacesTimestampLocked() time.Time { - var ts time.Time - for _, snap := range s.snapshots { - if snap == nil || snap.Namespaces == nil { - continue - } - current := snap.Namespaces.Timestamp - if current.IsZero() { - current = snap.LastScrape - } - if current.After(ts) { - ts = current - } - } - return ts + return s.latestScrapeLocked() } func (s *Store) latestNodesTimestampLocked() time.Time { - var ts time.Time - for _, snap := range s.snapshots { - if snap == nil || snap.Nodes == nil { - continue - } - current := snap.Nodes.Timestamp - if current.IsZero() { - current = snap.LastScrape - } - if current.After(ts) { - ts = current - } - } - return ts + return s.latestScrapeLocked() } func (s *Store) aggregateNamespacesLocked() (map[string]*NamespaceSummary, error) { @@ -762,79 +853,172 @@ func (s *Store) aggregateNamespacesLocked() (map[string]*NamespaceSummary, error haveData := false for _, snap := range s.snapshots { - if snap == nil || snap.Namespaces == nil || len(snap.Namespaces.Items) == 0 { + if snap == nil || snap.Report == nil { continue } - haveData = true - for _, ns := range snap.Namespaces.Items { - entry, ok := collector[ns.Namespace] + + // Determine node price for this snapshot + // We don't have node capacity in V2 Report (cpu_allocatable presumably in node metrics if sent?) + // ReportRequest does NOT have node capacity. + // For the 50/50 split math, we need total capacity (vCPUs, RAM bytes). + // Currently V2 proto does NOT send capacity. + // We have to assume a default capacity or look it up if we knew the instance type. + // ReportRequest doesn't have InstanceType either? + // Wait, user provided proto v2 only has: agent_id, cluster_id, node_name, az, pods. + // It lacks InstanceType and NodeCapacity. + // PROPOSAL: We must infer or assume defaults until agent sends metadata. + // Using "m5.large" proxies (2 vCPU, 8GB) for calculation if unknown. + + // TODO: Agent V2 should send Node Metadata (InstanceType, Capacity) for accurate pricing. + // For now, we use a default "standard" node. + // Region/AZ: check meta + region := snap.Report.AvailabilityZone + if region == "" { + region = "us-east-1" + } + cpuPrice, memPrice := s.pricing.GetNodeResourcePrices(context.Background(), region, "default", 2, 8*1024*1024*1024) + + for _, pod := range snap.Report.Pods { + haveData = true + namespace := strings.TrimSpace(pod.Namespace) + if namespace == "" { + continue + } + + entry, ok := collector[namespace] if !ok { entry = &NamespaceSummary{ - Namespace: ns.Namespace, - Environment: valueOrDefault(ns.Environment, "unknown"), - Labels: copyLabels(ns.Labels), + Namespace: namespace, + Labels: make(map[string]string), + Environment: "production", } - collector[ns.Namespace] = entry + collector[namespace] = entry } - entry.HourlyCost += ns.HourlyCost - entry.PodCount += ns.PodCount - entry.CPURequestMilli += ns.CPURequestMilli - entry.MemoryRequestBytes += ns.MemoryRequestBytes - entry.CPUUsageMilli += ns.CPUUsageMilli - entry.MemoryUsageBytes += ns.MemoryUsageBytes - if len(entry.Labels) == 0 { - entry.Labels = copyLabels(ns.Labels) + + // Aggregate Costs + memUsageBytes := safeInt64(0) + if pod.Memory != nil { + memUsageBytes = safeInt64(pod.Memory.RssBytes) + } + memGB := float64(memUsageBytes) / (1024 * 1024 * 1024) + + // CPU Usage (Cores) - provided as millicores in the report + cpuUsageCores := 0.0 + if pod.Cpu != nil { + cpuUsageCores = float64(pod.Cpu.UsageMillicores) / 1000.0 } - if entry.Environment == "" { - entry.Environment = valueOrDefault(ns.Environment, "unknown") + + // Network Cost (Egress) - Simplified for MVP + egressPublicGB := 0.0 + egressCrossAZGB := 0.0 + + // Calculate Total Hourly Cost Rate + hourCost := calculateHourlyCost(cpuUsageCores, memGB, egressPublicGB, egressCrossAZGB, cpuPrice, memPrice) + + entry.HourlyCost += hourCost + entry.MemoryUsageBytes += memUsageBytes + if pod.Cpu != nil { + entry.CPUUsageMilli += safeInt64(pod.Cpu.UsageMillicores) } + if pod.Cpu != nil { + entry.CPURequestMilli += safeInt64(pod.Cpu.RequestMillicores) + entry.CPULimitMilli += safeInt64(pod.Cpu.LimitMillicores) + } + if pod.Memory != nil { + entry.MemoryRequestBytes += safeInt64(pod.Memory.RequestBytes) + } + entry.PodCount++ + } + } + + // Post-processing: Calculate Percentages based on Totals + for _, ns := range collector { + // Priority: Limit > Request > Node Capacity (Estimate) + denominator := float64(ns.CPULimitMilli) + if denominator == 0 { + denominator = float64(ns.CPURequestMilli) + } + + // If still 0, try to estimate from node capacity? + // Since we don't have per-namespace node binding easily accessible here (pods are mixed), + // we skip Node Capacity fallback for Namespace-level % to avoid confusion. Checks against Request are standard efficiency. + // NOTE: User prompt mentioned "fallback to Node Capacity" for *Pod* calculation. + // aggregated, it's safer to stick to configured resources. + + if denominator > 0 { + ns.CPUUsagePercent = (float64(ns.CPUUsageMilli) / denominator) * 100 + } else { + // Last resort: If usage > 0 but no limit/request, cap at 100? Or leave 0? + // If we have usage but no request, it's infinite efficiency or undefined. + // Let's leave it 0 or set to computed "share of cluster" elsewhere. + // For now, 0 logic is consistent if "unbounded". + ns.CPUUsagePercent = 0 } } if !haveData { return nil, ErrNoData } - return collector, nil } func (s *Store) aggregateNodesLocked() (map[string]*NodeSummary, error) { - type nodeEntry struct { - node *NodeSummary - lastUpdated time.Time - } - - collector := make(map[string]nodeEntry) + nodes := make(map[string]*NodeSummary) haveData := false for _, snap := range s.snapshots { - if snap == nil || snap.Nodes == nil || len(snap.Nodes.Items) == 0 { + if snap == nil || snap.Report == nil { continue } haveData = true - for _, node := range snap.Nodes.Items { - current := nodeEntry{} - existing, ok := collector[node.NodeName] - if ok { - current = existing + + // Iterate over all nodes reported by this agent + for _, n := range snap.Report.Nodes { + if n == nil || n.NodeName == "" { + continue } - if !ok || snap.LastScrape.After(current.lastUpdated) { - current.node = &NodeSummary{ - NodeName: node.NodeName, - HourlyCost: node.HourlyCost, - CPUUsagePercent: node.CPUUsagePercent, - MemoryUsagePercent: node.MemoryUsagePercent, - CPUAllocatableMilli: node.CPUAllocatableMilli, - MemoryAllocatableBytes: node.MemoryAllocatableBytes, - PodCount: node.PodCount, - Status: node.Status, - IsUnderPressure: node.IsUnderPressure, - InstanceType: node.InstanceType, - Labels: copyLabels(node.Labels), - Taints: copyStrings(node.Taints), + name := n.NodeName + + entry, ok := nodes[name] + if !ok { + entry = &NodeSummary{ + NodeName: name, + Labels: make(map[string]string), + Status: "Ready", + InstanceType: "default", // placeholder + CPUAllocatableMilli: safeInt64(n.AllocatableCpuMillicores), + MemoryAllocatableBytes: safeInt64(n.AllocatableMemoryBytes), } - current.lastUpdated = snap.LastScrape - collector[node.NodeName] = current + nodes[name] = entry + } + + // Capture metrics + if n.AllocatableCpuMillicores > 0 { + entry.CPUUsagePercent = (float64(n.CpuUsageMillicores) / float64(n.AllocatableCpuMillicores)) * 100 + } + if n.AllocatableMemoryBytes > 0 { + entry.MemoryUsagePercent = (float64(n.MemoryUsageBytes) / float64(n.AllocatableMemoryBytes)) * 100 + } + + // Network (Host) + if n.Network != nil { + entry.NetTxBytes = safeInt64(n.Network.BytesSent) + entry.NetRxBytes = safeInt64(n.Network.BytesReceived) + entry.EgressPublicBytes = safeInt64(n.Network.EgressPublicBytes) + entry.EgressCrossAZBytes = safeInt64(n.Network.EgressCrossAzBytes) + entry.EgressInternalBytes = safeInt64(n.Network.EgressInternalBytes) + } + + // Cost calculation (simplified for now, using hardcoded price or placeholder) + // Ideally we lookup price by InstanceType/Zone from labels if available + // For now, assume $0.10/hr + entry.HourlyCost = 0.10 + + // Count pods logic: + // Assuming Agent runs as DaemonSet, all pods in this report belong to the agent's node. + // The agent's node is specified in snap.Report.NodeName. + if n.NodeName == snap.Report.NodeName { + entry.PodCount = len(snap.Report.Pods) } } } @@ -842,23 +1026,17 @@ func (s *Store) aggregateNodesLocked() (map[string]*NodeSummary, error) { if !haveData { return nil, ErrNoData } - - result := make(map[string]*NodeSummary, len(collector)) - for name, entry := range collector { - result[name] = entry.node - } - return result, nil + return nodes, nil } func (s *Store) sumNodeHourlyCostLocked() float64 { - total := 0.0 - for _, snap := range s.snapshots { - if snap == nil || snap.Nodes == nil { - continue - } - for _, node := range snap.Nodes.Items { - total += node.HourlyCost - } + nodes, err := s.aggregateNodesLocked() + if err != nil { + return 0 + } + var total float64 + for _, n := range nodes { + total += n.HourlyCost } return total } @@ -993,26 +1171,6 @@ func clampFloat(value, min, max float64) float64 { return value } -func copyLabels(in map[string]string) map[string]string { - if len(in) == 0 { - return map[string]string{} - } - out := make(map[string]string, len(in)) - for k, v := range in { - out[k] = v - } - return out -} - -func copyStrings(in []string) []string { - if len(in) == 0 { - return []string{} - } - out := make([]string, len(in)) - copy(out, in) - return out -} - func environmentMatches(filter, env string) bool { if filter == "" || filter == "all" { return true @@ -1033,20 +1191,3 @@ func maxFloat(a, b float64) float64 { } return b } - -func datasetStatus(hasData bool, timestamp, fallback time.Time) string { - if !hasData { - return "missing" - } - effective := timestamp - if effective.IsZero() { - effective = fallback - } - if effective.IsZero() { - return "partial" - } - if time.Since(effective) > datasetFreshThreshold { - return "partial" - } - return "ok" -} diff --git a/internal/store/store_test.go b/internal/store/store_test.go index 26cf32e..7702b7e 100644 --- a/internal/store/store_test.go +++ b/internal/store/store_test.go @@ -2,41 +2,37 @@ package store import ( "testing" - "time" - "github.com/clustercost/clustercost-dashboard/internal/agents" "github.com/clustercost/clustercost-dashboard/internal/config" + agentv1 "github.com/clustercost/clustercost-dashboard/internal/proto/agent/v1" ) func newTestStore() *Store { cfgs := []config.AgentConfig{ {Name: "test-agent", BaseURL: "http://example.com", Type: "k8s"}, } - return New(cfgs, "v1.0.0") + s := New(cfgs, "v1.0.0") + // Inject Mock Pricing + s.pricing = NewPricingCatalog(&MockPricing{}) + return s } func TestClusterMetadataReturnsLatestSnapshot(t *testing.T) { s := newTestStore() - now := time.Now().UTC() - s.Update("test-agent", AgentSnapshot{ - LastScrape: now, - Health: &agents.HealthResponse{ - Status: "ok", - ClusterID: "cluster-1", - ClusterName: "Cluster One", - ClusterType: "k8s", - Region: "us-east-1", - Version: "dev", - Timestamp: now, - }, + s.UpdateMetrics("test-agent", &agentv1.MetricsReportRequest{ + AgentId: "test-agent", + ClusterId: "cluster-1", + // ClusterName removed + AvailabilityZone: "us-east-1", // Using AZ as Region proxy + Pods: []*agentv1.PodMetric{}, // Changed from Snapshot }) meta, err := s.ClusterMetadata() if err != nil { t.Fatalf("ClusterMetadata returned error: %v", err) } - if meta.Name != "Cluster One" { - t.Fatalf("expected cluster name to be preserved, got %q", meta.Name) + if meta.Name != "Cluster" { + t.Fatalf("expected cluster name Cluster, got %q", meta.Name) } if meta.Type != "k8s" { t.Fatalf("expected cluster type k8s, got %q", meta.Type) @@ -44,8 +40,8 @@ func TestClusterMetadataReturnsLatestSnapshot(t *testing.T) { if meta.Region != "us-east-1" { t.Fatalf("expected region us-east-1, got %q", meta.Region) } - if meta.Version != "dev" { - t.Fatalf("expected version dev, got %q", meta.Version) + if meta.Version != "v2.0" { + t.Fatalf("expected version v2.0, got %q", meta.Version) } if meta.Timestamp.IsZero() { t.Fatal("expected metadata timestamp to be set") @@ -54,31 +50,19 @@ func TestClusterMetadataReturnsLatestSnapshot(t *testing.T) { func TestAgentStatusConnectedWhenDataFresh(t *testing.T) { s := newTestStore() - now := time.Now().UTC() - s.Update("test-agent", AgentSnapshot{ - LastScrape: now, - Health: &agents.HealthResponse{ - Status: "ok", - ClusterID: "cluster-2", - ClusterName: "Cluster Two", - ClusterType: "k8s", - Region: "us-west-2", - Version: "dev", - Timestamp: now, - }, - Namespaces: &agents.NamespacesResponse{ - Timestamp: now, - }, - Nodes: &agents.NodesResponse{ - Timestamp: now, - Items: []agents.NodeCost{ - {NodeName: "node-1"}, + s.UpdateMetrics("test-agent", &agentv1.MetricsReportRequest{ + AgentId: "test-agent", + ClusterId: "cluster-2", + NodeName: "node-1", + AvailabilityZone: "us-west-2", + Pods: []*agentv1.PodMetric{ + { + Namespace: "default", + PodName: "pod-1", + Memory: &agentv1.MemoryMetrics{RssBytes: 1024 * 1024 * 100}, }, }, - Resources: &agents.ResourcesResponse{ - Timestamp: now, - }, }) status, err := s.AgentStatus() @@ -88,8 +72,8 @@ func TestAgentStatusConnectedWhenDataFresh(t *testing.T) { if status.Status != "connected" { t.Fatalf("expected status connected, got %q", status.Status) } - if status.ClusterName != "Cluster Two" { - t.Fatalf("expected cluster name Cluster Two, got %q", status.ClusterName) + if status.ClusterName != "Cluster" { + t.Fatalf("expected cluster name Cluster, got %q", status.ClusterName) } if status.ClusterType != "k8s" { t.Fatalf("expected cluster type k8s, got %q", status.ClusterType) @@ -104,3 +88,63 @@ func TestAgentStatusConnectedWhenDataFresh(t *testing.T) { t.Fatalf("expected all datasets to be ok, got %+v", status.Datasets) } } + +func TestCPUUsageCalculation(t *testing.T) { + s := newTestStore() + agentID := "test-agent" + + // 1. Initial Report (Baseline) + s.UpdateMetrics(agentID, &agentv1.MetricsReportRequest{ + AgentId: agentID, + ClusterId: "cluster-1", + NodeName: "node-1", + TimestampSeconds: 1000, + Nodes: []*agentv1.NodeMetric{ + {NodeName: "node-1", CapacityCpuMillicores: 2000}, // 2 Cores + }, + Pods: []*agentv1.PodMetric{ + { + PodUid: "pod-1", + Namespace: "default", + Cpu: &agentv1.CpuMetrics{UsageMillicores: 250}, // 0.25 cores + }, + }, + }) + + // 2. Second Report (usage 500m) + // % = 0.5 / 2.0 = 25% + s.UpdateMetrics(agentID, &agentv1.MetricsReportRequest{ + AgentId: agentID, + ClusterId: "cluster-1", + NodeName: "node-1", + TimestampSeconds: 1010, // +10s + Nodes: []*agentv1.NodeMetric{ + {NodeName: "node-1", CapacityCpuMillicores: 2000}, + }, + Pods: []*agentv1.PodMetric{ + { + PodUid: "pod-1", + Namespace: "default", + Cpu: &agentv1.CpuMetrics{ + UsageMillicores: 500, + LimitMillicores: 2000, // 2 Cores + }, + }, + }, + }) + + summary, err := s.NamespaceDetail("default") + if err != nil { + t.Fatalf("NamespaceDetail failed: %v", err) + } + + // Milli = 500 + if summary.CPUUsageMilli != 500 { + t.Errorf("expected 500m CPU usage, got %d", summary.CPUUsageMilli) + } + + // Percent = (500 / 2000) * 100 = 25% + if summary.CPUUsagePercent != 25.0 { + t.Errorf("expected 25.0 percent CPU usage, got %f", summary.CPUUsagePercent) + } +} diff --git a/internal/vm/client.go b/internal/vm/client.go new file mode 100644 index 0000000..91a7b8a --- /dev/null +++ b/internal/vm/client.go @@ -0,0 +1,402 @@ +package vm + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "log" + "net/http" + "net/url" + "path" + "sort" + "strconv" + "strings" + "sync" + "time" + + "github.com/clustercost/clustercost-dashboard/internal/config" +) + +// ErrNoData indicates that VictoriaMetrics returned no usable data. +var ErrNoData = errors.New("no data available") + +const ( + queryPath = "/api/v1/query" + datasetFreshThreshold = 2 * time.Minute + agentOfflineThreshold = 5 * time.Minute + defaultQueryTimeout = 5 * time.Second + defaultQueryCacheTTL = 5 * time.Second +) + +// Client queries VictoriaMetrics for dashboard data. +type Client struct { + baseURL string + lookback time.Duration + recommendedAgentVersion string + agents []config.AgentConfig + httpClient *http.Client + authToken string + username string + password string + cacheTTL time.Duration + cacheMu sync.Mutex + cache map[string]cachedQuery +} + +type cachedQuery struct { + expires time.Time + samples []sample +} + +// NewClient creates a VictoriaMetrics query client. +func NewClient(cfg config.Config) (*Client, error) { + if cfg.VictoriaMetricsURL == "" { + return nil, fmt.Errorf("victoria metrics url is required") + } + + base, err := buildQueryURL(cfg.VictoriaMetricsURL) + if err != nil { + return nil, err + } + + timeout := cfg.VictoriaMetricsTimeout + if timeout <= 0 { + timeout = defaultQueryTimeout + } + + lookback := cfg.VictoriaMetricsLookback + if lookback <= 0 { + lookback = 24 * time.Hour + } + + c := &Client{ + baseURL: base, + lookback: lookback, + recommendedAgentVersion: cfg.RecommendedAgentVersion, + agents: cfg.Agents, + httpClient: &http.Client{Timeout: timeout}, + authToken: cfg.VictoriaMetricsToken, + username: cfg.VictoriaMetricsUsername, + password: cfg.VictoriaMetricsPassword, + cacheTTL: defaultQueryCacheTTL, + cache: make(map[string]cachedQuery), + } + + go func() { + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + if err := c.Ping(ctx); err != nil { + log.Printf("[VictoriaMetrics] WARN: Failed initial connection check to %s: %v", base, err) + } else { + log.Printf("[VictoriaMetrics] Successfully connected to %s", base) + } + }() + + return c, nil +} + +// Ping checks connectivity to VictoriaMetrics. +func (c *Client) Ping(ctx context.Context) error { + _, err := c.query(ctx, "1") + return err +} + +func buildQueryURL(base string) (string, error) { + parsed, err := url.Parse(base) + if err != nil { + return "", fmt.Errorf("invalid victoria metrics url: %w", err) + } + if parsed.Scheme == "" { + return "", fmt.Errorf("victoria metrics url missing scheme: %s", base) + } + parsed.Path = path.Join(parsed.Path, queryPath) + return parsed.String(), nil +} + +type sample struct { + labels map[string]string + value float64 + timestamp time.Time +} + +type vmResponse struct { + Status string `json:"status"` + Data struct { + ResultType string `json:"resultType"` + Result []struct { + Metric map[string]string `json:"metric"` + Value []any `json:"value"` + } `json:"result"` + } `json:"data"` + Error string `json:"error"` +} + +func (c *Client) query(ctx context.Context, expr string) ([]sample, error) { + if cached, ok := c.loadCached(expr); ok { + return cached, nil + } + + u, err := url.Parse(c.baseURL) + if err != nil { + return nil, fmt.Errorf("parse query url: %w", err) + } + q := u.Query() + q.Set("query", expr) + u.RawQuery = q.Encode() + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil) + if err != nil { + return nil, fmt.Errorf("build request: %w", err) + } + req.Header.Set("Accept", "application/json") + + if c.authToken != "" { + req.Header.Set("Authorization", "Bearer "+c.authToken) + } else if c.username != "" || c.password != "" { + req.SetBasicAuth(c.username, c.password) + } + + resp, err := c.httpClient.Do(req) + if err != nil { + return nil, fmt.Errorf("query victoria metrics: %w", err) + } + defer func() { _ = resp.Body.Close() }() + + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + return nil, fmt.Errorf("victoria metrics responded with status %d", resp.StatusCode) + } + + var payload vmResponse + if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil { + return nil, fmt.Errorf("decode victoria metrics response: %w", err) + } + if payload.Status != "success" { + if payload.Error != "" { + return nil, fmt.Errorf("victoria metrics error: %s", payload.Error) + } + return nil, fmt.Errorf("victoria metrics status %s", payload.Status) + } + + out := make([]sample, 0, len(payload.Data.Result)) + for _, item := range payload.Data.Result { + if len(item.Value) != 2 { + continue + } + ts, ok := parseFloat(item.Value[0]) + if !ok { + continue + } + val, ok := parseFloat(item.Value[1]) + if !ok { + continue + } + out = append(out, sample{ + labels: item.Metric, + value: val, + timestamp: time.Unix(int64(ts), 0), + }) + } + c.storeCached(expr, out) + return out, nil +} + +func (c *Client) loadCached(expr string) ([]sample, bool) { + if c.cacheTTL <= 0 { + return nil, false + } + c.cacheMu.Lock() + defer c.cacheMu.Unlock() + entry, ok := c.cache[expr] + if !ok || time.Now().After(entry.expires) { + delete(c.cache, expr) + return nil, false + } + out := make([]sample, len(entry.samples)) + copy(out, entry.samples) + return out, true +} + +func (c *Client) storeCached(expr string, samples []sample) { + if c.cacheTTL <= 0 { + return + } + c.cacheMu.Lock() + defer c.cacheMu.Unlock() + out := make([]sample, len(samples)) + copy(out, samples) + c.cache[expr] = cachedQuery{ + expires: time.Now().Add(c.cacheTTL), + samples: out, + } +} + +func parseFloat(v any) (float64, bool) { + switch t := v.(type) { + case float64: + return t, true + case string: + val, err := strconv.ParseFloat(t, 64) + if err != nil { + return 0, false + } + return val, true + default: + return 0, false + } +} + +func (c *Client) lookbackExpr(metric string, labels map[string]string, clusterID string) string { + selector := metricSelector(metric, c.scopedLabels(labels, clusterID)) + return fmt.Sprintf("last_over_time(%s[%s])", selector, c.lookback.String()) +} + +func metricSelector(metric string, labels map[string]string) string { + if len(labels) == 0 { + return metric + } + keys := make([]string, 0, len(labels)) + for key := range labels { + keys = append(keys, key) + } + sort.Strings(keys) + var b strings.Builder + b.WriteString(metric) + b.WriteByte('{') + for idx, key := range keys { + if idx > 0 { + b.WriteByte(',') + } + b.WriteString(key) + b.WriteString(`="`) + b.WriteString(escapeLabelValue(labels[key])) + b.WriteByte('"') + } + b.WriteByte('}') + return b.String() +} + +func escapeLabelValue(value string) string { + replacer := strings.NewReplacer(`\`, `\\`, "\n", `\n`, `"`, `\"`) + return replacer.Replace(value) +} + +type clusterIDKey struct{} + +// WithClusterID sets the preferred cluster id for subsequent queries. +func WithClusterID(ctx context.Context, clusterID string) context.Context { + if clusterID == "" { + return ctx + } + return context.WithValue(ctx, clusterIDKey{}, clusterID) +} + +func clusterIDFromContext(ctx context.Context) string { + if ctx == nil { + return "" + } + if val, ok := ctx.Value(clusterIDKey{}).(string); ok { + return val + } + return "" +} + +func (c *Client) resolveClusterID(ctx context.Context) string { + if clusterID := clusterIDFromContext(ctx); clusterID != "" { + return clusterID + } + clusterID, _ := c.latestClusterID(ctx) + return clusterID +} + +func (c *Client) latestClusterID(ctx context.Context) (string, error) { + samples, err := c.seriesTimestamp(ctx, "clustercost_agent_up", nil) + if err != nil { + return "", err + } + latest := pickLatestSample(samples) + if latest == nil { + return "", ErrNoData + } + return latest.labels["cluster_id"], nil +} + +func (c *Client) scopedLabels(labels map[string]string, clusterID string) map[string]string { + if clusterID == "" { + return labels + } + if labels == nil { + labels = map[string]string{} + } + if _, ok := labels["cluster_id"]; !ok { + labels["cluster_id"] = clusterID + } + return labels +} + +// GetPodP95Usage returns the 95th percentile of CPU and Memory usage for a specific pod over the lookback period. +// cpu is in cores, memory is in bytes. +func (c *Client) GetPodP95Usage(ctx context.Context, clusterID, namespace, podName string) (cpuCores float64, memoryBytes float64, err error) { + // Construct labels for specific pod + labels := map[string]string{ + "namespace": namespace, + "pod": podName, + } + if clusterID != "" { + labels["cluster_id"] = clusterID + } + + // CPU Query: quantile_over_time(0.95, clustercost_pod_cpu_usage_milli{...}[1h]) / 1000 + // Pod CPU usage is reported as millicores (gauge). + cpuQuery := fmt.Sprintf("quantile_over_time(0.95, clustercost_pod_cpu_usage_milli%s[%s]) / 1000", + formatLabels(labels), c.lookback.String()) + + // Memory Query: quantile_over_time(0.95, clustercost_pod_memory_rss_bytes{...}[1h]) + memQuery := fmt.Sprintf("quantile_over_time(0.95, clustercost_pod_memory_rss_bytes%s[%s])", + formatLabels(labels), c.lookback.String()) + + // Execute CPU query + cpuSamples, err := c.query(ctx, cpuQuery) + if err != nil { + return 0, 0, fmt.Errorf("query cpu p95: %w", err) + } + if len(cpuSamples) > 0 { + cpuCores = cpuSamples[0].value + } + + // Execute Memory query + memSamples, err := c.query(ctx, memQuery) + if err != nil { + return 0, 0, fmt.Errorf("query memory p95: %w", err) + } + if len(memSamples) > 0 { + memoryBytes = memSamples[0].value + } + + return cpuCores, memoryBytes, nil +} + +func formatLabels(labels map[string]string) string { + if len(labels) == 0 { + return "" + } + var b strings.Builder + b.WriteByte('{') + keys := make([]string, 0, len(labels)) + for k := range labels { + keys = append(keys, k) + } + sort.Strings(keys) + + for i, k := range keys { + if i > 0 { + b.WriteByte(',') + } + b.WriteString(k) + b.WriteString(`="`) + b.WriteString(labels[k]) // Simple escape for now, assume safe chars + b.WriteByte('"') + } + b.WriteByte('}') + return b.String() +} diff --git a/internal/vm/dashboard.go b/internal/vm/dashboard.go new file mode 100644 index 0000000..34cc685 --- /dev/null +++ b/internal/vm/dashboard.go @@ -0,0 +1,1227 @@ +package vm + +import ( + "context" + "fmt" + "regexp" + "sort" + "strconv" + "strings" + "time" + + "github.com/clustercost/clustercost-dashboard/internal/store" +) + +const hoursPerMonth = 24 * 30 + +func (c *Client) Overview(ctx context.Context, limit int) (store.OverviewPayload, error) { + namespaces, ts, err := c.namespaceMetrics(ctx, "", "") + if err != nil { + return store.OverviewPayload{}, err + } + if len(namespaces) == 0 { + return store.OverviewPayload{}, ErrNoData + } + + list := make([]store.NamespaceSummary, 0, len(namespaces)) + envCost := map[string]float64{ + "production": 0, + "nonprod": 0, + "system": 0, + "unknown": 0, + } + totalHourly := 0.0 + for _, ns := range namespaces { + totalHourly += ns.HourlyCost + list = append(list, *ns) + env := normalizeEnvironment(ns.Environment) + envCost[env] += ns.HourlyCost + } + + sort.Slice(list, func(i, j int) bool { + return list[i].HourlyCost > list[j].HourlyCost + }) + + topLimit := limit + if topLimit <= 0 || topLimit > len(list) { + topLimit = len(list) + } + topNamespaces := make([]store.TopNamespaceEntry, 0, topLimit) + for idx := 0; idx < topLimit; idx++ { + topNamespaces = append(topNamespaces, store.TopNamespaceEntry{ + Namespace: list[idx].Namespace, + Environment: valueOrDefault(list[idx].Environment, "unknown"), + HourlyCost: list[idx].HourlyCost, + }) + } + + meta, _ := c.ClusterMetadata(ctx) + clusterName := meta.ID + if meta.Name != "" { + clusterName = meta.Name + } + + if ts.IsZero() { + ts = meta.Timestamp + } + if ts.IsZero() { + ts = time.Now().UTC() + } + + return store.OverviewPayload{ + ClusterName: clusterName, + Timestamp: ts, + TotalHourlyCost: totalHourly, + TotalMonthlyCost: totalHourly * hoursPerMonth, + EnvCostHourly: envCost, + TopNamespacesByCost: topNamespaces, + SavingsCandidates: findSavingsCandidates(list), + }, nil +} + +func (c *Client) NamespaceList(ctx context.Context, filter store.NamespaceFilter) (store.NamespaceListResponse, error) { + namespaces, ts, err := c.namespaceMetrics(ctx, filter.Environment, "") + if err != nil { + return store.NamespaceListResponse{}, err + } + + var searchLower string + if filter.Search != "" { + searchLower = strings.ToLower(filter.Search) + } + + out := make([]store.NamespaceSummary, 0, len(namespaces)) + for _, ns := range namespaces { + if searchLower != "" && !strings.Contains(strings.ToLower(ns.Namespace), searchLower) { + continue + } + out = append(out, *ns) + } + + sort.Slice(out, func(i, j int) bool { + return out[i].HourlyCost > out[j].HourlyCost + }) + + total := len(out) + start := clampIndex(filter.Offset, total) + end := clampIndex(filter.Offset+filter.Limit, total) + + if ts.IsZero() { + ts = time.Now().UTC() + } + + return store.NamespaceListResponse{ + Items: out[start:end], + TotalCount: total, + Timestamp: ts, + }, nil +} + +func (c *Client) NamespaceDetail(ctx context.Context, name string) (store.NamespaceSummary, error) { + namespaces, _, err := c.namespaceMetrics(ctx, "", name) + if err != nil { + return store.NamespaceSummary{}, err + } + for _, ns := range namespaces { + if ns.Namespace == name { + return *ns, nil + } + } + return store.NamespaceSummary{}, ErrNoData +} + +func (c *Client) NodeList(ctx context.Context, filter store.NodeFilter) (store.NodeListResponse, error) { + nodes, ts, err := c.nodeMetrics(ctx, "") + if err != nil { + return store.NodeListResponse{}, err + } + + var searchLower string + if filter.Search != "" { + searchLower = strings.ToLower(filter.Search) + } + + out := make([]store.NodeSummary, 0, len(nodes)) + for _, node := range nodes { + if searchLower != "" && !strings.Contains(strings.ToLower(node.NodeName), searchLower) { + continue + } + out = append(out, *node) + } + + sort.Slice(out, func(i, j int) bool { + return out[i].HourlyCost > out[j].HourlyCost + }) + + total := len(out) + start := clampIndex(filter.Offset, total) + end := clampIndex(filter.Offset+filter.Limit, total) + + if ts.IsZero() { + ts = time.Now().UTC() + } + + return store.NodeListResponse{ + Items: out[start:end], + TotalCount: total, + Timestamp: ts, + }, nil +} + +func (c *Client) NodeDetail(ctx context.Context, name string) (store.NodeSummary, error) { + nodes, _, err := c.nodeMetrics(ctx, name) + if err != nil { + return store.NodeSummary{}, err + } + for _, node := range nodes { + if node.NodeName == name { + return *node, nil + } + } + return store.NodeSummary{}, ErrNoData +} + +func (c *Client) Resources(ctx context.Context) (store.ResourcesPayload, error) { + cpuUsage, cpuUsageTS, err := c.scalarMetric(ctx, "clustercost_cluster_cpu_usage_milli_total") + if err != nil && err != ErrNoData { + return store.ResourcesPayload{}, err + } + cpuRequest, _, err := c.scalarMetric(ctx, "clustercost_cluster_cpu_request_milli_total") + if err != nil && err != ErrNoData { + return store.ResourcesPayload{}, err + } + memUsage, _, err := c.scalarMetric(ctx, "clustercost_cluster_memory_usage_bytes_total") + if err != nil && err != ErrNoData { + return store.ResourcesPayload{}, err + } + memRequest, _, err := c.scalarMetric(ctx, "clustercost_cluster_memory_request_bytes_total") + if err != nil && err != ErrNoData { + return store.ResourcesPayload{}, err + } + nodeHourlyCost, _, err := c.scalarMetric(ctx, "clustercost_cluster_total_node_hourly_cost") + if err != nil && err != ErrNoData { + return store.ResourcesPayload{}, err + } + + // Fetch Network Metrics + netTx, _, _ := c.scalarMetric(ctx, "clustercost_cluster_network_tx_bytes_total") + netRx, _, _ := c.scalarMetric(ctx, "clustercost_cluster_network_rx_bytes_total") + netEgress, _, _ := c.scalarMetric(ctx, "clustercost_cluster_network_egress_cost_total") + + namespaces, _, nsErr := c.namespaceMetrics(ctx, "", "") + if nsErr != nil && nsErr != ErrNoData { + return store.ResourcesPayload{}, nsErr + } + + if cpuUsage == 0 && cpuRequest == 0 && len(namespaces) > 0 { + for _, ns := range namespaces { + cpuUsage += float64(ns.CPUUsageMilli) + cpuRequest += float64(ns.CPURequestMilli) + } + } + if memUsage == 0 && memRequest == 0 && len(namespaces) > 0 { + for _, ns := range namespaces { + memUsage += float64(ns.MemoryUsageBytes) + memRequest += float64(ns.MemoryRequestBytes) + } + } + if nodeHourlyCost == 0 { + nodeHourlyCost = c.sumNodeHourlyCost(namespaces) + } + + if cpuUsage == 0 && cpuRequest == 0 && memUsage == 0 && memRequest == 0 && nodeHourlyCost == 0 && len(namespaces) == 0 { + return store.ResourcesPayload{}, ErrNoData + } + + cpuEfficiency := percent(cpuUsage, cpuRequest) + memEfficiency := percent(memUsage, memRequest) + cpuWasteCost := wasteCost(nodeHourlyCost, cpuUsage, cpuRequest) + memWasteCost := wasteCost(nodeHourlyCost, memUsage, memRequest) + + ts := cpuUsageTS + if ts.IsZero() { + ts = time.Now().UTC() + } + + return store.ResourcesPayload{ + Timestamp: ts, + CPU: store.CPUResource{ + UsageMilli: int64(cpuUsage), + RequestMilli: int64(cpuRequest), + EfficiencyPercent: cpuEfficiency, + EstimatedHourlyWasteCost: cpuWasteCost, + }, + Memory: store.MemoryResource{ + UsageBytes: int64(memUsage), + RequestBytes: int64(memRequest), + EfficiencyPercent: memEfficiency, + EstimatedHourlyWasteCost: memWasteCost, + }, + Network: store.NetworkResource{ + TxBytesTotal: int64(netTx), + RxBytesTotal: int64(netRx), + EgressCostHourly: netEgress, + }, + NamespaceWaste: buildNamespaceWaste(namespaces), + }, nil +} + +func (c *Client) NetworkTopology(ctx context.Context, opts store.NetworkTopologyOptions) ([]store.NetworkEdge, error) { + clusterID := opts.ClusterID + if clusterID == "" { + clusterID = c.resolveClusterID(ctx) + } + if clusterID == "" { + return nil, ErrNoData + } + ctx = WithClusterID(ctx, clusterID) + + if opts.End.IsZero() { + opts.End = time.Now().UTC() + } + if opts.Start.IsZero() { + opts.Start = opts.End.Add(-c.lookback) + } + + window := opts.End.Sub(opts.Start) + if window <= 0 { + window = c.lookback + } + windowStr := formatDuration(window) + + labels := map[string]string{"cluster_id": clusterID} + queryNamespace := "" + if len(opts.Namespaces) == 1 { + queryNamespace = opts.Namespaces[0] + } + groupLabels := []string{ + "src_namespace", + "src_pod", + "src_node", + "src_ip", + "src_dns_name", + "src_availability_zone", + "dst_namespace", + "dst_pod", + "dst_node", + "dst_ip", + "dst_dns_name", + "dst_availability_zone", + "dst_kind", + "service_match", + "dst_services", + "protocol", + } + groupBy := strings.Join(groupLabels, ",") + + endSeconds := opts.End.UTC().Unix() + + bytesSentExpr := connectionMetricExpr("clustercost_connection_bytes_sent_total", labels, queryNamespace, windowStr, endSeconds, groupBy, "increase") + bytesRecvExpr := connectionMetricExpr("clustercost_connection_bytes_received_total", labels, queryNamespace, windowStr, endSeconds, groupBy, "increase") + countExpr := connectionMetricExpr("clustercost_connection_bytes_sent_total", labels, queryNamespace, windowStr, endSeconds, groupBy, "count") + + sentSamples, err := c.query(ctx, bytesSentExpr) + if err != nil { + return nil, err + } + recvSamples, err := c.query(ctx, bytesRecvExpr) + if err != nil { + return nil, err + } + + startSeconds := opts.Start.UTC().Unix() + edges := make(map[string]*store.NetworkEdge) + + namespaceSet := make(map[string]struct{}, len(opts.Namespaces)) + for _, namespace := range opts.Namespaces { + if namespace == "" { + continue + } + namespaceSet[namespace] = struct{}{} + } + + applySample := func(sample sample, assign func(*store.NetworkEdge, float64)) { + edge := edgeFromLabels(sample.labels, groupLabels) + if edge == nil { + return + } + if len(namespaceSet) > 0 { + if _, ok := namespaceSet[edge.SrcNamespace]; !ok { + if _, ok := namespaceSet[edge.DstNamespace]; !ok { + return + } + } + } + key := edgeKey(sample.labels, groupLabels) + current := edges[key] + if current == nil { + edge.FirstSeen = startSeconds + edge.LastSeen = endSeconds + edges[key] = edge + current = edge + } + assign(current, sample.value) + } + + for _, sample := range sentSamples { + applySample(sample, func(edge *store.NetworkEdge, value float64) { + edge.BytesSent = int64(value) + }) + } + for _, sample := range recvSamples { + applySample(sample, func(edge *store.NetworkEdge, value float64) { + edge.BytesReceived = int64(value) + }) + } + countSamples, err := c.query(ctx, countExpr) + if err != nil { + return nil, err + } + for _, sample := range countSamples { + applySample(sample, func(edge *store.NetworkEdge, value float64) { + edge.ConnectionCount = int64(value) + }) + } + + if len(edges) == 0 { + return nil, ErrNoData + } + + list := make([]store.NetworkEdge, 0, len(edges)) + for _, edge := range edges { + if opts.MinCostUSD > 0 && edge.EgressCostUSD <= opts.MinCostUSD { + continue + } + if opts.MinBytes > 0 && (edge.BytesSent+edge.BytesReceived) < opts.MinBytes { + continue + } + if opts.MinConnections > 0 && edge.ConnectionCount < opts.MinConnections { + continue + } + list = append(list, *edge) + } + sort.Slice(list, func(i, j int) bool { + if list[i].EgressCostUSD != list[j].EgressCostUSD { + return list[i].EgressCostUSD > list[j].EgressCostUSD + } + totalI := list[i].BytesSent + list[i].BytesReceived + totalJ := list[j].BytesSent + list[j].BytesReceived + return totalI > totalJ + }) + + if opts.Limit > 0 && len(list) > opts.Limit { + list = list[:opts.Limit] + } + return list, nil +} + +func (c *Client) AgentStatus(ctx context.Context) (store.AgentStatusPayload, error) { + clusterID := c.resolveClusterID(ctx) + ctx = WithClusterID(ctx, clusterID) + agentSamples, err := c.seriesTimestamp(ctx, "clustercost_agent_up", nil) + if err != nil { + return store.AgentStatusPayload{}, err + } + if len(agentSamples) == 0 { + return store.AgentStatusPayload{}, ErrNoData + } + + lastSync := latestTimestamp(agentSamples) + if lastSync.IsZero() { + return store.AgentStatusPayload{}, ErrNoData + } + + nsTS := c.seriesTimestampSafe(ctx, "clustercost_namespace_hourly_cost") + nodeTS := c.seriesTimestampSafe(ctx, "clustercost_node_hourly_cost") + resTS := c.seriesTimestampSafe(ctx, "clustercost_cluster_cpu_usage_milli_total") + + datasets := store.AgentDatasetHealth{ + Namespaces: datasetStatus(!nsTS.IsZero(), nsTS, lastSync), + Nodes: datasetStatus(!nodeTS.IsZero(), nodeTS, lastSync), + Resources: datasetStatus(!resTS.IsZero(), resTS, lastSync), + } + + var status string + allOK := datasets.Namespaces == "ok" && datasets.Nodes == "ok" && datasets.Resources == "ok" + if time.Since(lastSync) > agentOfflineThreshold { + status = "offline" + } else if allOK { + status = "connected" + } else { + status = "partial" + } + + meta, _ := c.ClusterMetadata(ctx) + version := meta.Version + updateAvailable := c.recommendedAgentVersion != "" && version != "" && version != c.recommendedAgentVersion + + nodeCount := len(c.nodeNames(ctx)) + + return store.AgentStatusPayload{ + Status: status, + LastSync: lastSync, + Datasets: datasets, + Version: version, + UpdateAvailable: updateAvailable, + ClusterName: meta.Name, + ClusterType: meta.Type, + ClusterRegion: meta.Region, + NodeCount: nodeCount, + }, nil +} + +func (c *Client) Agents(ctx context.Context) ([]store.AgentInfo, error) { + clusterID := c.resolveClusterID(ctx) + ctx = WithClusterID(ctx, clusterID) + + // Explicitly query for agents active in the last 24 hours + expr := "max_over_time(timestamp(clustercost_agent_up)[24h])" + samples, err := c.query(ctx, expr) + if err != nil && err != ErrNoData { + return nil, err + } + + for idx := range samples { + samples[idx].timestamp = time.Unix(int64(samples[idx].value), 0) + } + agentSamples := samples + + configuredNames := make(map[string]bool) + agentMap := make(map[string]store.AgentInfo) + for _, cfg := range c.agents { + configuredNames[cfg.Name] = true + agentMap[cfg.Name] = store.AgentInfo{ + Name: cfg.Name, + BaseURL: cfg.BaseURL, + Status: "unknown", + } + } + + now := time.Now() + for _, sample := range agentSamples { + // Try agent_id first, fallback to cluster_id or just "unknown" + name := sample.labels["agent_id"] + if name == "" { + name = sample.labels["cluster_id"] + } + if name == "" { + continue // skip samples without identification + } + + info := agentMap[name] + info.Name = name + info.LastScrapeTime = sample.timestamp + info.ClusterID = sample.labels["cluster_id"] + info.NodeName = sample.labels["node"] + + if sample.timestamp.IsZero() { + info.Status = "unknown" + } else if now.Sub(sample.timestamp) > agentOfflineThreshold { + info.Status = "offline" + } else { + info.Status = "connected" + } + agentMap[name] = info + } + + result := make([]store.AgentInfo, 0, len(agentMap)) + for _, info := range agentMap { + // Filter: only include agents seen in the last 24 hours or configured statically + if time.Since(info.LastScrapeTime) > 24*time.Hour && info.Status == "unknown" { + // If it's a static agent that we haven't seen, deciding whether to keep it. + // The user asked for "show only agents connected in last 24h". + // So, if it's static ("unknown") and no data, maybe exclude? + // But for now, let's keep static configs if they exist, but definitely filter out dynamic ones that are too old. + if !configuredNames[info.Name] { + continue + } + } + result = append(result, info) + } + + sort.Slice(result, func(i, j int) bool { + return result[i].Name < result[j].Name + }) + + return result, nil +} + +func (c *Client) ClusterMetadata(ctx context.Context) (store.ClusterMetadata, error) { + clusterID := c.resolveClusterID(ctx) + ctx = WithClusterID(ctx, clusterID) + agentSamples, err := c.seriesTimestamp(ctx, "clustercost_agent_up", nil) + if err != nil { + return store.ClusterMetadata{}, err + } + if len(agentSamples) == 0 { + return store.ClusterMetadata{}, ErrNoData + } + + latest := pickLatestSample(agentSamples) + if latest == nil { + return store.ClusterMetadata{}, ErrNoData + } + + clusterIDLabel := latest.labels["cluster_id"] + clusterName := latest.labels["cluster_name"] + if clusterName == "" { + clusterName = clusterIDLabel + } + + return store.ClusterMetadata{ + ID: clusterIDLabel, + Name: clusterName, + Type: latest.labels["cluster_type"], + Region: latest.labels["cluster_region"], + Version: latest.labels["version"], + Timestamp: latest.timestamp, + }, nil +} + +func (c *Client) namespaceMetrics(ctx context.Context, environment, namespace string) (map[string]*store.NamespaceSummary, time.Time, error) { + clusterID := c.resolveClusterID(ctx) + ctx = WithClusterID(ctx, clusterID) + labels := map[string]string{} + if environment != "" { + labels["environment"] = environment + } + if namespace != "" { + labels["namespace"] = namespace + } + + // We use pod metrics and aggregate them on the fly + metrics := []struct { + name string + agg string // "sum" or "count" + assign func(entry *store.NamespaceSummary, value float64) + expr func(clusterID string, labels map[string]string) string + fallback string + }{ + {"clustercost_namespace_pod_count", "sum", func(e *store.NamespaceSummary, v float64) { e.PodCount = int(v) }, nil, ""}, + { + "clustercost_namespace_cpu_request_millicores", + "sum", + func(e *store.NamespaceSummary, v float64) { e.CPURequestMilli = int64(v) }, + nil, + "clustercost_pod_cpu_request_millicores", + }, + { + "clustercost_namespace_cpu_usage_milli", + "sum", + func(e *store.NamespaceSummary, v float64) { e.CPUUsageMilli = int64(v) }, + func(clusterID string, labels map[string]string) string { + return fmt.Sprintf("sum by (namespace, environment) (%s)", c.lookbackExpr("clustercost_namespace_cpu_usage_milli", labels, clusterID)) + }, + "clustercost_pod_cpu_usage_milli", + }, + { + "clustercost_namespace_memory_request_bytes", + "sum", + func(e *store.NamespaceSummary, v float64) { e.MemoryRequestBytes = int64(v) }, + nil, + "clustercost_pod_memory_request_bytes", + }, + {"clustercost_namespace_memory_rss_bytes_total", "sum", func(e *store.NamespaceSummary, v float64) { e.MemoryUsageBytes = int64(v) }, nil, ""}, + } + + out := make(map[string]*store.NamespaceSummary) + var latest time.Time + + // Regex to identify UUID-like strings (which are likely garbage/incorrect namespaces) + uuidPattern := regexp.MustCompile(`^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$`) + + for _, metric := range metrics { + // e.g. sum by (namespace, environment) (last_over_time(clustercost_pod_hourly_cost{...}[1h])) + // Note: lookbackExpr returns "last_over_time(metric{...}[lookback])" + // We wrap that in the aggregation. + queryExpr := func(metricName string) (string, error) { + if metric.expr != nil && metricName == metric.name { + return metric.expr(clusterID, labels), nil + } + return fmt.Sprintf("%s by (namespace, environment) (%s)", metric.agg, c.lookbackExpr(metricName, labels, clusterID)), nil + } + + expr, _ := queryExpr(metric.name) + samples, err := c.query(ctx, expr) + if err != nil { + return nil, time.Time{}, err + } + if len(samples) == 0 && metric.fallback != "" { + fallbackExpr, _ := queryExpr(metric.fallback) + samples, err = c.query(ctx, fallbackExpr) + if err != nil { + return nil, time.Time{}, err + } + } + for _, sample := range samples { + ns := sample.labels["namespace"] + if ns == "" { + continue + } + // Filter out UUID-like namespaces as they are likely misreported or noise + if uuidPattern.MatchString(ns) { + continue + } + + env := sample.labels["environment"] + key := namespaceKey(ns, env) + entry := out[key] + if entry == nil { + entry = &store.NamespaceSummary{ + Namespace: ns, + Environment: env, + Labels: map[string]string{}, + } + out[key] = entry + } + metric.assign(entry, sample.value) + } + } + + queryScalar := func(expr string) (float64, error) { + samples, err := c.query(ctx, expr) + if err != nil { + return 0, err + } + if len(samples) == 0 { + return 0, ErrNoData + } + return samples[0].value, nil + } + + nodeCostExpr := fmt.Sprintf("sum(max by (node) (%s))", c.lookbackExpr("clustercost_node_hourly_cost", nil, clusterID)) + cpuAllocExpr := fmt.Sprintf("sum(max by (node) (%s))", c.lookbackExpr("clustercost_node_cpu_allocatable_milli", nil, clusterID)) + memAllocExpr := fmt.Sprintf("sum(max by (node) (%s))", c.lookbackExpr("clustercost_node_memory_allocatable_bytes", nil, clusterID)) + + nodeCost, err := queryScalar(nodeCostExpr) + if err == nil && nodeCost > 0 { + cpuAllocMilli, errCPU := queryScalar(cpuAllocExpr) + memAllocBytes, errMem := queryScalar(memAllocExpr) + if errCPU == nil && errMem == nil && cpuAllocMilli > 0 && memAllocBytes > 0 { + cpuPrice := (nodeCost * 0.5) / (cpuAllocMilli / 1000.0) + memPrice := (nodeCost * 0.5) / (memAllocBytes / (1024.0 * 1024.0 * 1024.0)) + for _, entry := range out { + cpuUsageCores := float64(entry.CPUUsageMilli) / 1000.0 + memUsageGB := float64(entry.MemoryUsageBytes) / (1024.0 * 1024.0 * 1024.0) + entry.HourlyCost = (cpuUsageCores * cpuPrice) + (memUsageGB * memPrice) + } + } + } + + latest = c.seriesTimestampSafe(ctx, "clustercost_namespace_memory_rss_bytes_total") + + type nodeAlloc struct { + instanceType string + region string + cpuMilli float64 + memBytes float64 + } + nodes := make(map[string]*nodeAlloc) + loadNodeAlloc := func(metric string, assign func(entry *nodeAlloc, value float64)) error { + expr := fmt.Sprintf("max by (node,instance_type,cluster_region) (%s)", c.lookbackExpr(metric, nil, clusterID)) + samples, err := c.query(ctx, expr) + if err != nil { + return err + } + for _, sample := range samples { + node := sample.labels["node"] + if node == "" { + continue + } + entry := nodes[node] + if entry == nil { + entry = &nodeAlloc{ + instanceType: sample.labels["instance_type"], + region: sample.labels["cluster_region"], + } + nodes[node] = entry + } + if entry.instanceType == "" { + entry.instanceType = sample.labels["instance_type"] + } + if entry.region == "" { + entry.region = sample.labels["cluster_region"] + } + assign(entry, sample.value) + } + return nil + } + + if err := loadNodeAlloc("clustercost_node_cpu_allocatable_milli", func(entry *nodeAlloc, value float64) { + entry.cpuMilli = value + }); err == nil { + _ = loadNodeAlloc("clustercost_node_memory_allocatable_bytes", func(entry *nodeAlloc, value float64) { + entry.memBytes = value + }) + } + + pricing := store.NewPricingCatalog(nil) + totalNodeCost := 0.0 + totalCpuCores := 0.0 + totalMemGB := 0.0 + for _, entry := range nodes { + if entry.cpuMilli > 0 { + totalCpuCores += entry.cpuMilli / 1000.0 + } + if entry.memBytes > 0 { + totalMemGB += entry.memBytes / (1024.0 * 1024.0 * 1024.0) + } + instanceType := entry.instanceType + if instanceType == "" { + instanceType = "default" + } + totalNodeCost += pricing.GetTotalNodePrice(context.Background(), entry.region, instanceType) + } + + if totalNodeCost > 0 && totalCpuCores > 0 && totalMemGB > 0 { + cpuPrice := (totalNodeCost * 0.5) / totalCpuCores + memPrice := (totalNodeCost * 0.5) / totalMemGB + for _, entry := range out { + cpuUsageCores := float64(entry.CPUUsageMilli) / 1000.0 + memUsageGB := float64(entry.MemoryUsageBytes) / (1024.0 * 1024.0 * 1024.0) + entry.HourlyCost = (cpuUsageCores * cpuPrice) + (memUsageGB * memPrice) + } + } + return out, latest, nil +} + +func (c *Client) nodeMetrics(ctx context.Context, nodeName string) (map[string]*store.NodeSummary, time.Time, error) { + clusterID := c.resolveClusterID(ctx) + ctx = WithClusterID(ctx, clusterID) + labels := map[string]string{} + if nodeName != "" { + labels["node"] = nodeName + } + + metrics := []struct { + name string + assign func(entry *store.NodeSummary, value float64, labels map[string]string) + }{ + {"clustercost_node_hourly_cost", func(e *store.NodeSummary, v float64, l map[string]string) { + e.HourlyCost = v + if e.InstanceType == "" { + e.InstanceType = l["instance_type"] + } + }}, + {"clustercost_node_cpu_usage_percent", func(e *store.NodeSummary, v float64, _ map[string]string) { e.CPUUsagePercent = v }}, + {"clustercost_node_memory_usage_percent", func(e *store.NodeSummary, v float64, _ map[string]string) { e.MemoryUsagePercent = v }}, + {"clustercost_node_cpu_allocatable_milli", func(e *store.NodeSummary, v float64, _ map[string]string) { e.CPUAllocatableMilli = int64(v) }}, + {"clustercost_node_memory_allocatable_bytes", func(e *store.NodeSummary, v float64, _ map[string]string) { e.MemoryAllocatableBytes = int64(v) }}, + {"clustercost_node_pod_count", func(e *store.NodeSummary, v float64, _ map[string]string) { e.PodCount = int(v) }}, + {"clustercost_node_under_pressure", func(e *store.NodeSummary, v float64, _ map[string]string) { e.IsUnderPressure = v > 0.5 }}, + } + + out := make(map[string]*store.NodeSummary) + for _, metric := range metrics { + by := "node" + if metric.name == "clustercost_node_hourly_cost" { + by = "node,instance_type" + } + expr := fmt.Sprintf("max by (%s) (%s)", by, c.lookbackExpr(metric.name, labels, clusterID)) + samples, err := c.query(ctx, expr) + if err != nil { + return nil, time.Time{}, err + } + for _, sample := range samples { + node := sample.labels["node"] + if node == "" { + continue + } + entry := out[node] + if entry == nil { + entry = &store.NodeSummary{ + NodeName: node, + Labels: map[string]string{}, + Taints: []string{}, + } + out[node] = entry + } + metric.assign(entry, sample.value, sample.labels) + } + } + + statusSamples, err := c.seriesTimestamp(ctx, "clustercost_node_status", labels) + if err != nil && err != ErrNoData { + return nil, time.Time{}, err + } + for node, status := range pickLatestStatus(statusSamples) { + entry := out[node] + if entry != nil { + entry.Status = status + } + } + + latest := c.seriesTimestampSafe(ctx, "clustercost_node_hourly_cost") + return out, latest, nil +} + +func (c *Client) scalarMetric(ctx context.Context, metric string) (float64, time.Time, error) { + clusterID := c.resolveClusterID(ctx) + ctx = WithClusterID(ctx, clusterID) + expr := fmt.Sprintf("sum(%s)", c.lookbackExpr(metric, nil, clusterID)) + samples, err := c.query(ctx, expr) + if err != nil { + return 0, time.Time{}, err + } + if len(samples) == 0 { + return 0, time.Time{}, ErrNoData + } + latest := c.seriesTimestampSafe(ctx, metric) + return samples[0].value, latest, nil +} + +func formatDuration(value time.Duration) string { + seconds := int64(value.Seconds()) + if seconds <= 0 { + return "0s" + } + if seconds%86400 == 0 { + return fmt.Sprintf("%dd", seconds/86400) + } + if seconds%3600 == 0 { + return fmt.Sprintf("%dh", seconds/3600) + } + if seconds%60 == 0 { + return fmt.Sprintf("%dm", seconds/60) + } + return fmt.Sprintf("%ds", seconds) +} + +func edgeKey(labels map[string]string, keys []string) string { + if len(labels) == 0 { + return "" + } + values := make([]string, 0, len(keys)) + for _, key := range keys { + values = append(values, labels[key]) + } + return strings.Join(values, "|") +} + +func edgeFromLabels(labels map[string]string, keys []string) *store.NetworkEdge { + if len(labels) == 0 { + return nil + } + protocol := int64(0) + if raw := labels["protocol"]; raw != "" { + if parsed, err := strconv.ParseInt(raw, 10, 64); err == nil { + protocol = parsed + } + } + + return &store.NetworkEdge{ + SrcNamespace: labels["src_namespace"], + SrcPodName: labels["src_pod"], + SrcNodeName: labels["src_node"], + SrcIP: labels["src_ip"], + SrcDNSName: labels["src_dns_name"], + SrcAZ: labels["src_availability_zone"], + DstNamespace: labels["dst_namespace"], + DstPodName: labels["dst_pod"], + DstNodeName: labels["dst_node"], + DstIP: labels["dst_ip"], + DstDNSName: labels["dst_dns_name"], + DstAZ: labels["dst_availability_zone"], + DstKind: labels["dst_kind"], + ServiceMatch: labels["service_match"], + DstServices: labels["dst_services"], + Protocol: protocol, + } +} + +func connectionMetricExpr(metric string, baseLabels map[string]string, namespace, window string, endSeconds int64, groupBy, op string) string { + rangeExpr := func(selector string) string { + switch op { + case "count": + return fmt.Sprintf("(count_over_time(%s[%s] @ %d) > 0)", selector, window, endSeconds) + default: + return fmt.Sprintf("increase(%s[%s] @ %d)", selector, window, endSeconds) + } + } + + selector := metricSelector(metric, baseLabels) + if namespace == "" { + return fmt.Sprintf("sum by (%s) (%s)", groupBy, rangeExpr(selector)) + } + + srcLabels := copyLabels(baseLabels) + dstLabels := copyLabels(baseLabels) + srcLabels["src_namespace"] = namespace + dstLabels["dst_namespace"] = namespace + + srcSelector := metricSelector(metric, srcLabels) + dstSelector := metricSelector(metric, dstLabels) + return fmt.Sprintf("sum by (%s) ((%s) or (%s))", groupBy, rangeExpr(srcSelector), rangeExpr(dstSelector)) +} + +func copyLabels(in map[string]string) map[string]string { + out := make(map[string]string, len(in)) + for key, value := range in { + out[key] = value + } + return out +} + +func (c *Client) seriesTimestamp(ctx context.Context, metric string, labels map[string]string) ([]sample, error) { + clusterID := clusterIDFromContext(ctx) + scoped := c.scopedLabels(labels, clusterID) + expr := fmt.Sprintf("max_over_time(timestamp(%s)[%s])", metricSelector(metric, scoped), c.lookback.String()) + samples, err := c.query(ctx, expr) + if err != nil { + return nil, err + } + for idx := range samples { + samples[idx].timestamp = time.Unix(int64(samples[idx].value), 0) + } + return samples, nil +} + +func (c *Client) seriesTimestampSafe(ctx context.Context, metric string) time.Time { + samples, err := c.seriesTimestamp(ctx, metric, nil) + if err != nil { + return time.Time{} + } + return latestTimestamp(samples) +} + +func latestTimestamp(samples []sample) time.Time { + var latest time.Time + for _, s := range samples { + if s.timestamp.After(latest) { + latest = s.timestamp + } + } + return latest +} + +func pickLatestSample(samples []sample) *sample { + var latest *sample + for idx := range samples { + current := &samples[idx] + if latest == nil || current.timestamp.After(latest.timestamp) { + latest = current + } + } + return latest +} + +func pickLatestStatus(samples []sample) map[string]string { + latest := make(map[string]sample) + for _, s := range samples { + node := s.labels["node"] + status := s.labels["status"] + if node == "" || status == "" { + continue + } + if existing, ok := latest[node]; !ok || s.timestamp.After(existing.timestamp) { + latest[node] = s + } + } + out := make(map[string]string, len(latest)) + for node, sample := range latest { + out[node] = sample.labels["status"] + } + return out +} + +func (c *Client) nodeNames(ctx context.Context) []string { + clusterID := c.resolveClusterID(ctx) + expr := fmt.Sprintf("max by (node) (%s)", c.lookbackExpr("clustercost_node_hourly_cost", nil, clusterID)) + samples, err := c.query(ctx, expr) + if err != nil { + return nil + } + nodes := make([]string, 0, len(samples)) + for _, sample := range samples { + if node := sample.labels["node"]; node != "" { + nodes = append(nodes, node) + } + } + return nodes +} + +func namespaceKey(ns, env string) string { + return fmt.Sprintf("%s|%s", ns, env) +} + +func normalizeEnvironment(env string) string { + switch strings.ToLower(env) { + case "prod", "production": + return "production" + case "nonprod", "dev", "development": + return "nonprod" + case "system": + return "system" + default: + return "unknown" + } +} + +func valueOrDefault(value, fallback string) string { + if value == "" { + return fallback + } + return value +} + +func datasetStatus(hasData bool, timestamp, fallback time.Time) string { + if !hasData { + return "missing" + } + effective := timestamp + if effective.IsZero() { + effective = fallback + } + if effective.IsZero() { + return "partial" + } + if time.Since(effective) > datasetFreshThreshold { + return "partial" + } + return "ok" +} + +func clampIndex(idx, max int) int { + if idx < 0 { + return 0 + } + if idx > max { + return max + } + return idx +} + +func findSavingsCandidates(namespaces []store.NamespaceSummary) []store.SavingsCandidate { + const utilizationThreshold = 0.4 + const costThreshold = 0.05 + + candidates := make([]store.SavingsCandidate, 0) + for _, ns := range namespaces { + if ns.HourlyCost < costThreshold { + continue + } + cpuRatio := usageRatio(float64(ns.CPUUsageMilli), float64(ns.CPURequestMilli)) + memRatio := usageRatio(float64(ns.MemoryUsageBytes), float64(ns.MemoryRequestBytes)) + if (ns.CPURequestMilli > 0 && cpuRatio <= utilizationThreshold) || + (ns.MemoryRequestBytes > 0 && memRatio <= utilizationThreshold) { + candidates = append(candidates, store.SavingsCandidate{ + Namespace: ns.Namespace, + Environment: valueOrDefault(ns.Environment, "unknown"), + HourlyCost: ns.HourlyCost, + CPURequestMilli: ns.CPURequestMilli, + CPUUsageMilli: ns.CPUUsageMilli, + MemoryRequestBytes: ns.MemoryRequestBytes, + MemoryUsageBytes: ns.MemoryUsageBytes, + }) + } + } + + sort.Slice(candidates, func(i, j int) bool { + return candidates[i].HourlyCost > candidates[j].HourlyCost + }) + + if len(candidates) > 5 { + return candidates[:5] + } + return candidates +} + +func buildNamespaceWaste(data map[string]*store.NamespaceSummary) []store.NamespaceWasteEntry { + if len(data) == 0 { + return []store.NamespaceWasteEntry{} + } + + out := make([]store.NamespaceWasteEntry, 0, len(data)) + for _, ns := range data { + cpuWaste := wastePercent(float64(ns.CPUUsageMilli), float64(ns.CPURequestMilli)) + memWaste := wastePercent(float64(ns.MemoryUsageBytes), float64(ns.MemoryRequestBytes)) + if cpuWaste == 0 && memWaste == 0 { + continue + } + wasteRatio := maxFloat( + unusedRatio(float64(ns.CPUUsageMilli), float64(ns.CPURequestMilli)), + unusedRatio(float64(ns.MemoryUsageBytes), float64(ns.MemoryRequestBytes)), + ) + out = append(out, store.NamespaceWasteEntry{ + Namespace: ns.Namespace, + Environment: valueOrDefault(ns.Environment, "unknown"), + CPUWastePercent: cpuWaste, + MemoryWastePercent: memWaste, + EstimatedHourlyWasteCost: ns.HourlyCost * wasteRatio, + }) + } + + sort.Slice(out, func(i, j int) bool { + return out[i].EstimatedHourlyWasteCost > out[j].EstimatedHourlyWasteCost + }) + + if len(out) > 5 { + return out[:5] + } + return out +} + +func usageRatio(usage, request float64) float64 { + if request <= 0 { + return 0 + } + return usage / request +} + +func percent(num, denom float64) float64 { + if denom <= 0 { + return 0 + } + val := (num / denom) * 100 + if val < 0 { + return 0 + } + return val +} + +func wastePercent(usage, request float64) float64 { + if request <= 0 { + return 0 + } + waste := (1 - (usage / request)) * 100 + return clampFloat(waste, 0, 100) +} + +func unusedRatio(usage, request float64) float64 { + if request <= 0 { + return 0 + } + return clampFloat(1-(usage/request), 0, 1) +} + +func wasteCost(nodeCost, usage, request float64) float64 { + if request <= 0 || nodeCost <= 0 { + return 0 + } + return nodeCost * clampFloat(1-(usage/request), 0, 1) +} + +func maxFloat(a, b float64) float64 { + if a > b { + return a + } + return b +} + +func clampFloat(value, min, max float64) float64 { + if value < min { + return min + } + if value > max { + return max + } + return value +} + +func (c *Client) sumNodeHourlyCost(namespaces map[string]*store.NamespaceSummary) float64 { + total := 0.0 + for _, ns := range namespaces { + total += ns.HourlyCost + } + return total +} diff --git a/internal/vm/ingestor.go b/internal/vm/ingestor.go new file mode 100644 index 0000000..5ba8fee --- /dev/null +++ b/internal/vm/ingestor.go @@ -0,0 +1,790 @@ +package vm + +import ( + "bytes" + "compress/gzip" + "context" + "fmt" + "io" + "log" + "math" + "net/http" + "net/url" + "path" + "runtime" + "sort" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/clustercost/clustercost-dashboard/internal/config" + agentv1 "github.com/clustercost/clustercost-dashboard/internal/proto/agent/v1" + "github.com/clustercost/clustercost-dashboard/internal/store" +) + +func safeInt64(u uint64) int64 { + if u > math.MaxInt64 { + return math.MaxInt64 + } + return int64(u) +} + +const ( + defaultIngestPath = "/api/v1/import/prometheus" + defaultTimeout = 5 * time.Second + defaultFlushInterval = 2 * time.Second + defaultBatchBytes = 2 << 20 // 2 MiB + defaultQueueSize = 10000 + defaultWorkerOverride = 0 +) + +var labelReplacer = strings.NewReplacer(`\`, `\\`, "\n", `\n`, `"`, `\"`) + +// Ingestor batches gRPC reports into VictoriaMetrics. +type Ingestor struct { + ingestURL string + authToken string + username string + password string + enableGzip bool + maxBatchBytes int + flushInterval time.Duration + queue chan reportEnvelope + client *http.Client + logger *log.Logger + agentMeta map[string]agentMetadata + stopped atomic.Bool + wg sync.WaitGroup + logLevel string + gzipPool sync.Pool +} + +type reportEnvelope struct { + agentName string + metricsReq *agentv1.MetricsReportRequest + networkReq *agentv1.NetworkReportRequest +} + +type agentMetadata struct { + clusterType string + clusterRegion string +} + +// NewIngestor creates a VictoriaMetrics ingestor. If no URL is configured, it returns nil. +func NewIngestor(cfg config.Config, logger *log.Logger) (*Ingestor, error) { + if cfg.VictoriaMetricsURL == "" { + return nil, nil + } + + ingestURL, err := buildIngestURL(cfg.VictoriaMetricsURL, cfg.VictoriaMetricsIngestPath) + if err != nil { + return nil, err + } + + timeout := cfg.VictoriaMetricsTimeout + if timeout <= 0 { + timeout = defaultTimeout + } + + flushInterval := cfg.VictoriaMetricsFlushInterval + if flushInterval <= 0 { + flushInterval = defaultFlushInterval + } + + batchBytes := cfg.VictoriaMetricsBatchBytes + if batchBytes <= 0 { + batchBytes = defaultBatchBytes + } + + queueSize := cfg.VictoriaMetricsQueueSize + if queueSize <= 0 { + queueSize = defaultQueueSize + } + + workers := cfg.VictoriaMetricsWorkers + if workers <= 0 { + if defaultWorkerOverride > 0 { + workers = defaultWorkerOverride + } else { + workers = max(2, runtime.NumCPU()) + } + } + + transport := &http.Transport{ + MaxIdleConns: 100, + MaxIdleConnsPerHost: 100, + IdleConnTimeout: 90 * time.Second, + } + + ing := &Ingestor{ + ingestURL: ingestURL, + authToken: cfg.VictoriaMetricsToken, + username: cfg.VictoriaMetricsUsername, + password: cfg.VictoriaMetricsPassword, + enableGzip: cfg.VictoriaMetricsGzip, + maxBatchBytes: batchBytes, + flushInterval: flushInterval, + queue: make(chan reportEnvelope, queueSize), + client: &http.Client{Timeout: timeout, Transport: transport}, + logger: logger, + agentMeta: buildAgentMeta(cfg), + logLevel: cfg.LogLevel, + gzipPool: sync.Pool{ + New: func() interface{} { + return gzip.NewWriter(io.Discard) + }, + }, + } + + for i := 0; i < workers; i++ { + ing.wg.Add(1) + go ing.runWorker(i) + } + + return ing, nil +} + +// EnqueueMetrics queues a metrics report for ingestion. +func (i *Ingestor) EnqueueMetrics(agentName string, req *agentv1.MetricsReportRequest) bool { + if i == nil || req == nil || i.stopped.Load() { + return false + } + + select { + case i.queue <- reportEnvelope{agentName: agentName, metricsReq: req}: + return true + default: + if i.logger != nil { + i.logger.Printf("victoria metrics queue full; dropping metrics report for agent %s", agentName) + } + return false + } +} + +// EnqueueNetwork queues a network report for ingestion. +func (i *Ingestor) EnqueueNetwork(agentName string, req *agentv1.NetworkReportRequest) bool { + if i == nil || req == nil || i.stopped.Load() { + return false + } + + select { + case i.queue <- reportEnvelope{agentName: agentName, networkReq: req}: + return true + default: + if i.logger != nil { + i.logger.Printf("victoria metrics queue full; dropping network report for agent %s", agentName) + } + return false + } +} + +// Stop flushes outstanding data and stops background workers. +func (i *Ingestor) Stop() { + if i == nil { + return + } + if i.stopped.Swap(true) { + return + } + close(i.queue) + i.wg.Wait() +} + +func (i *Ingestor) runWorker(id int) { + defer i.wg.Done() + ticker := time.NewTicker(i.flushInterval) + defer ticker.Stop() + + var buf bytes.Buffer + var labelBuf bytes.Buffer // Reusable buffer for label caching + scratch := make([]byte, 64) // Reusable scratch for number formatting + + flush := func() { + if buf.Len() == 0 { + return + } + if err := i.post(buf.Bytes()); err != nil && i.logger != nil { + i.logger.Printf("victoria metrics ingest error: %v", err) + } + buf.Reset() + } + + for { + select { + case env, ok := <-i.queue: + if !ok { + flush() + return + } + i.appendReport(&buf, &labelBuf, scratch, env) + if buf.Len() >= i.maxBatchBytes { + flush() + } + case <-ticker.C: + flush() + } + } +} + +func (i *Ingestor) post(payload []byte) error { + var body io.Reader = bytes.NewReader(payload) + req, err := http.NewRequest(http.MethodPost, i.ingestURL, nil) + if err != nil { + return fmt.Errorf("build request: %w", err) + } + + if i.enableGzip { + var buf bytes.Buffer + gz := i.gzipPool.Get().(*gzip.Writer) + gz.Reset(&buf) + + if _, err := gz.Write(payload); err != nil { + return fmt.Errorf("compress payload: %w", err) + } + if err := gz.Close(); err != nil { + return fmt.Errorf("finalize payload: %w", err) + } + + i.gzipPool.Put(gz) // Return to pool + body = &buf + req.Header.Set("Content-Encoding", "gzip") + } + + req.Body = io.NopCloser(body) + req.Header.Set("Content-Type", "text/plain; version=0.0.4") + + if i.authToken != "" { + req.Header.Set("Authorization", "Bearer "+i.authToken) + } else if i.username != "" || i.password != "" { + req.SetBasicAuth(i.username, i.password) + } + + resp, err := i.client.Do(req) + if err != nil { + return fmt.Errorf("send payload: %w", err) + } + defer func() { _ = resp.Body.Close() }() + + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + return fmt.Errorf("victoria metrics responded with status %d", resp.StatusCode) + } + return nil +} + +func (i *Ingestor) appendReport(buf, labelBuf *bytes.Buffer, scratch []byte, env reportEnvelope) { + if env.metricsReq != nil { + i.appendMetricsReport(buf, labelBuf, scratch, env.agentName, env.metricsReq) + } else if env.networkReq != nil { + i.appendNetworkReport(buf, labelBuf, scratch, env.agentName, env.networkReq) + } +} + +func (i *Ingestor) appendMetricsReport(buf, labelBuf *bytes.Buffer, scratch []byte, agentName string, req *agentv1.MetricsReportRequest) { + if req == nil { + return + } + + tsMillis := reportTimestampMillis(req.TimestampSeconds) + if agentName == "" { + agentName = req.AgentId + } + // Fallback + if agentName == "" { + agentName = "unknown" + } + + meta := i.agentMeta[agentName] + base := baseLabels(agentName, req.ClusterId, "", meta) // ClusterName is not in V2 proto? + // Wait, user proto: cluster_id = 2. No cluster_name. + // We'll leave clusterName empty or rely on agentMeta? + // The proto provided has: agent_id, cluster_id, node_name, availability_zone, timestamp_seconds, pods. + // No cluster_name. + + // Report agent up + labelBuf.Reset() + writeLabels(labelBuf, base) + baseLabelsBlob := labelBuf.Bytes() // Safe to use until labelBuf reset + + writeFlagSample(buf, scratch, "clustercost_agent_up", baseLabelsBlob, 1, tsMillis) + + // 2. Process Pods & Aggregate Namespace Data + type nsAgg struct { + hourlyCost float64 + podCount int64 + cpuUsageMilli int64 + memoryRssBytes int64 + cpuReqMilli int64 + memReqBytes int64 + netTxBytes int64 + netRxBytes int64 + egressPublic int64 + egressCrossAZ int64 + egressInternal int64 + } + // map[namespace]*nsAgg + nsMap := make(map[string]*nsAgg) + pricing := store.NewPricingCatalog(nil) + region := req.Region + if region == "" { + region = req.AvailabilityZone + } + if region == "" { + region = "us-east-1" + } + instanceType := req.InstanceType + if instanceType == "" { + instanceType = "default" + } + vcpus := safeInt64(0) + ramBytes := safeInt64(0) + if req.NodeName != "" { + for _, node := range req.Nodes { + if node == nil || node.NodeName != req.NodeName { + continue + } + if node.CapacityCpuMillicores > 0 { + vcpus = safeInt64(node.CapacityCpuMillicores / 1000) + } else if node.AllocatableCpuMillicores > 0 { + vcpus = safeInt64(node.AllocatableCpuMillicores / 1000) + } + if node.CapacityMemoryBytes > 0 { + ramBytes = safeInt64(node.CapacityMemoryBytes) + } else if node.AllocatableMemoryBytes > 0 { + ramBytes = safeInt64(node.AllocatableMemoryBytes) + } + break + } + } + cpuPrice, memPrice := pricing.GetNodeResourcePrices(context.Background(), region, instanceType, vcpus, ramBytes) + + for _, pod := range req.Pods { + if pod == nil { + continue + } + + // Labels are removed in V2 proto provided by user. + // We can't determine environment or owners from labels anymore. + // We will set environment to "unknown" or "production" default? + environment := "production" // Default assumption without labels + + nodeName := req.NodeName + + region := req.Region + if region == "" { + region = req.AvailabilityZone + } + + // Calculate Totals and Costs + // CPU + cpuUsageMilli := safeInt64(0) + cpuReq := safeInt64(0) + cpuLim := safeInt64(0) + if pod.Cpu != nil { + cpuUsageMilli = safeInt64(pod.Cpu.UsageMillicores) + if i.logLevel == "debug" { + if i.logger != nil && cpuUsageMilli == 0 { + i.logger.Printf("[DEBUG-CPU] Pod %s/%s has 0 CPU usage. Raw Proto: %+v", pod.Namespace, pod.PodName, pod.Cpu) + } else if i.logger != nil { + i.logger.Printf("[DEBUG-CPU] Pod %s/%s CPU Usage: %d", pod.Namespace, pod.PodName, cpuUsageMilli) + } + } + cpuReq = safeInt64(pod.Cpu.RequestMillicores) + cpuLim = safeInt64(pod.Cpu.LimitMillicores) + } + + // Memory + memBytes := safeInt64(0) + memReq := safeInt64(0) + memLim := safeInt64(0) + if pod.Memory != nil { + memBytes = safeInt64(pod.Memory.RssBytes) + memReq = safeInt64(pod.Memory.RequestBytes) + memLim = safeInt64(pod.Memory.LimitBytes) + } + + // Network + netTx := safeInt64(0) + netRx := safeInt64(0) + egressPublic := safeInt64(0) + egressCrossAZ := safeInt64(0) + egressInternal := safeInt64(0) + if pod.Network != nil { + netTx = safeInt64(pod.Network.BytesSent) + netRx = safeInt64(pod.Network.BytesReceived) + egressPublic = safeInt64(pod.Network.EgressPublicBytes) + egressCrossAZ = safeInt64(pod.Network.EgressCrossAzBytes) + egressInternal = safeInt64(pod.Network.EgressInternalBytes) + } + + // Prepare cached labels for this pod + labelBuf.Reset() + writeLabels(labelBuf, base, + label{"namespace", pod.Namespace}, + label{"pod", pod.PodName}, + label{"node", nodeName}, + label{"availability_zone", req.AvailabilityZone}, + label{"region", region}, + label{"instance_type", req.InstanceType}, + label{"environment", environment}, + ) + podLabelsBlob := labelBuf.Bytes() + + writeIntSample(buf, scratch, "clustercost_pod_cpu_usage_milli", podLabelsBlob, cpuUsageMilli, tsMillis) + writeIntSample(buf, scratch, "clustercost_pod_cpu_request_millicores", podLabelsBlob, cpuReq, tsMillis) + writeIntSample(buf, scratch, "clustercost_pod_cpu_limit_millicores", podLabelsBlob, cpuLim, tsMillis) + + writeIntSample(buf, scratch, "clustercost_pod_memory_rss_bytes", podLabelsBlob, memBytes, tsMillis) + writeIntSample(buf, scratch, "clustercost_pod_memory_request_bytes", podLabelsBlob, memReq, tsMillis) + writeIntSample(buf, scratch, "clustercost_pod_memory_limit_bytes", podLabelsBlob, memLim, tsMillis) + + writeIntSample(buf, scratch, "clustercost_pod_network_tx_bytes_total", podLabelsBlob, netTx, tsMillis) + writeIntSample(buf, scratch, "clustercost_pod_network_rx_bytes_total", podLabelsBlob, netRx, tsMillis) + writeIntSample(buf, scratch, "clustercost_pod_network_egress_public_bytes_total", podLabelsBlob, egressPublic, tsMillis) + writeIntSample(buf, scratch, "clustercost_pod_network_egress_cross_az_bytes_total", podLabelsBlob, egressCrossAZ, tsMillis) + writeIntSample(buf, scratch, "clustercost_pod_network_egress_internal_bytes_total", podLabelsBlob, egressInternal, tsMillis) + + cpuReqCores := float64(cpuReq) / 1000.0 + memReqGB := float64(memReq) / (1024 * 1024 * 1024) + hourlyCost := (cpuReqCores * cpuPrice) + (memReqGB * memPrice) + + writeFloatSample(buf, scratch, "clustercost_pod_hourly_cost", podLabelsBlob, hourlyCost, tsMillis) + + // Aggregate for Namespace + if nsMap[pod.Namespace] == nil { + nsMap[pod.Namespace] = &nsAgg{} + } + agg := nsMap[pod.Namespace] + agg.podCount++ + agg.cpuUsageMilli += cpuUsageMilli + agg.memoryRssBytes += memBytes + agg.hourlyCost += hourlyCost + agg.cpuReqMilli += cpuReq + agg.netTxBytes += netTx + agg.netRxBytes += netRx + agg.egressPublic += egressPublic + agg.egressCrossAZ += egressCrossAZ + agg.egressInternal += egressInternal + } + + // 3. Emit Aggregated Namespace Metrics & Calculate Cluster Totals + clusterTx := safeInt64(0) + clusterRx := safeInt64(0) + clusterEgressPublic := safeInt64(0) + clusterEgressCrossAZ := safeInt64(0) + clusterEgressInternal := safeInt64(0) + for ns, agg := range nsMap { + clusterTx += agg.netTxBytes + clusterRx += agg.netRxBytes + clusterEgressPublic += agg.egressPublic + clusterEgressCrossAZ += agg.egressCrossAZ + clusterEgressInternal += agg.egressInternal + + labelBuf.Reset() + writeLabels(labelBuf, base, + label{"namespace", ns}, + label{"environment", "production"}, + ) + nsLabelsBlob := labelBuf.Bytes() + + writeIntSample(buf, scratch, "clustercost_namespace_pod_count", nsLabelsBlob, agg.podCount, tsMillis) + writeIntSample(buf, scratch, "clustercost_namespace_cpu_usage_milli", nsLabelsBlob, agg.cpuUsageMilli, tsMillis) + writeIntSample(buf, scratch, "clustercost_namespace_memory_rss_bytes_total", nsLabelsBlob, agg.memoryRssBytes, tsMillis) + writeFloatSample(buf, scratch, "clustercost_namespace_hourly_cost", nsLabelsBlob, agg.hourlyCost, tsMillis) + writeIntSample(buf, scratch, "clustercost_namespace_cpu_request_millicores", nsLabelsBlob, agg.cpuReqMilli, tsMillis) + writeIntSample(buf, scratch, "clustercost_namespace_memory_request_bytes", nsLabelsBlob, agg.memReqBytes, tsMillis) + writeIntSample(buf, scratch, "clustercost_namespace_network_tx_bytes_total", nsLabelsBlob, agg.netTxBytes, tsMillis) + writeIntSample(buf, scratch, "clustercost_namespace_network_rx_bytes_total", nsLabelsBlob, agg.netRxBytes, tsMillis) + writeIntSample(buf, scratch, "clustercost_namespace_network_egress_public_bytes_total", nsLabelsBlob, agg.egressPublic, tsMillis) + writeIntSample(buf, scratch, "clustercost_namespace_network_egress_cross_az_bytes_total", nsLabelsBlob, agg.egressCrossAZ, tsMillis) + writeIntSample(buf, scratch, "clustercost_namespace_network_egress_internal_bytes_total", nsLabelsBlob, agg.egressInternal, tsMillis) + } + + // Cluster totals will be emitted after Node processing + + // 3b. Emit Node Metrics + for _, node := range req.Nodes { + if node == nil || node.NodeName == "" { + continue + } + labelBuf.Reset() + writeLabels(labelBuf, base, label{"node", node.NodeName}) + if node.NodeName == req.NodeName && req.InstanceType != "" { + writeLabel(labelBuf, label{"instance_type", req.InstanceType}) + } + nodeLabelsBlob := labelBuf.Bytes() + + writeIntSample(buf, scratch, "clustercost_node_cpu_usage_milli", nodeLabelsBlob, safeInt64(node.CpuUsageMillicores), tsMillis) + writeIntSample(buf, scratch, "clustercost_node_memory_usage_bytes", nodeLabelsBlob, safeInt64(node.MemoryUsageBytes), tsMillis) + writeIntSample(buf, scratch, "clustercost_node_cpu_capacity_milli", nodeLabelsBlob, safeInt64(node.CapacityCpuMillicores), tsMillis) + writeIntSample(buf, scratch, "clustercost_node_memory_capacity_bytes", nodeLabelsBlob, safeInt64(node.CapacityMemoryBytes), tsMillis) + writeIntSample(buf, scratch, "clustercost_node_cpu_allocatable_milli", nodeLabelsBlob, safeInt64(node.AllocatableCpuMillicores), tsMillis) + writeIntSample(buf, scratch, "clustercost_node_memory_allocatable_bytes", nodeLabelsBlob, safeInt64(node.AllocatableMemoryBytes), tsMillis) + writeIntSample(buf, scratch, "clustercost_node_cpu_requested_milli", nodeLabelsBlob, safeInt64(node.RequestedCpuMillicores), tsMillis) + writeIntSample(buf, scratch, "clustercost_node_memory_requested_bytes", nodeLabelsBlob, safeInt64(node.RequestedMemoryBytes), tsMillis) + writeIntSample(buf, scratch, "clustercost_node_cpu_throttling_ns_total", nodeLabelsBlob, safeInt64(node.ThrottlingNs), tsMillis) + + if node.AllocatableCpuMillicores > 0 { + cpuPct := (float64(node.CpuUsageMillicores) / float64(node.AllocatableCpuMillicores)) * 100 + writeFloatSample(buf, scratch, "clustercost_node_cpu_usage_percent", nodeLabelsBlob, cpuPct, tsMillis) + } + if node.AllocatableMemoryBytes > 0 { + memPct := (float64(node.MemoryUsageBytes) / float64(node.AllocatableMemoryBytes)) * 100 + writeFloatSample(buf, scratch, "clustercost_node_memory_usage_percent", nodeLabelsBlob, memPct, tsMillis) + } + + // Node Network Metrics (Host Traffic) + if node.Network != nil { + nodeTx := safeInt64(node.Network.BytesSent) + nodeRx := safeInt64(node.Network.BytesReceived) + nodeEgressPublic := safeInt64(node.Network.EgressPublicBytes) + nodeEgressCrossAZ := safeInt64(node.Network.EgressCrossAzBytes) + nodeEgressInternal := safeInt64(node.Network.EgressInternalBytes) + + writeIntSample(buf, scratch, "clustercost_node_network_tx_bytes_total", nodeLabelsBlob, nodeTx, tsMillis) + writeIntSample(buf, scratch, "clustercost_node_network_rx_bytes_total", nodeLabelsBlob, nodeRx, tsMillis) + writeIntSample(buf, scratch, "clustercost_node_network_egress_public_bytes_total", nodeLabelsBlob, nodeEgressPublic, tsMillis) + writeIntSample(buf, scratch, "clustercost_node_network_egress_cross_az_bytes_total", nodeLabelsBlob, nodeEgressCrossAZ, tsMillis) + writeIntSample(buf, scratch, "clustercost_node_network_egress_internal_bytes_total", nodeLabelsBlob, nodeEgressInternal, tsMillis) + + // Aggregate Node Traffic to Cluster Totals + clusterTx += nodeTx + clusterRx += nodeRx + clusterEgressPublic += nodeEgressPublic + clusterEgressCrossAZ += nodeEgressCrossAZ + clusterEgressInternal += nodeEgressInternal + } + } + + // 4. Emit Cluster Totals (Pod + Node) + if clusterTx > 0 || clusterRx > 0 { + writeIntSample(buf, scratch, "clustercost_cluster_network_tx_bytes_total", baseLabelsBlob, clusterTx, tsMillis) + writeIntSample(buf, scratch, "clustercost_cluster_network_rx_bytes_total", baseLabelsBlob, clusterRx, tsMillis) + writeIntSample(buf, scratch, "clustercost_cluster_network_egress_public_bytes_total", baseLabelsBlob, clusterEgressPublic, tsMillis) + writeIntSample(buf, scratch, "clustercost_cluster_network_egress_cross_az_bytes_total", baseLabelsBlob, clusterEgressCrossAZ, tsMillis) + writeIntSample(buf, scratch, "clustercost_cluster_network_egress_internal_bytes_total", baseLabelsBlob, clusterEgressInternal, tsMillis) + } + +} + +func (i *Ingestor) appendNetworkReport(buf, labelBuf *bytes.Buffer, scratch []byte, agentName string, req *agentv1.NetworkReportRequest) { + if req == nil { + return + } + tsMillis := reportTimestampMillis(req.TimestampSeconds) + if agentName == "" { + agentName = req.AgentId + } + if agentName == "" { + agentName = "unknown" + } + meta := i.agentMeta[agentName] + base := baseLabels(agentName, req.ClusterId, "", meta) + + // Decode Compact Connections + endpoints := req.Endpoints + for _, compact := range req.CompactConnections { + if compact == nil { + continue + } + if int(compact.SrcIndex) >= len(endpoints) || int(compact.DstIndex) >= len(endpoints) { + continue // Invalid index + } + src := endpoints[compact.SrcIndex] + dst := endpoints[compact.DstIndex] + + // Build full connection object for label generation + labelBuf.Reset() + // Use specialized compact writer to avoid allocs + writeCompactLabels(labelBuf, base, compact, src, dst) + labelsBlob := labelBuf.Bytes() + + writeIntSample(buf, scratch, "clustercost_connection_bytes_sent_total", labelsBlob, safeInt64(compact.BytesSent), tsMillis) + writeIntSample(buf, scratch, "clustercost_connection_bytes_received_total", labelsBlob, safeInt64(compact.BytesReceived), tsMillis) + } +} + +func buildIngestURL(baseURL, ingestPath string) (string, error) { + parsed, err := url.Parse(baseURL) + if err != nil { + return "", fmt.Errorf("invalid victoria metrics url: %w", err) + } + if parsed.Scheme == "" { + return "", fmt.Errorf("victoria metrics url missing scheme: %s", baseURL) + } + if ingestPath == "" { + ingestPath = defaultIngestPath + } + parsed.Path = path.Join(parsed.Path, ingestPath) + return parsed.String(), nil +} + +func buildAgentMeta(cfg config.Config) map[string]agentMetadata { + out := make(map[string]agentMetadata, len(cfg.Agents)) + for _, agent := range cfg.Agents { + out[agent.Name] = agentMetadata{ + clusterType: agent.Type, + clusterRegion: agent.Region, + } + } + return out +} + +type label struct { + key string + value string +} + +func baseLabels(agentName, clusterID, clusterName string, meta agentMetadata) []label { + labels := make([]label, 0, 5) + if clusterID != "" { + labels = append(labels, label{"cluster_id", clusterID}) + } + if clusterName != "" { + labels = append(labels, label{"cluster_name", clusterName}) + } + if meta.clusterType != "" { + labels = append(labels, label{"cluster_type", meta.clusterType}) + } + if meta.clusterRegion != "" { + labels = append(labels, label{"cluster_region", meta.clusterRegion}) + } + if agentName != "" { + labels = append(labels, label{"agent_id", agentName}) + } + return labels +} + +func writeIntSample(buf *bytes.Buffer, scratch []byte, name string, labels []byte, value int64, tsMillis int64) { + buf.WriteString(name) + if len(labels) > 0 { + buf.WriteByte('{') + buf.Write(labels) + buf.WriteByte('}') + } + buf.WriteByte(' ') + buf.Write(strconv.AppendInt(scratch[:0], value, 10)) + buf.WriteByte(' ') + buf.Write(strconv.AppendInt(scratch[:0], tsMillis, 10)) + buf.WriteByte('\n') +} + +func writeFlagSample(buf *bytes.Buffer, scratch []byte, name string, labels []byte, value int64, tsMillis int64) { + writeIntSample(buf, scratch, name, labels, value, tsMillis) +} + +func writeFloatSample(buf *bytes.Buffer, scratch []byte, name string, labels []byte, value float64, tsMillis int64) { + buf.WriteString(name) + if len(labels) > 0 { + buf.WriteByte('{') + buf.Write(labels) + buf.WriteByte('}') + } + buf.WriteByte(' ') + buf.Write(strconv.AppendFloat(scratch[:0], value, 'f', -1, 64)) + buf.WriteByte(' ') + buf.Write(strconv.AppendInt(scratch[:0], tsMillis, 10)) + buf.WriteByte('\n') +} + +func writeLabels(buf *bytes.Buffer, base []label, extra ...label) { + first := true + for _, l := range base { + if !first { + buf.WriteByte(',') + } + first = false + writeLabelKV(buf, l.key, l.value) + } + for _, l := range extra { + if strings.TrimSpace(l.value) != "" { + if !first { + buf.WriteByte(',') + } + first = false + writeLabelKV(buf, l.key, l.value) + } + } +} + +func writeLabel(buf *bytes.Buffer, l label) { + if buf.Len() > 0 { + buf.WriteByte(',') + } + writeLabelKV(buf, l.key, l.value) +} + +func writeLabelKV(buf *bytes.Buffer, k, v string) { + buf.WriteString(k) + buf.WriteString(`="`) + _, _ = labelReplacer.WriteString(buf, v) // Uses global replacer and writes directly to buffer + buf.WriteByte('"') +} + +func writeCompactLabels(buf *bytes.Buffer, base []label, compact *agentv1.CompactNetworkConnection, src, dst *agentv1.NetworkEndpoint) { + writeLabels(buf, base) // Writes base labels + + // Write extra manually + writeLabel(buf, label{"protocol", strconv.FormatUint(uint64(compact.Protocol), 10)}) + writeLabel(buf, label{"egress_class", compact.EgressClass}) + writeLabel(buf, label{"dst_kind", compact.DstKind}) + writeLabel(buf, label{"service_match", compact.ServiceMatch}) + writeLabel(buf, label{"is_egress", strconv.FormatBool(compact.IsEgress)}) + + if src != nil { + writeEndpointLabels(buf, "src", src) + } + if dst != nil { + writeEndpointLabels(buf, "dst", dst) + services := joinServiceRefs(dst.Services) + if services != "" { + writeLabel(buf, label{"dst_services", services}) + } + } +} + +func writeEndpointLabels(buf *bytes.Buffer, prefix string, ep *agentv1.NetworkEndpoint) { + writeLabel(buf, label{prefix + "_ip", ep.Ip}) + writeLabel(buf, label{prefix + "_namespace", ep.Namespace}) + writeLabel(buf, label{prefix + "_pod", ep.PodName}) + writeLabel(buf, label{prefix + "_node", ep.NodeName}) + writeLabel(buf, label{prefix + "_availability_zone", ep.AvailabilityZone}) + writeLabel(buf, label{prefix + "_dns_name", ep.DnsName}) +} + +func reportTimestampMillis(tsSeconds int64) int64 { + if tsSeconds > 0 { + return tsSeconds * 1000 + } + return time.Now().UnixMilli() +} + +func joinServiceRefs(services []*agentv1.ServiceRef) string { + if len(services) == 0 { + return "" + } + parts := make([]string, 0, len(services)) + for _, svc := range services { + if svc == nil { + continue + } + if svc.Namespace == "" && svc.Name == "" { + continue + } + if svc.Namespace == "" { + parts = append(parts, svc.Name) + continue + } + parts = append(parts, svc.Namespace+"/"+svc.Name) + } + sort.Strings(parts) + return strings.Join(parts, ",") +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} diff --git a/internal/vm/ingestor_test.go b/internal/vm/ingestor_test.go new file mode 100644 index 0000000..9457c6f --- /dev/null +++ b/internal/vm/ingestor_test.go @@ -0,0 +1,379 @@ +package vm + +import ( + "bytes" + "strconv" + "strings" + "testing" + + agentv1 "github.com/clustercost/clustercost-dashboard/internal/proto/agent/v1" +) + +func TestAppendReportConnectionsEmitsMetrics(t *testing.T) { + endpoints := []*agentv1.NetworkEndpoint{ + { + Ip: "10.0.0.1", + DnsName: "api.internal.local", + Namespace: "default", + PodName: "pod-a", + NodeName: "node-a", + AvailabilityZone: "us-east-1a", + }, + { + Ip: "1.1.1.1", + DnsName: "api.example.com", + AvailabilityZone: "us-east-1a", + Services: []*agentv1.ServiceRef{ + {Namespace: "default", Name: "api"}, + }, + }, + } + + req := &agentv1.NetworkReportRequest{ + AgentId: "agent-1", + ClusterId: "cluster-1", + TimestampSeconds: 1700000000, + Endpoints: endpoints, + CompactConnections: []*agentv1.CompactNetworkConnection{ + { + SrcIndex: 0, + DstIndex: 1, + Protocol: 6, + BytesSent: 100, + BytesReceived: 200, + EgressClass: "public_internet", + DstKind: "external", + ServiceMatch: "none", + IsEgress: true, + }, + { + SrcIndex: 0, + DstIndex: 1, // reusing for simplicity + Protocol: 17, + BytesSent: 300, + BytesReceived: 400, + }, + }, + } + + ing := &Ingestor{} + var buf bytes.Buffer + ing.appendReport(&buf, &bytes.Buffer{}, make([]byte, 64), reportEnvelope{agentName: "agent-1", networkReq: req}) + + lines := strings.Split(strings.TrimSpace(buf.String()), "\n") + connLine := findMetricLine(lines, "clustercost_connection_bytes_sent_total") + if connLine == "" { + t.Fatalf("expected connection bytes metric in output") + } + + _, labels, value, ts := parseMetricLine(t, connLine) + if value != "100" { + t.Fatalf("expected bytes sent 100, got %s", value) + } + if ts != 1700000000000 { + t.Fatalf("expected timestamp 1700000000000, got %d", ts) + } + + assertLabel(t, labels, "cluster_id", "cluster-1") + assertLabel(t, labels, "agent_id", "agent-1") + assertLabel(t, labels, "protocol", "6") + assertLabel(t, labels, "egress_class", "public_internet") + assertLabel(t, labels, "dst_kind", "external") + assertLabel(t, labels, "service_match", "none") + assertLabel(t, labels, "is_egress", "true") + assertLabel(t, labels, "src_ip", "10.0.0.1") + assertLabel(t, labels, "src_namespace", "default") + assertLabel(t, labels, "src_pod", "pod-a") + assertLabel(t, labels, "src_node", "node-a") + assertLabel(t, labels, "src_availability_zone", "us-east-1a") + assertLabel(t, labels, "src_dns_name", "api.internal.local") + assertLabel(t, labels, "dst_ip", "1.1.1.1") + assertLabel(t, labels, "dst_availability_zone", "us-east-1a") + assertLabel(t, labels, "dst_dns_name", "api.example.com") + assertLabel(t, labels, "dst_services", "default/api") + + // Cluster metrics now aggregated in MetricsReport, not NetworkReport + + // Egress cost metrics removed from the proto; bytes-only aggregation remains. +} + +func TestAppendReportEmitsNodeMetrics(t *testing.T) { + req := &agentv1.MetricsReportRequest{ + AgentId: "agent-1", + ClusterId: "cluster-1", + TimestampSeconds: 1700000000, + Nodes: []*agentv1.NodeMetric{ + { + NodeName: "node-a", + CpuUsageMillicores: 1500, + MemoryUsageBytes: 2147483648, + CapacityCpuMillicores: 4000, + CapacityMemoryBytes: 8589934592, + AllocatableCpuMillicores: 3500, + AllocatableMemoryBytes: 7516192768, + RequestedCpuMillicores: 2000, + RequestedMemoryBytes: 3221225472, + ThrottlingNs: 123456789, + }, + }, + } + + ing := &Ingestor{} + var buf bytes.Buffer + ing.appendReport(&buf, &bytes.Buffer{}, make([]byte, 64), reportEnvelope{agentName: "agent-1", metricsReq: req}) + + lines := strings.Split(strings.TrimSpace(buf.String()), "\n") + cpuLine := findMetricLine(lines, "clustercost_node_cpu_usage_milli") + if cpuLine == "" { + t.Fatalf("expected node cpu usage metric in output") + } + _, labels, value, _ := parseMetricLine(t, cpuLine) + if value != "1500" { + t.Fatalf("expected node cpu usage 1500, got %s", value) + } + assertLabel(t, labels, "node", "node-a") + + memLine := findMetricLine(lines, "clustercost_node_memory_allocatable_bytes") + if memLine == "" { + t.Fatalf("expected node allocatable memory metric in output") + } + _, labels, value, _ = parseMetricLine(t, memLine) + if value != "7516192768" { + t.Fatalf("expected allocatable memory 7516192768, got %s", value) + } + assertLabel(t, labels, "node", "node-a") + + throttleLine := findMetricLine(lines, "clustercost_node_cpu_throttling_ns_total") + if throttleLine == "" { + t.Fatalf("expected node throttling metric in output") + } + _, labels, value, _ = parseMetricLine(t, throttleLine) + if value != "123456789" { + t.Fatalf("expected node throttling 123456789, got %s", value) + } + assertLabel(t, labels, "node", "node-a") +} + +func TestAppendReportEmitsPodAndNamespaceHourlyCost(t *testing.T) { + req := &agentv1.MetricsReportRequest{ + AgentId: "agent-1", + ClusterId: "cluster-1", + NodeName: "node-a", + InstanceType: "t3.medium", + TimestampSeconds: 1700000000, + Nodes: []*agentv1.NodeMetric{ + { + NodeName: "node-a", + CpuUsageMillicores: 1200, + CapacityCpuMillicores: 2000, + CapacityMemoryBytes: 8 * 1024 * 1024 * 1024, + }, + }, + Pods: []*agentv1.PodMetric{ + { + Namespace: "payments", + PodName: "api-1", + Cpu: &agentv1.CpuMetrics{ + RequestMillicores: 500, + }, + Memory: &agentv1.MemoryMetrics{ + RequestBytes: 1024 * 1024 * 1024, + }, + Network: &agentv1.NetworkMetrics{ + BytesSent: 1000, + BytesReceived: 2000, + }, + }, + }, + } + + ing := &Ingestor{} + var buf bytes.Buffer + ing.appendReport(&buf, &bytes.Buffer{}, make([]byte, 64), reportEnvelope{agentName: "agent-1", metricsReq: req}) + + lines := strings.Split(strings.TrimSpace(buf.String()), "\n") + podCostLine := findMetricLine(lines, "clustercost_pod_hourly_cost") + if podCostLine == "" { + t.Fatalf("expected pod hourly cost metric in output") + } + _, _, podCostValue, _ := parseMetricLine(t, podCostLine) + podCost, err := strconv.ParseFloat(podCostValue, 64) + if err != nil { + t.Fatalf("expected pod hourly cost float, got %s", podCostValue) + } + if diff := podCost - 0.0078; diff < -0.0001 || diff > 0.0001 { + t.Fatalf("expected pod hourly cost ~0.0078, got %v", podCost) + } + + nsCostLine := findMetricLine(lines, "clustercost_namespace_hourly_cost") + if nsCostLine == "" { + t.Fatalf("expected namespace hourly cost metric in output") + } + _, labels, nsCostValue, _ := parseMetricLine(t, nsCostLine) + if labels["namespace"] != "payments" { + t.Fatalf("expected namespace payments, got %s", labels["namespace"]) + } + nsCost, err := strconv.ParseFloat(nsCostValue, 64) + if err != nil { + t.Fatalf("expected namespace hourly cost float, got %s", nsCostValue) + } + if diff := nsCost - 0.0078; diff < -0.0001 || diff > 0.0001 { + t.Fatalf("expected namespace hourly cost ~0.0078, got %v", nsCost) + } + + nodeAllocLine := findMetricLine(lines, "clustercost_node_cpu_allocatable_milli") + if nodeAllocLine == "" { + t.Fatalf("expected node allocatable cpu metric in output") + } + _, labels, _, _ = parseMetricLine(t, nodeAllocLine) + if labels["instance_type"] != "t3.medium" { + t.Fatalf("expected instance_type t3.medium, got %s", labels["instance_type"]) + } +} + +func TestReportTimestampMillisUsesReportTimestamp(t *testing.T) { + got := reportTimestampMillis(1700001234) + if got != 1700001234000 { + t.Fatalf("expected timestamp seconds converted to ms, got %d", got) + } +} + +func findMetricLine(lines []string, metric string) string { + for _, line := range lines { + if strings.HasPrefix(line, metric+"{") || strings.HasPrefix(line, metric+" ") { + return line + } + } + return "" +} + +func parseMetricLine(t *testing.T, line string) (string, map[string]string, string, int64) { + fields := strings.Fields(line) + if len(fields) < 3 { + t.Fatalf("expected 3 fields in metric line, got %q", line) + } + + nameAndLabels := fields[0] + value := fields[1] + ts, err := strconv.ParseInt(fields[2], 10, 64) + if err != nil { + t.Fatalf("invalid timestamp %q", fields[2]) + } + + name := nameAndLabels + labels := map[string]string{} + if idx := strings.Index(nameAndLabels, "{"); idx != -1 { + name = nameAndLabels[:idx] + labelsStr := strings.TrimSuffix(nameAndLabels[idx+1:], "}") + if labelsStr != "" { + for _, part := range strings.Split(labelsStr, ",") { + kv := strings.SplitN(part, "=", 2) + if len(kv) != 2 { + continue + } + key := kv[0] + val := strings.Trim(kv[1], "\"") + labels[key] = val + } + } + } + + return name, labels, value, ts +} + +func assertLabel(t *testing.T, labels map[string]string, key, expected string) { + t.Helper() + if labels[key] != expected { + t.Fatalf("expected label %s=%s, got %s", key, expected, labels[key]) + } +} + +func TestReportEmitsEgressBreakdownMetrics(t *testing.T) { + req := &agentv1.MetricsReportRequest{ + AgentId: "agent-1", + TimestampSeconds: 1700000000, + Pods: []*agentv1.PodMetric{ + { + Namespace: "backend", + PodName: "api-1", + Network: &agentv1.NetworkMetrics{ + BytesSent: 1000, + BytesReceived: 2000, + EgressPublicBytes: 500, + EgressCrossAzBytes: 300, + EgressInternalBytes: 200, + }, + }, + }, + } + + ing := &Ingestor{} + var buf bytes.Buffer + ing.appendReport(&buf, &bytes.Buffer{}, make([]byte, 64), reportEnvelope{agentName: "agent-1", metricsReq: req}) + + lines := strings.Split(strings.TrimSpace(buf.String()), "\n") + + // Verify Pod Metrics + checkMetric(t, lines, "clustercost_pod_network_egress_public_bytes_total", "500") + checkMetric(t, lines, "clustercost_pod_network_egress_cross_az_bytes_total", "300") + checkMetric(t, lines, "clustercost_pod_network_egress_internal_bytes_total", "200") + + // Verify Namespace Metrics + checkMetric(t, lines, "clustercost_namespace_network_egress_public_bytes_total", "500") + checkMetric(t, lines, "clustercost_namespace_network_egress_cross_az_bytes_total", "300") + checkMetric(t, lines, "clustercost_namespace_network_egress_internal_bytes_total", "200") + + // Verify Cluster Metrics + checkMetric(t, lines, "clustercost_cluster_network_egress_public_bytes_total", "500") + checkMetric(t, lines, "clustercost_cluster_network_egress_cross_az_bytes_total", "300") + checkMetric(t, lines, "clustercost_cluster_network_egress_internal_bytes_total", "200") +} + +func TestReportEmitsNodeNetworkMetrics(t *testing.T) { + req := &agentv1.MetricsReportRequest{ + AgentId: "agent-1", + TimestampSeconds: 1700000000, + Nodes: []*agentv1.NodeMetric{ + { + NodeName: "node-1", + Network: &agentv1.NetworkMetrics{ + BytesSent: 100, + BytesReceived: 200, + EgressPublicBytes: 50, + EgressCrossAzBytes: 30, + EgressInternalBytes: 20, + }, + }, + }, + } + + ing := &Ingestor{} + var buf bytes.Buffer + ing.appendReport(&buf, &bytes.Buffer{}, make([]byte, 64), reportEnvelope{agentName: "agent-1", metricsReq: req}) + + lines := strings.Split(strings.TrimSpace(buf.String()), "\n") + + // Verify Node Metrics + checkMetric(t, lines, "clustercost_node_network_tx_bytes_total", "100") + checkMetric(t, lines, "clustercost_node_network_rx_bytes_total", "200") + checkMetric(t, lines, "clustercost_node_network_egress_public_bytes_total", "50") + + // Verify Cluster Aggregation (Should contain Node metrics) + checkMetric(t, lines, "clustercost_cluster_network_tx_bytes_total", "100") + checkMetric(t, lines, "clustercost_cluster_network_egress_public_bytes_total", "50") +} + +func checkMetric(t *testing.T, lines []string, name, expectedVal string) { + t.Helper() + line := findMetricLine(lines, name) + if line == "" { + t.Fatalf("metric %s not found", name) + } + fields := strings.Fields(line) + if len(fields) < 2 { + t.Fatalf("invalid metric line: %s", line) + } + if fields[1] != expectedVal { + t.Errorf("metric %s: expected %s, got %s", name, expectedVal, fields[1]) + } +} diff --git a/internal/vm/topology_test.go b/internal/vm/topology_test.go new file mode 100644 index 0000000..6ff1f77 --- /dev/null +++ b/internal/vm/topology_test.go @@ -0,0 +1,84 @@ +package vm + +import ( + "strings" + "testing" +) + +func TestConnectionMetricExpr_NoNamespace(t *testing.T) { + expr := connectionMetricExpr( + "clustercost_connection_bytes_sent_total", + map[string]string{"cluster_id": "cluster-1"}, + "", + "1h", + 1700000000, + "src_namespace,dst_namespace,protocol", + "increase", + ) + + if !strings.Contains(expr, `sum by (src_namespace,dst_namespace,protocol)`) { + t.Fatalf("expected sum by clause, got %s", expr) + } + if !strings.Contains(expr, `increase(clustercost_connection_bytes_sent_total{cluster_id="cluster-1"}[1h] @ 1700000000)`) { + t.Fatalf("expected increase selector with @ end, got %s", expr) + } + if strings.Contains(expr, "or") { + t.Fatalf("did not expect namespace filter OR, got %s", expr) + } +} + +func TestConnectionMetricExpr_WithNamespace(t *testing.T) { + expr := connectionMetricExpr( + "clustercost_connection_bytes_sent_total", + map[string]string{"cluster_id": "cluster-1"}, + "payments", + "30m", + 1700001234, + "src_namespace,dst_namespace,protocol", + "increase", + ) + + if !strings.Contains(expr, `or`) { + t.Fatalf("expected namespace filter OR, got %s", expr) + } + if !strings.Contains(expr, `src_namespace="payments"`) || !strings.Contains(expr, `dst_namespace="payments"`) { + t.Fatalf("expected namespace label filters, got %s", expr) + } + if !strings.Contains(expr, `@ 1700001234`) { + t.Fatalf("expected explicit end timestamp, got %s", expr) + } +} + +func TestEdgeFromLabelsParsesProtocol(t *testing.T) { + edge := edgeFromLabels(map[string]string{ + "src_namespace": "payments", + "src_pod": "api-1", + "src_node": "node-a", + "src_ip": "10.0.0.1", + "src_dns_name": "api.internal.local", + "src_availability_zone": "us-east-1a", + "dst_namespace": "payments", + "dst_pod": "db-1", + "dst_node": "node-b", + "dst_ip": "10.0.0.2", + "dst_dns_name": "db.internal.local", + "dst_availability_zone": "us-east-1b", + "dst_kind": "pod", + "service_match": "endpoint", + "dst_services": "payments/db", + "protocol": "6", + }, nil) + + if edge == nil { + t.Fatalf("expected edge from labels") + } + if edge.Protocol != 6 { + t.Fatalf("expected protocol 6, got %d", edge.Protocol) + } + if edge.SrcAZ != "us-east-1a" || edge.DstAZ != "us-east-1b" { + t.Fatalf("unexpected AZs: %s %s", edge.SrcAZ, edge.DstAZ) + } + if edge.SrcDNSName != "api.internal.local" || edge.DstDNSName != "db.internal.local" { + t.Fatalf("unexpected dns names: %s %s", edge.SrcDNSName, edge.DstDNSName) + } +} diff --git a/scripts/generate_pricing.go b/scripts/generate_pricing.go new file mode 100644 index 0000000..5a746b4 --- /dev/null +++ b/scripts/generate_pricing.go @@ -0,0 +1,203 @@ +package main + +import ( + "encoding/json" + "fmt" + "net/http" + "os" + "sort" + "strconv" + "time" +) + +const ( + // AWS Price List API (Bulk) + // Region Index: https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonEC2/current/region_index.json + baseUrl = "https://pricing.us-east-1.amazonaws.com" + regionIndexUrl = baseUrl + "/offers/v1.0/aws/AmazonEC2/current/region_index.json" +) + +// Target regions to keep file size manageable for this MVP. +// We can expand this list or make it a flag. +var targetRegions = []string{ + // US + "us-east-1", "us-east-2", + "us-west-1", "us-west-2", + // Europe + "eu-central-1", "eu-west-1", "eu-west-2", "eu-north-1", "eu-south-1", "eu-west-3", + // Asia Pacific + "ap-southeast-1", "ap-southeast-2", "ap-northeast-1", "ap-northeast-2", "ap-south-1", + // Other + "ca-central-1", "sa-east-1", +} + +type RegionIndex struct { + Regions map[string]RegionEntry `json:"regions"` +} + +type RegionEntry struct { + RegionCode string `json:"regionCode"` + CurrentVersionUrl string `json:"currentVersionUrl"` +} + +type PriceList struct { + Products map[string]Product `json:"products"` + Terms map[string]map[string]map[string]Term `json:"terms"` // OnDemand -> SKU -> OfferTermCode -> Term +} + +type Product struct { + Sku string `json:"sku"` + ProductFamily string `json:"productFamily"` + Attributes map[string]string `json:"attributes"` +} + +type Term struct { + PriceDimensions map[string]PriceDimension `json:"priceDimensions"` +} + +type PriceDimension struct { + PricePerUnit map[string]string `json:"pricePerUnit"` +} + +func main() { + fmt.Println("Generating pricing data...") + + // 1. Fetch Region Index + fmt.Printf("Fetching region index from %s\n", regionIndexUrl) + resp, err := http.Get(regionIndexUrl) + if err != nil { + panic(err) + } + defer func() { _ = resp.Body.Close() }() + + var index RegionIndex + if err := json.NewDecoder(resp.Body).Decode(&index); err != nil { + panic(err) + } + + prices := make(map[string]float64) + + // 2. Iterate Regions + for _, region := range targetRegions { + entry, ok := index.Regions[region] + if !ok { + fmt.Printf("Warning: Region %s not found in index\n", region) + continue + } + + fullUrl := baseUrl + entry.CurrentVersionUrl + fmt.Printf("Processing %s (%s)...\n", region, fullUrl) + + regionPrices, err := processRegion(fullUrl) + if err != nil { + panic(err) + } + + for k, v := range regionPrices { + // Key format: "region|instanceType" + key := fmt.Sprintf("%s|%s", region, k) + prices[key] = v + } + } + + // 3. Generate Go Code + if err := generateGoFile(prices); err != nil { + panic(err) + } + + fmt.Println("Done!") +} + +func processRegion(url string) (map[string]float64, error) { + resp, err := http.Get(url) // #nosec G107 + if err != nil { + return nil, err + } + defer func() { _ = resp.Body.Close() }() + + var list PriceList + // The file can be large, but for a single region it's manageable (tens of MBs) + if err := json.NewDecoder(resp.Body).Decode(&list); err != nil { + return nil, err + } + + result := make(map[string]float64) + + for sku, product := range list.Products { + attrs := product.Attributes + + // Filter + if attrs["servicecode"] != "AmazonEC2" { + continue + } // explicit check (though map is filtered by URL) + if attrs["operatingSystem"] != "Linux" { + continue + } + if attrs["tenancy"] != "Shared" { + continue + } + if attrs["capacitystatus"] != "Used" { + continue + } + if attrs["preInstalledSw"] != "NA" { + continue + } + + instanceType := attrs["instanceType"] + if instanceType == "" { + continue + } + + // Find Price + // Terms -> OnDemand -> SKU -> ... + onDemandTerms, ok := list.Terms["OnDemand"][sku] + if !ok { + continue + } + + for _, term := range onDemandTerms { + for _, dim := range term.PriceDimensions { + if costStr, ok := dim.PricePerUnit["USD"]; ok { + cost, err := strconv.ParseFloat(costStr, 64) + if err == nil && cost > 0 { + result[instanceType] = cost + // We take the first valid price found for this SKU + // (usually there's only one OnDemand price per SKU matching filters) + goto NextProduct + } + } + } + } + + NextProduct: + } + + fmt.Printf(" Found %d instance types for region\n", len(result)) + return result, nil +} + +func generateGoFile(prices map[string]float64) error { + f, err := os.Create("internal/pricing/data.go") + if err != nil { + return err + } + defer func() { _ = f.Close() }() + + keys := make([]string, 0, len(prices)) + for k := range prices { + keys = append(keys, k) + } + sort.Strings(keys) + + _, _ = fmt.Fprintf(f, "// Code generated by scripts/generate_pricing.go; DO NOT EDIT.\n") + _, _ = fmt.Fprintf(f, "// Generated at %s\n", time.Now().Format(time.RFC3339)) + _, _ = fmt.Fprintf(f, "package pricing\n\n") + _, _ = fmt.Fprintf(f, "var InstancePrices = map[string]float64{\n") + + for _, k := range keys { + _, _ = fmt.Fprintf(f, "\t%q: %f,\n", k, prices[k]) + } + + _, _ = fmt.Fprintf(f, "}\n") + return nil +} diff --git a/web/package-lock.json b/web/package-lock.json index 22fee39..227b0d7 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -9,6 +9,7 @@ "version": "0.1.0", "dependencies": { "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-label": "^2.1.8", "@radix-ui/react-progress": "^1.1.8", "@radix-ui/react-select": "^2.2.6", "@radix-ui/react-slot": "^1.2.4", @@ -19,6 +20,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.20.0", + "reactflow": "^11.11.4", "recharts": "^2.8.0", "shadcn-ui": "^0.9.5", "tailwind-merge": "^1.14.0", @@ -1338,6 +1340,52 @@ } } }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.8.tgz", + "integrity": "sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-popper": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", @@ -1826,10 +1874,112 @@ "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", "license": "MIT" }, + "node_modules/@reactflow/background": { + "version": "11.3.14", + "resolved": "https://registry.npmjs.org/@reactflow/background/-/background-11.3.14.tgz", + "integrity": "sha512-Gewd7blEVT5Lh6jqrvOgd4G6Qk17eGKQfsDXgyRSqM+CTwDqRldG2LsWN4sNeno6sbqVIC2fZ+rAUBFA9ZEUDA==", + "license": "MIT", + "dependencies": { + "@reactflow/core": "11.11.4", + "classcat": "^5.0.3", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/controls": { + "version": "11.2.14", + "resolved": "https://registry.npmjs.org/@reactflow/controls/-/controls-11.2.14.tgz", + "integrity": "sha512-MiJp5VldFD7FrqaBNIrQ85dxChrG6ivuZ+dcFhPQUwOK3HfYgX2RHdBua+gx+40p5Vw5It3dVNp/my4Z3jF0dw==", + "license": "MIT", + "dependencies": { + "@reactflow/core": "11.11.4", + "classcat": "^5.0.3", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/core": { + "version": "11.11.4", + "resolved": "https://registry.npmjs.org/@reactflow/core/-/core-11.11.4.tgz", + "integrity": "sha512-H4vODklsjAq3AMq6Np4LE12i1I4Ta9PrDHuBR9GmL8uzTt2l2jh4CiQbEMpvMDcp7xi4be0hgXj+Ysodde/i7Q==", + "license": "MIT", + "dependencies": { + "@types/d3": "^7.4.0", + "@types/d3-drag": "^3.0.1", + "@types/d3-selection": "^3.0.3", + "@types/d3-zoom": "^3.0.1", + "classcat": "^5.0.3", + "d3-drag": "^3.0.0", + "d3-selection": "^3.0.0", + "d3-zoom": "^3.0.0", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/minimap": { + "version": "11.7.14", + "resolved": "https://registry.npmjs.org/@reactflow/minimap/-/minimap-11.7.14.tgz", + "integrity": "sha512-mpwLKKrEAofgFJdkhwR5UQ1JYWlcAAL/ZU/bctBkuNTT1yqV+y0buoNVImsRehVYhJwffSWeSHaBR5/GJjlCSQ==", + "license": "MIT", + "dependencies": { + "@reactflow/core": "11.11.4", + "@types/d3-selection": "^3.0.3", + "@types/d3-zoom": "^3.0.1", + "classcat": "^5.0.3", + "d3-selection": "^3.0.0", + "d3-zoom": "^3.0.0", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/node-resizer": { + "version": "2.2.14", + "resolved": "https://registry.npmjs.org/@reactflow/node-resizer/-/node-resizer-2.2.14.tgz", + "integrity": "sha512-fwqnks83jUlYr6OHcdFEedumWKChTHRGw/kbCxj0oqBd+ekfs+SIp4ddyNU0pdx96JIm5iNFS0oNrmEiJbbSaA==", + "license": "MIT", + "dependencies": { + "@reactflow/core": "11.11.4", + "classcat": "^5.0.4", + "d3-drag": "^3.0.0", + "d3-selection": "^3.0.0", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@reactflow/node-toolbar": { + "version": "1.3.14", + "resolved": "https://registry.npmjs.org/@reactflow/node-toolbar/-/node-toolbar-1.3.14.tgz", + "integrity": "sha512-rbynXQnH/xFNu4P9H+hVqlEUafDCkEoCy0Dg9mG22Sg+rY/0ck6KkrAQrYrTgXusd+cEJOMK0uOOFCK2/5rSGQ==", + "license": "MIT", + "dependencies": { + "@reactflow/core": "11.11.4", + "classcat": "^5.0.3", + "zustand": "^4.4.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, "node_modules/@remix-run/router": { - "version": "1.23.1", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.1.tgz", - "integrity": "sha512-vDbaOzF7yT2Qs4vO6XV1MHcJv+3dgR1sT+l3B8xxOVhUC336prMvqrvsLL/9Dnw2xr6Qhz4J0dmS0llNAbnUmQ==", + "version": "1.23.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.2.tgz", + "integrity": "sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==", "license": "MIT", "engines": { "node": ">=14.0.0" @@ -2311,24 +2461,159 @@ "assertion-error": "^2.0.1" } }, + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, "node_modules/@types/d3-array": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", "license": "MIT" }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", + "license": "MIT" + }, "node_modules/@types/d3-color": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", "license": "MIT" }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "license": "MIT" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", + "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==", + "license": "MIT" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", + "license": "MIT" + }, "node_modules/@types/d3-ease": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", "license": "MIT" }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "license": "MIT", + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", + "license": "MIT" + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "license": "MIT" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", + "license": "MIT" + }, "node_modules/@types/d3-interpolate": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", @@ -2344,6 +2629,24 @@ "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", "license": "MIT" }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", + "license": "MIT" + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", + "license": "MIT" + }, + "node_modules/@types/d3-random": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", + "license": "MIT" + }, "node_modules/@types/d3-scale": { "version": "4.0.9", "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", @@ -2353,6 +2656,18 @@ "@types/d3-time": "*" } }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "license": "MIT" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", + "license": "MIT" + }, "node_modules/@types/d3-shape": { "version": "3.1.7", "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz", @@ -2368,12 +2683,37 @@ "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", "license": "MIT" }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", + "license": "MIT" + }, "node_modules/@types/d3-timer": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", "license": "MIT" }, + "node_modules/@types/d3-transition": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "license": "MIT", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, "node_modules/@types/deep-eql": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", @@ -2388,6 +2728,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, "node_modules/@types/node": { "version": "20.19.25", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.25.tgz", @@ -2891,6 +3237,12 @@ "url": "https://polar.sh/cva" } }, + "node_modules/classcat": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/classcat/-/classcat-5.0.5.tgz", + "integrity": "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==", + "license": "MIT" + }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -3028,6 +3380,28 @@ "node": ">=12" } }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/d3-ease": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", @@ -3083,6 +3457,15 @@ "node": ">=12" } }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/d3-shape": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", @@ -3128,6 +3511,41 @@ "node": ">=12" } }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/data-urls": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", @@ -3609,9 +4027,9 @@ } }, "node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -4929,12 +5347,12 @@ } }, "node_modules/react-router": { - "version": "6.30.2", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.2.tgz", - "integrity": "sha512-H2Bm38Zu1bm8KUE5NVWRMzuIyAV8p/JrOaBJAwVmp37AXG72+CZJlEBw6pdn9i5TBgLMhNDgijS4ZlblpHyWTA==", + "version": "6.30.3", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.3.tgz", + "integrity": "sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw==", "license": "MIT", "dependencies": { - "@remix-run/router": "1.23.1" + "@remix-run/router": "1.23.2" }, "engines": { "node": ">=14.0.0" @@ -4944,13 +5362,13 @@ } }, "node_modules/react-router-dom": { - "version": "6.30.2", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.2.tgz", - "integrity": "sha512-l2OwHn3UUnEVUqc6/1VMmR1cvZryZ3j3NzapC2eUXO1dB0sYp5mvwdjiXhpUbRb21eFow3qSxpP8Yv6oAU824Q==", + "version": "6.30.3", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.3.tgz", + "integrity": "sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag==", "license": "MIT", "dependencies": { - "@remix-run/router": "1.23.1", - "react-router": "6.30.2" + "@remix-run/router": "1.23.2", + "react-router": "6.30.3" }, "engines": { "node": ">=14.0.0" @@ -5013,6 +5431,24 @@ "react-dom": ">=16.6.0" } }, + "node_modules/reactflow": { + "version": "11.11.4", + "resolved": "https://registry.npmjs.org/reactflow/-/reactflow-11.11.4.tgz", + "integrity": "sha512-70FOtJkUWH3BAOsN+LU9lCrKoKbtOPnz2uq0CV2PLdNSwxTXOhCbsZr50GmZ+Rtw3jx8Uv7/vBFtCGixLfd4Og==", + "license": "MIT", + "dependencies": { + "@reactflow/background": "11.3.14", + "@reactflow/controls": "11.2.14", + "@reactflow/core": "11.11.4", + "@reactflow/minimap": "11.7.14", + "@reactflow/node-resizer": "2.2.14", + "@reactflow/node-toolbar": "1.3.14" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -5777,6 +6213,15 @@ } } }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -6230,6 +6675,34 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true, "license": "ISC" + }, + "node_modules/zustand": { + "version": "4.5.7", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.7.tgz", + "integrity": "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.2.2" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0.6", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } } } } diff --git a/web/package.json b/web/package.json index 7d61b49..5daf043 100644 --- a/web/package.json +++ b/web/package.json @@ -12,6 +12,7 @@ }, "dependencies": { "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-label": "^2.1.8", "@radix-ui/react-progress": "^1.1.8", "@radix-ui/react-select": "^2.2.6", "@radix-ui/react-slot": "^1.2.4", @@ -21,6 +22,7 @@ "lucide-react": "^0.298.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "reactflow": "^11.11.4", "react-router-dom": "^6.20.0", "recharts": "^2.8.0", "shadcn-ui": "^0.9.5", diff --git a/web/src/App.tsx b/web/src/App.tsx index 0eea408..acaceec 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -1,11 +1,14 @@ import { Outlet } from "react-router-dom"; import LayoutShell from "./components/layout/LayoutShell"; +import { AuthProvider } from "./context/AuthContext"; const App = () => { return ( - - - + + + + + ); }; diff --git a/web/src/charts/CostTreemap.tsx b/web/src/charts/CostTreemap.tsx new file mode 100644 index 0000000..39bdf1f --- /dev/null +++ b/web/src/charts/CostTreemap.tsx @@ -0,0 +1,122 @@ +import { ResponsiveContainer, Treemap, Tooltip } from "recharts"; +import { formatCurrency, formatPercentage } from "../lib/utils"; +import { useMemo } from "react"; + +export interface TreemapNode { + name: string; + value: number; // Cost or Percentage + size: number; // Used for "weight" if different from value + formattedValue: string; + originalData: any; + children?: TreemapNode[]; +} + +interface CustomContentProps { + depth: number; + x: number; + y: number; + width: number; + height: number; + index: number; + payload: any; + colors: string[]; + rank: number; + name: string; + value: number; +} + +const COLORS = [ + "#8884d8", + "#83a6ed", + "#8dd1e1", + "#82ca9d", + "#a4de6c", + "#d0ed57", + "#ffc658", +]; + +const CustomizeTreemapContent = (props: CustomContentProps) => { + const { depth, x, y, width, height, name, value, colors, index } = props; + + return ( + + + {depth === 1 ? ( + + {name} + + ) : null} + {depth === 1 ? ( + + {index + 1} + + ) : null} + + ); +}; + +const CustomTooltip = ({ active, payload, unit }: { active?: boolean; payload?: any[]; unit: "$" | "%" }) => { + if (active && payload && payload.length) { + const data = payload[0].payload; + return ( +
+
{data.name}
+
+ {unit === "$" ? formatCurrency(data.value) : formatPercentage(data.value)} +
+
+ ); + } + return null; +}; + +export const CostTreemap = ({ data, unit = "$" }: { data: TreemapNode[]; unit?: "$" | "%" }) => { + + // Recharts Treemap expects a single root node with children + const treeData = useMemo(() => { + return [{ + name: "Cluster", + value: 0, + children: data + }]; + }, [data]); + + return ( + + } + > + } /> + + + ); +}; diff --git a/web/src/components/layout/AppSidebar.tsx b/web/src/components/layout/AppSidebar.tsx index 9b95326..15e7084 100644 --- a/web/src/components/layout/AppSidebar.tsx +++ b/web/src/components/layout/AppSidebar.tsx @@ -1,5 +1,5 @@ import { NavLink, useLocation } from "react-router-dom"; -import { Cloud, Gauge, LayoutGrid, Network, PieChart, Server } from "lucide-react"; +import { Cloud, Gauge, GitBranch, LayoutGrid, Network, PieChart, Server } from "lucide-react"; import { Sidebar, @@ -20,6 +20,7 @@ const navItems = [ { to: "/namespaces", label: "Namespaces", icon: LayoutGrid }, { to: "/nodes", label: "Nodes", icon: Server }, { to: "/resources", label: "Resources", icon: PieChart }, + { to: "/network", label: "Network Map", icon: GitBranch }, { to: "/agents", label: "Agents", icon: Network }, { to: "/connect-cloud", label: "Connect Cloud", icon: Cloud } ]; diff --git a/web/src/components/layout/LayoutShell.tsx b/web/src/components/layout/LayoutShell.tsx index e2d4ebe..1245bda 100644 --- a/web/src/components/layout/LayoutShell.tsx +++ b/web/src/components/layout/LayoutShell.tsx @@ -1,7 +1,14 @@ import AppSidebar from "./AppSidebar"; import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar"; +import { useAuth } from "@/context/AuthContext"; const LayoutShell = ({ children }: { children: React.ReactNode }) => { + const { isAuthenticated } = useAuth(); + + if (!isAuthenticated) { + return
{children}
; + } + return (
diff --git a/web/src/components/layout/ProtectedRoute.tsx b/web/src/components/layout/ProtectedRoute.tsx new file mode 100644 index 0000000..62175af --- /dev/null +++ b/web/src/components/layout/ProtectedRoute.tsx @@ -0,0 +1,21 @@ +import { Navigate, Outlet } from "react-router-dom"; +import { useAuth } from "@/context/AuthContext"; +import { Loader2 } from "lucide-react"; + +export default function ProtectedRoute() { + const { isAuthenticated, isLoading } = useAuth(); + + if (isLoading) { + return ( +
+ +
+ ); + } + + if (!isAuthenticated) { + return ; + } + + return ; +} diff --git a/web/src/components/ui/label.tsx b/web/src/components/ui/label.tsx new file mode 100644 index 0000000..ef090dc --- /dev/null +++ b/web/src/components/ui/label.tsx @@ -0,0 +1,24 @@ +import * as React from "react" +import * as LabelPrimitive from "@radix-ui/react-label" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const labelVariants = cva( + "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" +) + +const Label = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, ...props }, ref) => ( + +)) +Label.displayName = LabelPrimitive.Root.displayName + +export { Label } diff --git a/web/src/context/AuthContext.tsx b/web/src/context/AuthContext.tsx new file mode 100644 index 0000000..b0c8693 --- /dev/null +++ b/web/src/context/AuthContext.tsx @@ -0,0 +1,59 @@ +import React, { createContext, useContext, useState, useEffect, useCallback } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { setAuthToken, setUnauthorizedHandler } from '@/lib/api'; + +interface AuthContextType { + isAuthenticated: boolean; + login: (token: string) => void; + logout: () => void; + isLoading: boolean; +} + +const AuthContext = createContext({ + isAuthenticated: false, + login: () => { }, + logout: () => { }, + isLoading: true, +}); + +export const useAuth = () => useContext(AuthContext); + +export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { + const [isAuthenticated, setIsAuthenticated] = useState(false); + const [isLoading, setIsLoading] = useState(true); + const navigate = useNavigate(); + + useEffect(() => { + const token = localStorage.getItem('token'); + if (token) { + setAuthToken(token); + setIsAuthenticated(true); + } + setIsLoading(false); + }, []); + + const login = useCallback((token: string) => { + localStorage.setItem('token', token); + setAuthToken(token); + setIsAuthenticated(true); + navigate('/'); + }, [navigate]); + + const logout = useCallback(() => { + localStorage.removeItem('token'); + setAuthToken(null); + setIsAuthenticated(false); + navigate('/login'); + }, [navigate]); + + useEffect(() => { + setUnauthorizedHandler(logout); + return () => setUnauthorizedHandler(null); + }, [logout]); + + return ( + + {children} + + ); +}; diff --git a/web/src/hooks/useApiData.ts b/web/src/hooks/useApiData.ts index eb99d62..23cb417 100644 --- a/web/src/hooks/useApiData.ts +++ b/web/src/hooks/useApiData.ts @@ -1,11 +1,16 @@ -import { useCallback, useEffect, useState } from "react"; +import { useCallback, useEffect, useRef, useState } from "react"; export const useApiData = (fetcher: () => Promise) => { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); + const inFlight = useRef(false); const refresh = useCallback(async () => { + if (inFlight.current) { + return; + } + inFlight.current = true; try { setLoading(true); const result = await fetcher(); @@ -15,6 +20,7 @@ export const useApiData = (fetcher: () => Promise) => { setError(err instanceof Error ? err.message : "Unable to load data"); } finally { setLoading(false); + inFlight.current = false; } }, [fetcher]); diff --git a/web/src/lib/api.ts b/web/src/lib/api.ts index 3716343..3805d12 100644 --- a/web/src/lib/api.ts +++ b/web/src/lib/api.ts @@ -72,7 +72,9 @@ type NamespaceCostRecordApi = { hourlyCost: number; podCount: number; cpuRequestMilli: number; + cpuLimitMilli: number; cpuUsageMilli: number; + cpuUsagePercent?: number; memoryRequestBytes: number; memoryUsageBytes: number; labels?: Record; @@ -90,7 +92,9 @@ export interface NamespaceCostRecord { hourlyCost: number; podCount: number; cpuRequestMilli: number; + cpuLimitMilli: number; cpuUsageMilli: number; + cpuUsagePercent: number; memoryRequestBytes: number; memoryUsageBytes: number; labels: Record; @@ -203,8 +207,70 @@ export interface HealthResponse { timestamp: string; } -async function request(path: string): Promise { - const response = await fetch(`${API_PREFIX}${path}`); +export type NetworkEdge = { + srcNamespace: string; + srcPodName: string; + srcNodeName: string; + srcIp: string; + srcDnsName?: string; + srcAvailabilityZone: string; + dstNamespace: string; + dstPodName: string; + dstNodeName: string; + dstIp: string; + dstDnsName?: string; + dstAvailabilityZone: string; + dstKind: string; + serviceMatch: string; + dstServices: string; + protocol: number; + bytesSent: number; + bytesReceived: number; + egressCostUsd: number; + connectionCount: number; + firstSeen: number; + lastSeen: number; +}; + +export type NetworkTopologyResponse = { + clusterId: string; + namespace?: string; + start: string; + end: string; + edges: NetworkEdge[]; + totalEdges: number; + requestedLimit: number; + timestamp: string; +}; + +let authToken: string | null = null; +let unauthorizedHandler: (() => void) | null = null; + +export const setAuthToken = (token: string | null) => { + authToken = token; +}; + +export const setUnauthorizedHandler = (handler: (() => void) | null) => { + unauthorizedHandler = handler; +}; + +async function request(path: string, options: RequestInit = {}): Promise { + const headers = new Headers(options.headers); + if (authToken) { + headers.set("Authorization", `Bearer ${authToken}`); + } + + const response = await fetch(`${API_PREFIX}${path}`, { + ...options, + headers, + }); + + if (response.status === 401) { + setAuthToken(null); + unauthorizedHandler?.(); + throw new Error("Unauthorized"); + } + if (!response.ok) { const text = await response.text(); throw new Error(text || `Request failed with ${response.status}`); @@ -212,6 +278,29 @@ async function request(path: string): Promise { return response.json(); } +export interface AgentInfo { + name: string; + baseUrl: string; + status: string; + lastScrapeTime: string; + error?: string; + clusterId?: string; + nodeName?: string; +} + +export const fetchAgents = async (): Promise => { + return request("/agents"); +}; + +export const login = async (username: string, password: string): Promise<{ token: string }> => { + const resp = await request<{ token: string }>("/login", { + method: "POST", + body: JSON.stringify({ username, password }), + headers: { "Content-Type": "application/json" }, + }); + return resp; +}; + export const fetchOverview = async (): Promise => { const resp = await request("/cost/overview"); return { @@ -235,7 +324,9 @@ export const fetchNamespaces = async (): Promise => { records: resp.items.map((record) => ({ ...record, labels: record.labels ?? {}, - environment: normalizeEnvironment(record.environment) + environment: normalizeEnvironment(record.environment), + cpuLimitMilli: record.cpuLimitMilli ?? 0, + cpuUsagePercent: record.cpuUsagePercent ?? 0 })) }; }; @@ -265,3 +356,34 @@ export const fetchResources = async (): Promise => { export const fetchHealth = () => request("/health"); export const fetchAgentStatus = () => request("/agent"); + +export type NetworkTopologyParams = { + clusterId?: string; + namespace?: string | string[]; + lookback?: string; + start?: string | number; + end?: string | number; + limit?: number; + minCost?: number; + minBytes?: number; + minConnections?: number; +}; + +export const fetchNetworkTopology = async (params: NetworkTopologyParams): Promise => { + const search = new URLSearchParams(); + if (params.clusterId) search.set("clusterId", params.clusterId); + if (params.namespace) { + const value = Array.isArray(params.namespace) ? params.namespace.join(",") : params.namespace; + search.set("namespace", value); + } + if (params.lookback) search.set("lookback", params.lookback); + if (params.start !== undefined) search.set("start", String(params.start)); + if (params.end !== undefined) search.set("end", String(params.end)); + if (params.limit !== undefined) search.set("limit", String(params.limit)); + if (params.minCost !== undefined) search.set("minCost", String(params.minCost)); + if (params.minBytes !== undefined) search.set("minBytes", String(params.minBytes)); + if (params.minConnections !== undefined) search.set("minConnections", String(params.minConnections)); + + const query = search.toString(); + return request(`/network/topology${query ? `?${query}` : ""}`); +}; diff --git a/web/src/pages/AgentsPage.tsx b/web/src/pages/AgentsPage.tsx index 9561f6f..4916a6d 100644 --- a/web/src/pages/AgentsPage.tsx +++ b/web/src/pages/AgentsPage.tsx @@ -1,188 +1,155 @@ -import { useMemo } from "react"; -import { fetchAgentStatus, fetchHealth, type AgentDatasetStatus, type AgentStatusResponse } from "../lib/api"; +import { useRef } from "react"; +import { fetchAgents, type AgentInfo } from "../lib/api"; import { useApiData } from "../hooks/useApiData"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Skeleton } from "@/components/ui/skeleton"; import { Badge } from "@/components/ui/badge"; -import { relativeTimeFromIso, formatNumber } from "../lib/utils"; - -const statusConfig: Record = { - connected: { - label: "Agent Connected", - tone: "bg-emerald-500", - description: "Data is flowing normally" - }, - partial: { - label: "Agent Partially Connected", - tone: "bg-amber-400", - description: "Some datasets are delayed" - }, - offline: { - label: "Agent Offline", - tone: "bg-destructive", - description: "No recent data received" - } -}; - -const datasetLabels: Array<{ key: keyof AgentStatusResponse["datasets"]; - label: string }> - = [ - { key: "namespaces", label: "Namespaces" }, - { key: "nodes", label: "Nodes" }, - { key: "resources", label: "Resources" } - ]; - -const datasetTone: Record = { - ok: { label: "OK", className: "text-emerald-400" }, - partial: { label: "Partial", className: "text-amber-400" }, - missing: { label: "Missing", className: "text-destructive" } -}; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { relativeTimeFromIso } from "../lib/utils"; +import { Activity, Server, AlertCircle, CheckCircle2 } from "lucide-react"; const AgentsPage = () => { - const { data, loading, error, refresh } = useApiData(fetchAgentStatus); - const { - data: health, - refresh: refreshHealth - } = useApiData(fetchHealth); - const statusDetails = data ? statusConfig[data.status] : null; - const lastSyncLabel = data?.lastSync ? relativeTimeFromIso(data.lastSync) : "Unknown"; - - const clusterMeta = useMemo(() => { - const clusterName = data?.clusterName || health?.clusterName || health?.clusterId; - const clusterType = data?.clusterType || health?.clusterType; - const region = data?.clusterRegion || data?.region || health?.clusterRegion; - const nodeCount = typeof data?.nodeCount === "number" ? data?.nodeCount : undefined; - - const hasMetadata = clusterName || clusterType || region || typeof nodeCount === "number"; - if (!hasMetadata) return null; - - return { - clusterName: clusterName || "Unknown", - clusterType: clusterType || (clusterName ? "Unknown" : undefined), - region: region || "Unknown", - nodeCount - }; - }, [data, health]); - - const handleRefresh = () => { - refresh(); - refreshHealth(); - }; - - if (loading && !data) { - return ; - } + const { data: agents, loading, error, refresh } = useApiData(fetchAgents); - if (error) { + if (loading && !agents) { return ( - - {error} - +
+
+ + +
+ + +
+ + + +
+
+
+
); } - if (!data || !statusDetails) { + if (error) { return ( - - - No agent data - - -

The dashboard hasn\'t received any metrics from your agent yet.

- + + +

+ + {error} +

+
); } + const sortedAgents = [...(agents || [])].sort((a, b) => { + // Sort by Last Scrape Time Descending (most recent first) + return new Date(b.lastScrapeTime).getTime() - new Date(a.lastScrapeTime).getTime(); + }); + return (
-
+
-

Agent

-

Agent connection and data health

+

Agents

+

+ Manage and monitor connected agents across your clusters. +

-
-
- - -
-
-
- Last sync {lastSyncLabel} -
-
-
- - - - Data Health - - - {datasetLabels.map(({ key, label }) => ( -
- {label} - - {datasetTone[data.datasets[key]].label} - -
- ))} -
-
- - - - Agent Version - - -

{data.version || "Unknown"}

- {data.updateAvailable && Update available} -

Keep the agent updated for best accuracy.

+ {!agents || agents.length === 0 ? ( + + + +

No Agents Connected

+

+ Install the ClusterCost agent in your Kubernetes clusters to start seeing data. +

-
- - {clusterMeta && ( + ) : ( - - Cluster metadata - - -
-

Cluster

-

{clusterMeta.clusterName}

-
- {clusterMeta.clusterType && ( -
-

Type

-

{clusterMeta.clusterType}

-
- )} -
-

Region

-

{clusterMeta.region}

-
-
-

Nodes

-

- {typeof clusterMeta.nodeCount === "number" ? formatNumber(clusterMeta.nodeCount) : "Unknown"} -

-
-
+ + + + Agent Name + Status + Last Seen + Cluster + Node + + + + {sortedAgents.map((agent) => ( + + ))} + +
)}
); }; +const AgentRow = ({ agent }: { agent: AgentInfo }) => { + const isOk = agent.status === "connected"; + const isOffline = agent.status === "offline"; + + return ( + + +
+ {agent.name} + {agent.error && ( + + {agent.error} + + )} +
+
+ + {isOk ? ( + + Connected + + ) : isOffline ? ( + + Offline + + ) : ( + + {agent.status} + + )} + + + {relativeTimeFromIso(agent.lastScrapeTime)} + + + {agent.clusterId || "-"} + + + {agent.nodeName || "-"} + +
+ ); +}; + export default AgentsPage; diff --git a/web/src/pages/LoginPage.tsx b/web/src/pages/LoginPage.tsx new file mode 100644 index 0000000..dd5eaf8 --- /dev/null +++ b/web/src/pages/LoginPage.tsx @@ -0,0 +1,83 @@ +import { useState } from "react"; +import { useAuth } from "@/context/AuthContext"; +import { login as apiLogin } from "@/lib/api"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "@/components/ui/card"; +import { AlertCircle, Loader2 } from "lucide-react"; + +export default function LoginPage() { + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const [error, setError] = useState(""); + const [loading, setLoading] = useState(false); + const { login } = useAuth(); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setError(""); + setLoading(true); + + try { + const { token } = await apiLogin(username, password); + login(token); + } catch (err) { + setError("Invalid username or password"); + } finally { + setLoading(false); + } + }; + + return ( +
+ + + ClusterCost + + Enter your credentials to access the dashboard + + +
+ + {error && ( +
+ +

{error}

+
+ )} +
+ + setUsername(e.target.value)} + required + disabled={loading} + /> +
+
+ + setPassword(e.target.value)} + required + disabled={loading} + /> +
+
+ + + +
+
+
+ ); +} diff --git a/web/src/pages/namespaces/NamespacesPage.test.tsx b/web/src/pages/namespaces/NamespacesPage.test.tsx index eee1353..2f115ed 100644 --- a/web/src/pages/namespaces/NamespacesPage.test.tsx +++ b/web/src/pages/namespaces/NamespacesPage.test.tsx @@ -10,6 +10,13 @@ vi.mock("../../hooks/useApiData", () => ({ useApiData: (fetcher: any) => mockUseApiData(fetcher) })); +// Mock ResizeObserver +global.ResizeObserver = class ResizeObserver { + observe() { } + unobserve() { } + disconnect() { } +}; + const sampleNamespace = { clusterId: "cluster", namespace: "payments", @@ -43,7 +50,12 @@ describe("NamespacesPage", () => { render(); - expect(screen.getByText("payments")).toBeInTheDocument(); - expect(screen.getByText("$10")).toBeInTheDocument(); + // "payments" appears in Summary Card, Treemap, Optimization List, and Table. + // Let's verify it exists at least once. + expect(screen.getAllByText("payments")[0]).toBeInTheDocument(); + + // Hourly cost 10 * 720 hours = $7,200 + // It appears in Total Monthly, Cost Treemap, etc. + expect(screen.getAllByText("$7,200")[0]).toBeInTheDocument(); }); }); diff --git a/web/src/pages/namespaces/NamespacesPage.tsx b/web/src/pages/namespaces/NamespacesPage.tsx index cff3620..51766d4 100644 --- a/web/src/pages/namespaces/NamespacesPage.tsx +++ b/web/src/pages/namespaces/NamespacesPage.tsx @@ -21,6 +21,7 @@ import { EnvironmentBadge } from "@/components/environment/EnvironmentBadge"; import { NamespaceDetailSheet, type NamespaceDetailSnapshot } from "@/components/namespaces/NamespaceDetailSheet"; import { CostByEnvironmentChart } from "../../charts/CostByEnvironmentChart"; import { TopNamespacesBarChart } from "../../charts/TopNamespacesBarChart"; +import { CostTreemap } from "../../charts/CostTreemap"; interface DerivedNamespace { name: string; @@ -52,6 +53,7 @@ const NamespacesPage = () => { const { data, loading, error, refresh } = useApiData(fetchNamespaces); const [search, setSearch] = useState(""); const [selected, setSelected] = useState(null); + const [unit, setUnit] = useState<"$" | "%">("$"); const records = data?.records ?? []; const derived = useMemo(() => { @@ -60,13 +62,18 @@ const NamespacesPage = () => { const cpuUsed = milliToCores(record.cpuUsageMilli ?? 0); const memoryRequested = bytesToGiB(record.memoryRequestBytes ?? 0); const memoryUsed = bytesToGiB(record.memoryUsageBytes ?? 0); + + // Use backend provided percent if available, otherwise calculate fallback + // The backend now provides `record.cpuUsagePercent` + const cpuPercent = record.cpuUsagePercent ?? getUsagePercent(cpuUsed, cpuRequested); + return { name: record.namespace, environment: record.environment ?? "unknown", hourlyCost: record.hourlyCost ?? 0, monthlyCost: toMonthlyCost(record.hourlyCost ?? 0), podCount: record.podCount ?? 0, - cpuUsagePercent: getUsagePercent(cpuUsed, cpuRequested), + cpuUsagePercent: cpuPercent, memoryUsagePercent: getUsagePercent(memoryUsed, memoryRequested), cpuRequestedCores: cpuRequested, cpuUsedCores: cpuUsed, @@ -90,6 +97,8 @@ const NamespacesPage = () => { const totalMonthly = useMemo(() => derived.reduce((sum, ns) => sum + ns.monthlyCost, 0), [derived]); const topNamespace = sorted[0]; const topNamespacePercent = topNamespace && totalMonthly > 0 ? (topNamespace.monthlyCost / totalMonthly) * 100 : 0; + + // Calculate top 5 share based on currently sorted/filtered list const topFiveShare = (() => { const topFive = sorted.slice(0, 5); const share = topFive.reduce((sum, ns) => sum + ns.monthlyCost, 0); @@ -107,10 +116,14 @@ const NamespacesPage = () => { const optimization = useMemo(() => { if (!derived.length) return []; - const costThreshold = [...derived].sort((a, b) => b.monthlyCost - a.monthlyCost)[Math.max(Math.floor(derived.length * 0.25) - 1, 0)]?.monthlyCost ?? 0; - return derived - .filter((ns) => ns.monthlyCost >= costThreshold && ns.cpuUsagePercent < 35 && ns.memoryUsagePercent < 35) - .sort((a, b) => b.monthlyCost - a.monthlyCost) + // Find high cost items (top 25th percentile of cost) + // sort descending + const sortedByCost = [...derived].sort((a, b) => b.monthlyCost - a.monthlyCost); + // arbitrary threshold: items costing more than index 25% * average? + // Just pick top spenders with low usage. + + return sortedByCost + .filter((ns) => ns.monthlyCost > 10 && ns.cpuUsagePercent < 35 && ns.memoryUsagePercent < 35) // Hardcoded $10 threshold for noise .slice(0, 5); }, [derived]); @@ -122,25 +135,34 @@ const NamespacesPage = () => { ]; }, [envBreakdown]); - const topFiveChart = useMemo(() => { - return sorted.slice(0, 5).map((ns) => ({ name: ns.name, value: ns.monthlyCost })); - }, [sorted]); + // Data for Treemap + const treemapData = useMemo(() => { + // Only show top 20 or so to avoid clutter, bundle rest as "Others"? + // For now just map all + return sorted.map(ns => ({ + name: ns.name, + value: unit === "$" ? ns.monthlyCost : (ns.monthlyCost / totalMonthly) * 100, + formattedValue: unit === "$" ? formatCurrency(ns.monthlyCost) : formatPercentage((ns.monthlyCost / totalMonthly) * 100), + size: ns.monthlyCost, // Use cost for sizing always? Or match unit? Size usually implies importance (cost) + originalData: ns + })); + }, [sorted, unit, totalMonthly]); const lastUpdated = data?.lastUpdated ? relativeTimeFromIso(data.lastUpdated) : "moments ago"; const detailSnapshot = selected ? { - name: selected.name, - environment: selected.environment, - hourlyCost: selected.hourlyCost, - monthlyCost: selected.monthlyCost, - podCount: selected.podCount, - cpuRequested: selected.cpuRequestedCores, - cpuUsed: selected.cpuUsedCores, - memoryRequested: selected.memoryRequestedGiB, - memoryUsed: selected.memoryUsedGiB, - labels: selected.labels - } + name: selected.name, + environment: selected.environment, + hourlyCost: selected.hourlyCost, + monthlyCost: selected.monthlyCost, + podCount: selected.podCount, + cpuRequested: selected.cpuRequestedCores, + cpuUsed: selected.cpuUsedCores, + memoryRequested: selected.memoryRequestedGiB, + memoryUsed: selected.memoryUsedGiB, + labels: selected.labels + } : null; if (loading && !data) { @@ -178,9 +200,26 @@ const NamespacesPage = () => {

Namespaces

See where your cluster money goes.

-
Last updated {lastUpdated}
+
+
+ + +
+
Last updated {lastUpdated}
+
+ {/* Main Stats Row */}
@@ -209,154 +248,130 @@ const NamespacesPage = () => { - Prod vs Non-prod vs System + Prod vs Other -

Prod {formatPercentage(totalMonthly ? (envBreakdown["Prod"] / totalMonthly) * 100 : 0, { fractionDigits: 0 })}

-

Non-prod {formatPercentage(totalMonthly ? (envBreakdown["Non-Prod"] / totalMonthly) * 100 : 0, { fractionDigits: 0 })}

-

System {formatPercentage(totalMonthly ? (envBreakdown["System"] / totalMonthly) * 100 : 0, { fractionDigits: 0 })}

+
+ Prod + {formatPercentage(totalMonthly ? (envBreakdown["Prod"] / totalMonthly) * 100 : 0, { fractionDigits: 0 })} +
+
+ Non-Prod + {formatPercentage(totalMonthly ? (envBreakdown["Non-Prod"] / totalMonthly) * 100 : 0, { fractionDigits: 0 })} +
- Optimization targets + Optimization candidates

{optimization.length}

-

High spend, low usage

+

Wasted CPU/RAM

+
+
+
+ + {/* Visualization Row */} +
+ {/* Treemap takes 2 columns */} + + + Cost Distribution +

Size represents cost relative to total cluster spend.

+
+ + + +
+ + {/* Optimization List takes 1 column */} + + + Optimization opportunities +

High cost, low usage targets

+
+ + {optimization.length === 0 ? ( +
+

🎉 All workloads are right-sized!

+
+ ) : ( + optimization.map((ns) => ( + + )) + )}
-
+ {/* Detailed Table Row */} +
- Namespaces -

Top 5 = {formatPercentage(topFiveShare, { fractionDigits: 0 })} of total

+ Namespace Details
setSearch(event.target.value)} className="h-9 w-full" />
- -
-
-
- - - - Namespace - Monthly cost - CPU usage - Memory usage - Environment - - - - {sorted.map((ns) => ( - setSelected(ns)}> - {ns.name} - {formatCurrency(ns.monthlyCost)} - -
- - {ns.cpuUsagePercent.toFixed(0)}% -
-
- -
- - {ns.memoryUsagePercent.toFixed(0)}% -
-
- - - -
- ))} -
-
-
-
-
-
- {sorted.map((ns) => ( - - ))} -
+ + + + + Namespace + Monthly cost + CPU usage + Memory usage + Environment + + + + {sorted.map((ns) => ( + setSelected(ns)}> + {ns.name} + {formatCurrency(ns.monthlyCost)} + +
+ + {ns.cpuUsagePercent.toFixed(0)}% +
+
+ +
+ + {ns.memoryUsagePercent.toFixed(0)}% +
+
+ + + +
+ ))} +
+
- -
- - - Optimization opportunities - - - {optimization.length === 0 ? ( -

Everything looks right-sized right now.

- ) : ( - optimization.map((ns) => ( -
-
- {ns.name} - {formatCurrency(ns.monthlyCost)} -
-

- CPU {ns.cpuUsagePercent.toFixed(0)}% · Memory {ns.memoryUsagePercent.toFixed(0)}% -

-
- )) - )} -
-
- - - - Cost concentration -

Where your money goes

-
- - - -
- - - Top namespaces by cost - - - {topFiveChart.length > 0 ? ( - - ) : ( -

We need namespace cost data before showing this chart.

- )} -
-
-
!open && setSelected(null)} data={detailSnapshot} /> diff --git a/web/src/pages/network/NetworkTopologyPage.tsx b/web/src/pages/network/NetworkTopologyPage.tsx new file mode 100644 index 0000000..562a006 --- /dev/null +++ b/web/src/pages/network/NetworkTopologyPage.tsx @@ -0,0 +1,833 @@ +import { useCallback, useMemo, useState } from "react"; +import ReactFlow, { + Background, + Controls, + Handle, + MiniMap, + Position, + type Edge, + type Node, + type NodeProps +} from "reactflow"; +import "reactflow/dist/style.css"; + +import { fetchNamespaces, fetchNetworkTopology, type NetworkEdge } from "@/lib/api"; +import { useApiData } from "@/hooks/useApiData"; +import { Card } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { Skeleton } from "@/components/ui/skeleton"; +import { Badge } from "@/components/ui/badge"; +import { + Box, + Cloud, + Database, + Globe, + Layers, + Network, + Repeat, + Server, + Circle +} from "lucide-react"; + +const lookbackOptions = [ + { label: "15m", value: "15m" }, + { label: "1h", value: "1h" }, + { label: "6h", value: "6h" }, + { label: "24h", value: "24h" } +]; + +const nodeSpacing = 220; +const groupPadding = 22; +const groupHeaderHeight = 36; +const defaultCostThreshold = 0.01; +const defaultMinBytesMb = 0; +const defaultMinConnections = 0; +const maxExternalEndpoints = 10; +const maxInfraEndpoints = 10; +const tierGap = 90; +const externalRowPadding = 40; + +type ResourceKind = + | "service" + | "deployment" + | "statefulset" + | "daemonset" + | "pod" + | "node" + | "ip" + | "external" + | "unknown"; + +type ResourceNodeData = { + title: string; + kind: ResourceKind; + namespace: string; +}; + +type NamespaceNodeData = { + name: string; + count: number; +}; + +type AggregatedEdge = { + srcId: string; + dstId: string; + bytesSent: number; + bytesReceived: number; + egressCostUsd: number; + connectionCount: number; + isExternal: boolean; + isCrossAz: boolean; + direction: "egress" | "ingress" | "internal"; +}; + +const parseWorkloadFromPod = (podName: string) => { + const parts = podName.split("-"); + const last = parts[parts.length - 1]; + const secondLast = parts[parts.length - 2] ?? ""; + + if (parts.length >= 2 && /^\d+$/.test(last)) { + return { name: parts.slice(0, -1).join("-"), kind: "statefulset" as const }; + } + + if (parts.length >= 3 && /^[a-z0-9]{5}$/.test(last) && /^[a-z0-9]{9,10}$/.test(secondLast)) { + return { name: parts.slice(0, -2).join("-"), kind: "deployment" as const }; + } + + if (parts.length >= 2 && /^[a-z0-9]{5}$/.test(last)) { + return { name: parts.slice(0, -1).join("-"), kind: "daemonset" as const }; + } + + return { name: podName, kind: "pod" as const }; +}; + +const extractNamespaceFromServices = (services: string | null | undefined) => { + if (!services) return ""; + const first = services.split(",")[0]?.trim(); + if (!first) return ""; + const [namespace] = first.split("/"); + return namespace ?? ""; +}; + +const extractServiceName = (services: string | null | undefined) => { + if (!services) return ""; + const first = services.split(",")[0]?.trim(); + if (!first) return ""; + const [_, name] = first.split("/"); + return name ?? ""; +}; + +const getExternalKey = (edge: NetworkEdge) => { + if (edge.dstKind !== "external") return ""; + return `external:${edge.dstDnsName || edge.dstIp || "unknown"}`; +}; + +const getInfraKey = (edge: NetworkEdge, side: "src" | "dst") => { + const namespace = side === "src" ? edge.srcNamespace : edge.dstNamespace; + const pod = side === "src" ? edge.srcPodName : edge.dstPodName; + const node = side === "src" ? edge.srcNodeName : edge.dstNodeName; + const ip = side === "src" ? edge.srcIp : edge.dstIp; + + if (namespace || pod) return ""; + if (node) return `infra:node:${node}`; + if (ip) return `infra:ip:${ip}`; + return ""; +}; + +const buildEndpointGroup = ( + edge: NetworkEdge, + side: "src" | "dst", + topExternal: Set, + topInfra: Set +) => { + const namespace = side === "src" ? edge.srcNamespace : edge.dstNamespace; + const pod = side === "src" ? edge.srcPodName : edge.dstPodName; + const node = side === "src" ? edge.srcNodeName : edge.dstNodeName; + const ip = side === "src" ? edge.srcIp : edge.dstIp; + const dnsName = side === "src" ? edge.srcDnsName : edge.dstDnsName; + const isExternal = side === "dst" && edge.dstKind === "external"; + const services = side === "dst" ? edge.dstServices : ""; + + if (isExternal) { + const externalKey = getExternalKey(edge); + if (externalKey && !topExternal.has(externalKey)) { + return { + id: "external:other", + title: "Other external IPs", + kind: "external" as const, + namespace: "external", + isExternal: true + }; + } + return { + id: externalKey || `external:${dnsName || ip || "unknown"}`, + title: dnsName || ip || "External", + kind: "external" as const, + namespace: "external", + isExternal: true + }; + } + + const serviceName = !pod ? extractServiceName(services) : ""; + const serviceNamespace = !namespace && serviceName ? extractNamespaceFromServices(services) : namespace; + + if (serviceNamespace && serviceName) { + return { + id: `${side}:service:${serviceNamespace}/${serviceName}`, + title: serviceName, + kind: "service" as const, + namespace: serviceNamespace, + isExternal: false + }; + } + + if (namespace && pod) { + const workload = parseWorkloadFromPod(pod); + return { + id: `${side}:${workload.kind}:${namespace}/${workload.name}`, + title: workload.name, + kind: workload.kind, + namespace, + isExternal: false + }; + } + + if (node) { + const infraKey = getInfraKey(edge, side); + if (infraKey && !topInfra.has(infraKey)) { + return { + id: "infra:other", + title: "Other infra endpoints", + kind: "node" as const, + namespace: "infrastructure", + isExternal: false + }; + } + return { + id: `${side}:node:${node}`, + title: node, + kind: "node" as const, + namespace: "infrastructure", + isExternal: false + }; + } + + if (ip) { + const infraKey = getInfraKey(edge, side); + if (infraKey && !topInfra.has(infraKey)) { + return { + id: "infra:other", + title: "Other infra endpoints", + kind: "ip" as const, + namespace: "infrastructure", + isExternal: false + }; + } + return { + id: `${side}:ip:${dnsName || ip}`, + title: dnsName || ip, + kind: "ip" as const, + namespace: "infrastructure", + isExternal: false + }; + } + + return { + id: `${side}:unknown`, + title: "Unknown", + kind: "unknown" as const, + namespace: "unknown", + isExternal: false + }; +}; + +const edgeColor = (edge: AggregatedEdge) => { + if (edge.direction === "egress" && edge.egressCostUsd > 0.01) return "#f97316"; + if (edge.isExternal && edge.direction === "ingress") return "#2563eb"; + if (edge.isExternal) return "#ef4444"; + if (edge.egressCostUsd < 0.01) return "rgba(148,163,184,0.45)"; + if (edge.isCrossAz) return "#f97316"; + return "#0ea5a4"; +}; + +const edgeLabel = (edge: AggregatedEdge) => { + if (!edge.egressCostUsd) return "$0.00"; + return `$${edge.egressCostUsd.toFixed(2)}`; +}; + +const edgeWidth = (edge: AggregatedEdge) => { + if (edge.egressCostUsd <= 0.01 && edge.direction === "internal") return 1; + const costWeight = Math.log10(edge.egressCostUsd + 1) * 2; + return Math.min(8, Math.max(1.5, 2 + costWeight)); +}; + +const isSystemNamespace = (value: string) => { + if (!value) return false; + const normalized = value.toLowerCase(); + return ( + normalized === "kube-system" || + normalized === "kube-public" || + normalized === "kube-node-lease" || + normalized === "elastic-system" || + normalized === "istio-system" || + normalized === "monitoring" || + normalized === "ingress-nginx" || + normalized === "cert-manager" || + normalized === "infrastructure" + ); +}; + +const kindMeta: Record< + ResourceKind, + { icon: typeof Box; color: string; bg: string; label: string } +> = { + service: { icon: Network, color: "#0f766e", bg: "#ccfbf1", label: "Service" }, + deployment: { icon: Layers, color: "#7c3aed", bg: "#ede9fe", label: "Deployment" }, + statefulset: { icon: Database, color: "#b45309", bg: "#ffedd5", label: "StatefulSet" }, + daemonset: { icon: Repeat, color: "#1d4ed8", bg: "#dbeafe", label: "DaemonSet" }, + pod: { icon: Box, color: "#0f172a", bg: "#e2e8f0", label: "Pod" }, + node: { icon: Server, color: "#0f766e", bg: "#ccfbf1", label: "Node" }, + ip: { icon: Globe, color: "#0f172a", bg: "#e2e8f0", label: "IP" }, + external: { icon: Cloud, color: "#b91c1c", bg: "#fee2e2", label: "External" }, + unknown: { icon: Circle, color: "#475569", bg: "#e2e8f0", label: "Unknown" } +}; + +const ResourceNode = ({ data }: NodeProps) => { + const meta = kindMeta[data.kind]; + const Icon = meta.icon; + const sourcePosition = data.kind === "external" ? Position.Bottom : Position.Top; + const targetPosition = Position.Bottom; + + return ( +
+ +
+ + + +
+ {meta.label} +
+
+
{data.title}
+
{data.namespace}
+ +
+ ); +}; + +const NamespaceNode = ({ data }: NodeProps) => ( +
+ +
+
{data.name}
+
+ {data.count} +
+
+ +
+); + +const NetworkTopologyPage = () => { + const [lookback, setLookback] = useState("1h"); + const [namespaces, setNamespaces] = useState([]); + const [namespaceCandidate, setNamespaceCandidate] = useState(""); + const [limit, setLimit] = useState(500); + const [costThreshold, setCostThreshold] = useState(defaultCostThreshold); + const [minBytesMb, setMinBytesMb] = useState(defaultMinBytesMb); + const [minConnections, setMinConnections] = useState(defaultMinConnections); + const nodeTypes = useMemo(() => ({ resource: ResourceNode, namespace: NamespaceNode }), []); + + const fetchTopology = useCallback( + () => + fetchNetworkTopology({ + lookback, + namespace: namespaces.length > 0 ? namespaces : undefined, + limit: limit > 0 ? limit : undefined, + minCost: costThreshold > 0 ? costThreshold : undefined, + minBytes: minBytesMb > 0 ? Math.round(minBytesMb * 1024 * 1024) : undefined, + minConnections: minConnections > 0 ? minConnections : undefined + }), + [lookback, namespaces, limit, costThreshold, minBytesMb, minConnections] + ); + + const { data, loading, error, refresh } = useApiData(fetchTopology); + const { data: namespaceData } = useApiData(fetchNamespaces); + + const namespaceOptions = useMemo(() => { + if (!namespaceData?.records) return []; + return namespaceData.records + .map((record) => record.namespace) + .filter((name) => name) + .sort((a, b) => a.localeCompare(b)); + }, [namespaceData]); + + const addNamespace = useCallback(() => { + if (!namespaceCandidate) return; + if (namespaces.includes(namespaceCandidate)) return; + setNamespaces((prev) => [...prev, namespaceCandidate]); + setNamespaceCandidate(""); + }, [namespaceCandidate, namespaces]); + + const removeNamespace = useCallback((value: string) => { + setNamespaces((prev) => prev.filter((entry) => entry !== value)); + }, []); + + const { nodes, edges } = useMemo(() => { + if (!data?.edges?.length) return { nodes: [], edges: [] }; + + const nodeMap = new Map>(); + const aggregatedEdges = new Map(); + + const externalUsage = new Map(); + const infraUsage = new Map(); + + data.edges.forEach((edge) => { + const bytes = edge.bytesSent + edge.bytesReceived; + const externalKey = getExternalKey(edge); + if (externalKey) { + externalUsage.set(externalKey, (externalUsage.get(externalKey) ?? 0) + bytes); + } + + (["src", "dst"] as const).forEach((side) => { + const infraKey = getInfraKey(edge, side); + if (!infraKey) return; + infraUsage.set(infraKey, (infraUsage.get(infraKey) ?? 0) + bytes); + }); + }); + + const topExternal = new Set( + Array.from(externalUsage.entries()) + .sort((a, b) => b[1] - a[1]) + .slice(0, maxExternalEndpoints) + .map(([key]) => key) + ); + const topInfra = new Set( + Array.from(infraUsage.entries()) + .sort((a, b) => b[1] - a[1]) + .slice(0, maxInfraEndpoints) + .map(([key]) => key) + ); + + data.edges.forEach((edge) => { + const srcGroup = buildEndpointGroup(edge, "src", topExternal, topInfra); + const dstGroup = buildEndpointGroup(edge, "dst", topExternal, topInfra); + + if (!nodeMap.has(srcGroup.id)) { + nodeMap.set(srcGroup.id, { + id: srcGroup.id, + data: { title: srcGroup.title, kind: srcGroup.kind, namespace: srcGroup.namespace }, + position: { x: 0, y: 0 }, + type: "resource" + }); + } + if (!nodeMap.has(dstGroup.id)) { + nodeMap.set(dstGroup.id, { + id: dstGroup.id, + data: { title: dstGroup.title, kind: dstGroup.kind, namespace: dstGroup.namespace }, + position: { x: 0, y: 0 }, + type: "resource" + }); + } + + const srcEdgeId = + dstGroup.kind === "external" && srcGroup.namespace + ? `namespace:${srcGroup.namespace}` + : srcGroup.kind === "external" && dstGroup.namespace + ? srcGroup.id + : srcGroup.id; + const dstEdgeId = + srcGroup.kind === "external" && dstGroup.namespace + ? `namespace:${dstGroup.namespace}` + : dstGroup.id; + + const key = `${srcEdgeId}->${dstEdgeId}`; + const isCrossAz = + Boolean(edge.srcAvailabilityZone) && + Boolean(edge.dstAvailabilityZone) && + edge.srcAvailabilityZone !== edge.dstAvailabilityZone; + const direction = + srcGroup.kind === "external" ? "ingress" : dstGroup.kind === "external" ? "egress" : "internal"; + + const existing = aggregatedEdges.get(key); + if (existing) { + existing.bytesSent += edge.bytesSent; + existing.bytesReceived += edge.bytesReceived; + existing.egressCostUsd += edge.egressCostUsd; + existing.connectionCount += edge.connectionCount; + existing.isCrossAz = existing.isCrossAz || isCrossAz; + existing.isExternal = existing.isExternal || edge.dstKind === "external" || srcGroup.kind === "external"; + existing.direction = existing.direction === "internal" ? direction : existing.direction; + } else { + aggregatedEdges.set(key, { + srcId: srcEdgeId, + dstId: dstEdgeId, + bytesSent: edge.bytesSent, + bytesReceived: edge.bytesReceived, + egressCostUsd: edge.egressCostUsd, + connectionCount: edge.connectionCount, + isExternal: edge.dstKind === "external" || srcGroup.kind === "external", + isCrossAz, + direction + }); + } + }); + + const flowEdges: Edge[] = Array.from(aggregatedEdges.values()).map((edge) => ({ + id: `${edge.srcId}->${edge.dstId}`, + source: edge.srcId, + target: edge.dstId, + type: "step", + animated: edge.isExternal && edge.direction === "egress", + label: edgeLabel(edge), + style: { + stroke: edgeColor(edge), + strokeWidth: edgeWidth(edge), + strokeDasharray: edge.egressCostUsd < 0.01 && edge.direction === "internal" ? "4 6" : undefined + }, + labelStyle: { + fill: "#0f172a", + fontWeight: 600 + }, + labelBgPadding: [6, 4], + labelBgBorderRadius: 6, + labelBgStyle: { fill: "rgba(255,255,255,0.9)" } + })); + + const activeNodeIds = new Set(); + flowEdges.forEach((edge) => { + activeNodeIds.add(edge.source); + activeNodeIds.add(edge.target); + }); + + const namespaceMap = new Map[]>(); + const externalNodes: Node[] = []; + nodeMap.forEach((node) => { + if (!activeNodeIds.has(node.id)) return; + if (node.data.kind === "external") { + externalNodes.push(node); + return; + } + const ns = node.data.namespace || "unknown"; + if (!namespaceMap.has(ns)) namespaceMap.set(ns, []); + namespaceMap.get(ns)?.push(node); + }); + + const namespaceList = Array.from(namespaceMap.keys()).sort((a, b) => a.localeCompare(b)); + const primaryNamespaces = namespaceList.filter((value) => !isSystemNamespace(value)); + const systemNamespaces = namespaceList.filter((value) => isSystemNamespace(value)); + const namespaceNodes: Node[] = []; + const childNodes: Node[] = []; + const namespaceColumns = primaryNamespaces.length > 6 ? 3 : 2; + const namespaceColumnWidth = 980; + const namespaceGap = 40; + const layoutNamespaces = (namespaces: string[], baseY: number) => { + const localNamespaceNodes: Node[] = []; + const localRowHeights: number[] = []; + + namespaces.forEach((ns, index) => { + const children = (namespaceMap.get(ns) ?? []).sort((a, b) => { + if (a.data.kind !== b.data.kind) return a.data.kind.localeCompare(b.data.kind); + return a.data.title.localeCompare(b.data.title); + }); + + const childColumns = Math.min(4, Math.max(2, Math.ceil(Math.sqrt(children.length || 1)))); + const childRows = Math.max(1, Math.ceil(children.length / childColumns)); + const groupWidth = Math.max(420, childColumns * nodeSpacing + groupPadding * 2); + const groupHeight = childRows * nodeSpacing + groupPadding * 2 + groupHeaderHeight; + + const col = index % namespaceColumns; + const row = Math.floor(index / namespaceColumns); + localRowHeights[row] = Math.max(localRowHeights[row] ?? 0, groupHeight); + + localNamespaceNodes.push({ + id: `namespace:${ns}`, + type: "namespace", + data: { name: ns, count: children.length }, + position: { x: 0, y: 0 }, + style: { width: groupWidth, height: groupHeight, zIndex: 0, pointerEvents: "none" }, + sourcePosition: Position.Top, + targetPosition: Position.Bottom, + selectable: false, + draggable: false + }); + + children.forEach((node, idx) => { + const rowIndex = Math.floor(idx / childColumns); + const colIndex = idx % childColumns; + node.parentNode = `namespace:${ns}`; + node.extent = "parent"; + node.position = { + x: groupPadding + colIndex * nodeSpacing, + y: groupPadding + groupHeaderHeight + rowIndex * nodeSpacing + }; + node.style = { ...(node.style ?? {}), zIndex: 2 }; + node.sourcePosition = Position.Top; + node.targetPosition = Position.Bottom; + childNodes.push(node); + }); + }); + + const rowOffsets: number[] = []; + localRowHeights.forEach((height, idx) => { + rowOffsets[idx] = (rowOffsets[idx - 1] ?? 0) + (idx === 0 ? 0 : localRowHeights[idx - 1] + namespaceGap); + }); + + localNamespaceNodes.forEach((node, index) => { + const col = index % namespaceColumns; + const row = Math.floor(index / namespaceColumns); + node.position = { + x: col * (namespaceColumnWidth + namespaceGap), + y: baseY + (rowOffsets[row] ?? 0) + }; + }); + + namespaceNodes.push(...localNamespaceNodes); + const totalHeight = + localRowHeights.length === 0 + ? 0 + : localRowHeights.reduce((sum, height) => sum + height, 0) + + namespaceGap * (localRowHeights.length - 1); + return totalHeight; + }; + + const externalRowColumns = Math.min(6, Math.max(2, externalNodes.length)); + const externalRowHeight = + externalNodes.length === 0 + ? 0 + : Math.ceil(externalNodes.length / externalRowColumns) * nodeSpacing + externalRowPadding * 2; + + externalNodes.forEach((node, index) => { + const col = index % externalRowColumns; + const row = Math.floor(index / externalRowColumns); + node.position = { + x: col * (nodeSpacing + 40), + y: externalRowPadding + row * nodeSpacing + }; + node.targetPosition = Position.Bottom; + node.sourcePosition = Position.Bottom; + }); + + const middleStartY = externalRowHeight + tierGap; + const middleHeight = layoutNamespaces(primaryNamespaces, middleStartY); + + const systemStartY = middleStartY + Math.max(0, middleHeight) + tierGap; + layoutNamespaces(systemNamespaces, systemStartY); + + return { nodes: [...externalNodes, ...namespaceNodes, ...childNodes], edges: flowEdges }; + }, [data]); + + const totalCost = useMemo(() => { + if (!data?.edges) return 0; + return data.edges.reduce((sum, edge) => sum + edge.egressCostUsd, 0); + }, [data]); + + return ( +
+
+
+

Cost-Aware Network Topology

+

+ Highlight cross-AZ and internet egress connections with real cost impact. +

+
+
+
+ +
+
+
+
+ +
+ + +
+ {namespaces.length > 0 ? ( +
+ {namespaces.map((name) => ( + + {name} + + + ))} +
+ ) : ( +

All namespaces

+ )} +
+ { + const parsed = Number(event.target.value); + setLimit(Number.isFinite(parsed) ? Math.max(0, Math.floor(parsed)) : 0); + }} + placeholder="Max edges" + className="w-28" + inputMode="numeric" + /> + { + const parsed = Number(event.target.value); + setCostThreshold(Number.isFinite(parsed) ? Math.max(0, parsed) : 0); + }} + placeholder="Min cost $" + className="w-28" + inputMode="decimal" + /> + { + const parsed = Number(event.target.value); + setMinBytesMb(Number.isFinite(parsed) ? Math.max(0, parsed) : 0); + }} + placeholder="Min MB" + className="w-24" + inputMode="decimal" + /> + { + const parsed = Number(event.target.value); + setMinConnections(Number.isFinite(parsed) ? Math.max(0, Math.floor(parsed)) : 0); + }} + placeholder="Min conns" + className="w-24" + inputMode="numeric" + /> + +
+
+ +
+ +

Edges

+

{data?.totalEdges ?? 0}

+

+ Aggregated {edges.length} • Limit {data?.requestedLimit ?? limit} +

+
+ +

Estimated Egress Cost

+

${totalCost.toFixed(2)}

+

Across current window

+
+ +

Legend

+
+
+ + Intra-AZ / Internal +
+
+ + Cross-AZ +
+
+ + Internet Egress +
+
+ + Internet Ingress +
+
+
+
+ + + {loading ? ( +
+ +
+ ) : error ? ( +
+

Failed to load topology.

+ +
+ ) : nodes.length === 0 ? ( +
+ No network connections found for this window. +
+ ) : ( + + + + + + )} +
+
+ ); +}; + +export default NetworkTopologyPage; diff --git a/web/src/pages/overview/OverviewPage.tsx b/web/src/pages/overview/OverviewPage.tsx index 1fd735d..637f951 100644 --- a/web/src/pages/overview/OverviewPage.tsx +++ b/web/src/pages/overview/OverviewPage.tsx @@ -16,6 +16,9 @@ import { CostByEnvironmentChart } from "../../charts/CostByEnvironmentChart"; import { NamespaceDetailSheet } from "@/components/namespaces/NamespaceDetailSheet"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { Progress } from "@/components/ui/progress"; +import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; +import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from "@/components/ui/sheet"; interface DerivedNamespace { name: string; @@ -28,6 +31,9 @@ interface DerivedNamespace { cpuUsed: number; memoryRequested: number; memoryUsed: number; + efficiencyRatio: number; + wasteMonthlyCost: number; + wastePercent: number; labels: Record; } @@ -45,6 +51,7 @@ const envMap: Record = { const OverviewPage = () => { const { data, loading, error, refresh } = useApiData(fetchNamespaces); const [selected, setSelected] = useState(null); + const [selectedZombie, setSelectedZombie] = useState(null); const records = data?.records ?? []; @@ -58,6 +65,11 @@ const OverviewPage = () => { const memoryUsed = bytesToGiB(record.memoryUsageBytes ?? 0); const cpuUsagePercent = cpuRequested > 0 ? Math.min(100, (cpuUsed / cpuRequested) * 100) : 0; const memoryUsagePercent = memoryRequested > 0 ? Math.min(100, (memoryUsed / memoryRequested) * 100) : 0; + const cpuEfficiency = cpuRequested > 0 ? cpuUsed / cpuRequested : 1; + const memoryEfficiency = memoryRequested > 0 ? memoryUsed / memoryRequested : 1; + const efficiencyRatio = Math.max(0, Math.min(1, Math.min(cpuEfficiency, memoryEfficiency))); + const wastePercent = 1 - Math.max(0, Math.min(1, (cpuEfficiency + memoryEfficiency) / 2)); + const wasteMonthlyCost = toMonthlyCost(hourlyCost) * wastePercent; return { name: record.namespace, hourlyCost, @@ -69,6 +81,9 @@ const OverviewPage = () => { cpuUsed, memoryRequested, memoryUsed, + efficiencyRatio, + wasteMonthlyCost, + wastePercent, labels: record.labels ?? {} }; }); @@ -76,6 +91,9 @@ const OverviewPage = () => { const sortedByCost = useMemo(() => [...derived].sort((a, b) => b.monthlyCost - a.monthlyCost), [derived]); const totalMonthly = useMemo(() => derived.reduce((sum, ns) => sum + ns.monthlyCost, 0), [derived]); + const totalWasteMonthly = useMemo(() => derived.reduce((sum, ns) => sum + ns.wasteMonthlyCost, 0), [derived]); + const totalWastePercent = totalMonthly > 0 ? (totalWasteMonthly / totalMonthly) * 100 : 0; + const hourlyLeak = totalWasteMonthly / (30 * 24); const topNamespace = sortedByCost[0]; const topNamespaceShare = topNamespace && totalMonthly > 0 ? (topNamespace.monthlyCost / totalMonthly) * 100 : 0; const buckets = useMemo(() => { @@ -112,6 +130,51 @@ const OverviewPage = () => { const lastUpdated = data?.lastUpdated ? relativeTimeFromIso(data.lastUpdated) : "moments ago"; + const zombieCandidates = useMemo(() => { + return [...derived] + .filter((ns) => ns.efficiencyRatio > 0 && ns.efficiencyRatio < 0.1) + .sort((a, b) => b.wasteMonthlyCost - a.wasteMonthlyCost) + .slice(0, 5); + }, [derived]); + + const heatmapCells = useMemo(() => { + return derived + .map((ns) => { + const tone = + ns.wastePercent >= 0.7 + ? "bg-red-600/90 text-white border-red-500/60" + : ns.wastePercent >= 0.4 + ? "bg-amber-400/80 text-amber-950 border-amber-500/60" + : "bg-emerald-500/20 text-emerald-900 border-emerald-500/30"; + return { ...ns, tone }; + }) + .sort((a, b) => b.wastePercent - a.wastePercent); + }, [derived]); + + const selectedZombieYaml = useMemo(() => { + if (!selectedZombie) return ""; + const cpuTarget = Math.max(0.1, selectedZombie.cpuUsed * 1.2); + const memoryTarget = Math.max(0.1, selectedZombie.memoryUsed * 1.2); + return `apiVersion: apps/v1 +kind: Deployment +metadata: + name: ${selectedZombie.name}-resized + namespace: ${selectedZombie.name} +spec: + template: + spec: + containers: + - name: app + resources: + requests: + cpu: "${cpuTarget.toFixed(2)}" + memory: "${memoryTarget.toFixed(1)}Gi" + limits: + cpu: "${(cpuTarget * 1.5).toFixed(2)}" + memory: "${(memoryTarget * 1.5).toFixed(1)}Gi" +`; + }, [selectedZombie]); + const detailSnapshot = selected ? { name: selected.name, @@ -201,6 +264,137 @@ const OverviewPage = () => {
Last updated {lastUpdated}
+
+ + +
+ Monthly Burn + + Recuperable Revenue + +
+ + Money leaking from the budget based on request vs reality. + +
+ +
+

Potential Monthly Savings

+

{formatCurrency(totalWasteMonthly)}

+

+ You are wasting {formatPercentage(totalWastePercent, { fractionDigits: 0 })} of your allocated budget. +

+
+
+ + Leaking {formatCurrency(hourlyLeak, { maximumFractionDigits: 2 })}/hr right now + + Last updated {lastUpdated} +
+
+
+ + + + Savings report + + Export the top offenders for finance. + + + +
+

Executive PDF snapshot

+

Top 5 zombies + total savings, 1 page.

+
+ +
+
+
+ +
+ + + Top 5 money zombies + Pods consuming < 10% of what they reserved. + + + {zombieCandidates.length === 0 ? ( +
+ No zombies detected. Utilization is tight right now. +
+ ) : ( +
+ + + + Namespace + Efficiency + Cost of silence + Action + + + + {zombieCandidates.map((ns) => { + const multiplier = ns.efficiencyRatio > 0 ? Math.min(99, Math.round(1 / ns.efficiencyRatio)) : 99; + return ( + + +
+ {ns.name} + Zombie +
+
+ + {formatPercentage(ns.efficiencyRatio * 100, { fractionDigits: 0 })} ({multiplier}x) + + + {formatCurrency(ns.wasteMonthlyCost, { maximumFractionDigits: 0 })} + + + + +
+ ); + })} +
+
+
+ )} +
+
+ + + + Efficiency heatmap + Bright red = massive waste. + + +
+ {heatmapCells.map((ns) => ( +
+
+ {ns.name} + {formatPercentage(ns.wastePercent * 100, { fractionDigits: 0 })} +
+
+ ))} +
+
+
+
+
@@ -404,6 +598,38 @@ const OverviewPage = () => {
!open && setSelected(null)} data={detailSnapshot} /> + !open && setSelectedZombie(null)}> + + + Optimization action + Generated YAML to resize the zombie workload. + + {selectedZombie ? ( +
+
+

+ {selectedZombie.name} is wasting {formatCurrency(selectedZombie.wasteMonthlyCost)} / month +

+

+ Efficiency {formatPercentage(selectedZombie.efficiencyRatio * 100, { fractionDigits: 0 })} · Requests far + above reality +

+
+
+

Proposed YAML

+
+                  {selectedZombieYaml}
+                
+
+
+ +
+
+ ) : null} +
+
); }; diff --git a/web/src/router.tsx b/web/src/router.tsx index 2557a0c..9da315a 100644 --- a/web/src/router.tsx +++ b/web/src/router.tsx @@ -6,6 +6,9 @@ import NodesPage from "./pages/nodes/NodesPage"; import ResourcesPage from "./pages/resources/ResourcesPage"; import AgentsPage from "./pages/AgentsPage"; import ConnectCloudPage from "./pages/ConnectCloudPage"; +import LoginPage from "./pages/LoginPage"; +import NetworkTopologyPage from "./pages/network/NetworkTopologyPage"; +import ProtectedRoute from "./components/layout/ProtectedRoute"; import RouteError from "./components/layout/RouteError"; const router = createBrowserRouter([ @@ -14,12 +17,22 @@ const router = createBrowserRouter([ element: , errorElement: , children: [ - { index: true, element: }, - { path: "namespaces", element: }, - { path: "nodes", element: }, - { path: "resources", element: }, - { path: "agents", element: }, - { path: "connect-cloud", element: } + { + path: "login", + element: + }, + { + element: , + children: [ + { index: true, element: }, + { path: "namespaces", element: }, + { path: "nodes", element: }, + { path: "resources", element: }, + { path: "network", element: }, + { path: "agents", element: }, + { path: "connect-cloud", element: } + ] + } ] } ]);