System Overview
FinFocus is a CLI tool and plugin host system for calculating cloud infrastructure costs from Pulumi infrastructure definitions. It provides both projected cost estimates and actual historical cost analysis through a plugin-based architecture.
Architecture Diagram
Section titled “Architecture Diagram”See the System Architecture Diagram for a visual representation of all components and their relationships.
Core Components
Section titled “Core Components”CLI Layer
Section titled “CLI Layer”Location: internal/cli
The CLI layer provides a Cobra-based command-line interface with the following subcommands:
cost projected- Calculate projected costs from Pulumi preview JSONcost actual- Fetch actual historical costs with time rangesplugin list- List installed pluginsplugin validate- Validate plugin installations
Design Pattern: Command pattern with Cobra framework
Engine
Section titled “Engine”Location: internal/engine
The Engine is the core orchestration layer that coordinates between plugins, local specifications, and output formatting.
Responsibilities:
- Cost calculation orchestration
- Plugin selection and fallback logic
- Resource mapping and aggregation
- Multiple output format support (table, JSON, NDJSON)
- Actual cost pipeline with advanced querying
Key Methods:
CalculateProjectedCost()- Estimate future costs from Pulumi plansGetActualCostWithOptions()- Query historical costs with filteringCreateCrossProviderAggregation()- Aggregate costs across providers
Ingest
Section titled “Ingest”Location: internal/ingest
The Ingest component parses Pulumi JSON output and converts it to internal resource descriptors.
Process:
- Read
pulumi preview --jsonoutput file - Extract resource definitions
- Parse provider, type, SKU, region, tags
- Build ResourceDescriptor objects
Output: Array of ResourceDescriptor objects for Engine processing
Plugin Host
Section titled “Plugin Host”Location: internal/pluginhost
The Plugin Host manages gRPC connections to external cost source plugins.
Components:
Client- Wraps plugin gRPC connectionsProcessLauncher- Launches plugins as TCP processesStdioLauncher- Alternative stdio-based communication
Lifecycle Management:
- Process spawning and monitoring
- Connection establishment with retries
- Graceful shutdown handling
See Plugin Lifecycle Diagram for detailed state transitions.
Registry
Section titled “Registry”Location: internal/registry
The Registry discovers and manages plugin lifecycle from the filesystem.
Discovery Process:
- Scan
~/.finfocus/plugins/<name>/<version>/directories - Validate plugin binaries (Unix permissions or Windows .exe extension)
- Load optional
plugin.manifest.jsonmetadata - Build available plugins catalog
Directory Structure:
~/.finfocus/└── plugins/ ├── kubecost/ │ └── 1.0.0/ │ ├── kubecost-plugin │ └── plugin.manifest.json └── vantage/ └── 1.0.0/ ├── vantage-plugin └── plugin.manifest.jsonSpec System
Section titled “Spec System”Location: internal/spec
The Spec System provides fallback pricing when plugins are unavailable.
Specification Format:
provider: awsresource_type: ec2sku: t3.microregion: us-east-1billing_mode: per_hourrate_per_unit: 0.0104currency: USDdescription: AWS EC2 t3.micro instance pricingLocation: ~/.finfocus/specs/
Data Flow
Section titled “Data Flow”See the Data Flow Diagram for a complete sequence diagram showing how data flows through the system.
High-Level Flow
Section titled “High-Level Flow”Pulumi JSON → Resource Descriptors → Plugin Queries →Cost Results → Aggregation → Output RenderingProjected Cost Flow
Section titled “Projected Cost Flow”- User generates Pulumi plan with
pulumi preview --json - User runs
finfocus cost projected --pulumi-json plan.json - CLI passes plan path to Engine
- Engine delegates to Ingest to parse JSON
- Ingest extracts resources and builds ResourceDescriptors
- Engine discovers plugins via Registry
- Engine connects to plugins via PluginHost
- For each resource, Engine queries plugin for projected cost
- Plugin queries external API for pricing data
- Plugin calculates monthly cost estimate
- Engine aggregates all costs
- Engine formats output (table/JSON/NDJSON)
- CLI displays result to user
Actual Cost Flow
Section titled “Actual Cost Flow”- User runs
finfocus cost actual --start-date X --end-date Y - CLI builds ActualCostRequest with time range and filters
- Engine connects to plugins
- For each resource, Engine queries plugin for actual costs
- Plugin queries external API for historical cost data
- Plugin returns daily/monthly cost breakdowns
- Engine aggregates costs with grouping (resource, type, provider, date)
- Engine validates currency consistency
- Engine formats output
- CLI displays result to user
Key Design Patterns
Section titled “Key Design Patterns”Plugin Architecture
Section titled “Plugin Architecture”Pattern: Plugin-based extensibility
Benefits:
- Third-party cost source integration without core changes
- Language-agnostic plugin development (any language with gRPC)
- Isolated plugin failures don’t crash main system
- Independent plugin versioning and deployment
Protocol: gRPC using protocol buffers from finfocus-spec repository
See Plugin Protocol for complete gRPC specification.
Fallback Pattern
Section titled “Fallback Pattern”Pattern: Try plugins first, fall back to local specifications
Flow:
1. Try available plugins for resource type2. If plugin fails or doesn't support: → Load local YAML spec from ~/.finfocus/specs/3. If spec not found: → Return placeholder cost ($0.00 with "unknown" source)Guarantee: System always produces output, even with incomplete data
Registry Pattern
Section titled “Registry Pattern”Pattern: Dynamic plugin discovery from filesystem
Benefits:
- No hardcoded plugin list in core
- Users install plugins by copying to directory
- Multiple versions can coexist
- Platform-specific binary detection
Adapter Pattern
Section titled “Adapter Pattern”Pattern: Engine adapts between CLI expectations and plugin realities
Implementation:
internal/proto/adapter.go- Bridges engine types with proto types- Converts between internal ResourceDescriptor and proto ResourceDescriptor
- Handles error translation from proto to Go errors
Cost Calculation
Section titled “Cost Calculation”See Cost Calculation for detailed algorithms and Cost Calculation Flow Diagram for flowchart.
Projected Cost Formula
Section titled “Projected Cost Formula”Monthly Cost = Unit Price × Hours Per Month
Where: Hours Per Month = 730 (standard constant) Unit Price = From plugin or local specActual Cost Aggregation
Section titled “Actual Cost Aggregation”Total Cost = Σ (Daily Cost) for date in [start, end]
With optional grouping by: - Resource ID - Resource Type (ec2, s3, etc.) - Provider (aws, azure, gcp) - Date (daily or monthly aggregation)Cross-Provider Aggregation
Section titled “Cross-Provider Aggregation”Feature: Aggregate costs across multiple cloud providers
Validation:
- Ensures consistent currency (USD, EUR, etc.)
- Validates date ranges (end > start)
- Supports time-based grouping only (daily, monthly)
Error Handling:
ErrMixedCurrencies- Different currencies detectedErrInvalidGroupBy- Non-time-based grouping attemptedErrInvalidDateRange- Invalid date range provided
Error Handling Strategy
Section titled “Error Handling Strategy”Transient Errors
Section titled “Transient Errors”Examples: Network timeout, rate limiting, service unavailable
Handling:
- Retry up to 3 times with exponential backoff
- Wait intervals: 100ms, 200ms, 400ms
- Continue with next plugin or fallback to specs
Permanent Errors
Section titled “Permanent Errors”Examples: Resource not found, invalid credentials, unsupported region
Handling:
- No retry
- Immediately fall back to local specs
- Log error for user visibility
Configuration Errors
Section titled “Configuration Errors”Examples: Missing API key, invalid endpoint, missing plugin binary
Handling:
- Report clear error message to user
- Suggest configuration fixes
- Exit with non-zero status code
Output Formats
Section titled “Output Formats”Table Format
Section titled “Table Format”┌──────────────────┬─────────┬──────────┬─────────────┐│ Resource │ Type │ Cost/mo │ Source │├──────────────────┼─────────┼──────────┼─────────────┤│ aws-ec2-i-123 │ t3.micro│ $7.59 │ vantage ││ aws-ec2-i-456 │ t3.micro│ $7.59 │ vantage │├──────────────────┼─────────┼──────────┼─────────────┤│ Total │ │ $15.18 │ │└──────────────────┴─────────┴──────────┴─────────────┘JSON Format
Section titled “JSON Format”{ "resources": [ { "id": "aws-ec2-i-123", "type": "t3.micro", "cost_per_month": 7.59, "currency": "USD", "source": "vantage" } ], "total_cost": 15.18, "currency": "USD"}NDJSON Format
Section titled “NDJSON Format”{"id":"aws-ec2-i-123","type":"t3.micro","cost_per_month":7.59}{"id":"aws-ec2-i-456","type":"t3.micro","cost_per_month":7.59}Dependencies
Section titled “Dependencies”External Libraries
Section titled “External Libraries”github.com/spf13/cobra- CLI frameworkgoogle.golang.org/grpc- Plugin communicationgopkg.in/yaml.v3- YAML spec parsinggithub.com/rshade/finfocus-spec- Protocol definitions
Protocol Version
Section titled “Protocol Version”Current protocol version: v0.1.0 (frozen and integrated)
Protocol Repository:
github.com/rshade/finfocus-spec/proto/finfocus/v1/costsource.proto
Plugin Protocol Integration
Section titled “Plugin Protocol Integration”The project uses real protocol buffer definitions from the finfocus-spec
repository.
Integration:
internal/proto/adapter.go- Adapts between engine and proto types- Generated SDK:
github.com/rshade/finfocus-spec/sdk/go/proto - gRPC v1.74.2, protobuf v1.36.7
Services:
CostSourceService- Core cost operationsObservabilityService- Health checks and metrics (future)
See Plugin Protocol for complete gRPC specification.
Integration Example
Section titled “Integration Example”See Integration Example Diagram for a complete end-to-end example showing Pulumi → FinFocus → Vantage API integration.
Related Documentation:
- Plugin Protocol - gRPC protocol specification
- Cost Calculation - Detailed calculation algorithms
- CLI Commands - Command-line reference
- API Reference - Complete API docs