Plugin Routing Configuration Guide
Feature: Multi-Plugin Routing | Status: Stable | Since: v0.3.0
Overview
Section titled “Overview”FinFocus intelligently routes cost calculation requests to the most appropriate plugins based on:
- Provider Matching: Automatically route resources to plugins that support their cloud provider
- Feature Capabilities: Route different operations (projected costs, recommendations) to specialized plugins
- Resource Patterns: Override default routing with custom glob or regex patterns
- Priority Ordering: Control which plugin is preferred when multiple match
- Automatic Fallback: Retry with alternative plugins when the primary fails
Table of Contents
Section titled “Table of Contents”- Overview
- How Routing Works
- Configuration Reference
- Common Configuration Patterns
- Validation
- Debugging Routing Decisions
- Troubleshooting
- Performance Considerations
- Migration from All-Plugin Querying
- Advanced Topics
- Best Practices
- Related Documentation
- Changelog
How Routing Works
Section titled “How Routing Works”Layer 1: Automatic Provider-Based Routing (Zero Configuration)
Section titled “Layer 1: Automatic Provider-Based Routing (Zero Configuration)”FinFocus automatically routes resources based on the SupportedProviders metadata each plugin reports:
# Install plugins - routing happens automaticallyfinfocus plugin install aws-publicfinfocus plugin install gcp-public
# Verify what each plugin supportsfinfocus plugin list# NAME VERSION PROVIDERS# aws-public 1.0.0 aws# gcp-public 1.0.0 gcp## Note: Output is tab-delimited. Column alignment may vary by terminal.
# Cost calculation automatically routes resourcesfinfocus cost projected --pulumi-json multi-cloud-plan.json# aws:ec2/instance:Instance → aws-public (provider: aws)# gcp:compute/instance:Instance → gcp-public (provider: gcp)Provider Extraction: FinFocus extracts the provider from the resource type’s first segment:
| Resource Type | Provider |
|---|---|
aws:ec2/instance:Instance | aws |
gcp:compute/instance:Instance | gcp |
azure:compute/virtualMachine:VirtualMachine | azure |
kubernetes:core/v1:Pod | kubernetes |
Global Plugins: Plugins reporting ["*"] or empty providers match ALL resources (e.g., debugging plugins).
Metadata-Aware Binary Selection: When a plugin is installed with
--metadata="region=us-west-2", the registry writes a plugin.metadata.json
file alongside the binary.
At load time the registry reads this metadata and prefers a region-specific
binary (e.g., finfocus-plugin-aws-public-us-west-2) over the generic one.
If no region binary is found, the standard binary is used as a fallback.
Layer 2: Declarative Configuration (Advanced Control)
Section titled “Layer 2: Declarative Configuration (Advanced Control)”For advanced scenarios, add routing rules to ~/.finfocus/config.yaml:
routing: plugins: - name: aws-ce features: - Recommendations priority: 20 fallback: true
- name: aws-public features: - ProjectedCosts - ActualCosts patterns: - type: glob pattern: 'aws:*' priority: 10 fallback: trueConfiguration Reference
Section titled “Configuration Reference”RoutingConfig
Section titled “RoutingConfig”routing: plugins: - name: <plugin-name> # Required: Installed plugin name features: [...] # Optional: Limit to specific capabilities patterns: [...] # Optional: Resource type patterns priority: <number> # Optional: Selection priority (default: 0) fallback: <bool> # Optional: Enable fallback (default: true)PluginRouting Fields
Section titled “PluginRouting Fields”name (required)
Section titled “name (required)”The plugin identifier. Must match an installed plugin name from finfocus plugin list.
- name: aws-publicfeatures (optional)
Section titled “features (optional)”Limits which capabilities this plugin handles. Valid values:
ProjectedCosts- Monthly cost estimatesActualCosts- Historical spending dataRecommendations- Cost optimization suggestionsCarbon- Carbon emission calculationsDryRun- What-if analysisBudgets- Budget tracking
Empty/omitted: Plugin handles all features it reports.
- name: aws-ce features: - Recommendations - ActualCostspatterns (optional)
Section titled “patterns (optional)”Resource type patterns that override automatic provider matching.
Empty/omitted: Use automatic provider-based routing.
patterns: # Glob pattern (simpler syntax) - type: glob pattern: 'aws:eks:*'
# Regex pattern (full RE2 syntax) - type: regex pattern: 'aws:(ec2|rds)/.*'Pattern Types:
| Type | Syntax | Example | Matches |
|---|---|---|---|
glob | *, ?, [...] | aws:ec2:* | aws:ec2:Instance, aws:ec2:SecurityGroup |
regex | RE2 regex | aws:eks:.* | aws:eks:Cluster, aws:eks:NodeGroup |
Pattern Precedence: Patterns override automatic provider matching. If a pattern matches, the resource routes to that plugin regardless of provider.
priority (optional)
Section titled “priority (optional)”Controls plugin selection order when multiple plugins match the same resource.
Default: 0 (all plugins queried in parallel)
Behavior:
- Higher priority = preferred:
priority: 30beatspriority: 10 - Equal priority: Query all matching plugins in parallel
- Priority 0: Special case - always query all matching
- name: eks-costs priority: 30 # Highest - try first
- name: aws-ce priority: 20 # Medium
- name: aws-public priority: 10 # Lowest - fallbackfallback (optional)
Section titled “fallback (optional)”Enables automatic retry with the next priority plugin if this one fails.
Default: true
Fallback Triggers:
- Connection timeout
- Plugin crash (EOF, connection reset)
- Empty result (no cost data)
- gRPC error (unavailable, internal)
NOT Fallback Triggers:
- Validation error (InvalidArgument) - plugin explicitly rejected
- $0 cost result - this is a valid result, not a failure
- name: aws-ce fallback: true # Retry with next plugin on failure
- name: aws-public fallback: false # Last resort - don't fallbackCommon Configuration Patterns
Section titled “Common Configuration Patterns”Pattern 1: Multi-Cloud Setup
Section titled “Pattern 1: Multi-Cloud Setup”Automatic routing works perfectly for multi-cloud infrastructure:
routing: plugins: - name: aws-public priority: 10 - name: gcp-public priority: 10 - name: azure-public priority: 10Result: Each resource automatically routes to its provider’s plugin.
Pattern 2: Feature-Specific Routing
Section titled “Pattern 2: Feature-Specific Routing”Route different features to specialized plugins:
routing: plugins: # AWS Cost Explorer for recommendations (uses AWS API) - name: aws-ce features: - Recommendations - ActualCosts priority: 20
# AWS Public for projected costs (no credentials needed) - name: aws-public features: - ProjectedCosts priority: 10Result:
finfocus cost projected→ aws-publicfinfocus cost recommendations→ aws-cefinfocus cost actual→ aws-ce
Pattern 3: Specialized Plugin Override
Section titled “Pattern 3: Specialized Plugin Override”Route specific resource types to specialized plugins:
routing: plugins: # EKS-specific plugin for Kubernetes costs - name: eks-costs patterns: - type: glob pattern: 'aws:eks:*' priority: 30
# RDS-specific plugin for database costs - name: rds-optimizer patterns: - type: regex pattern: 'aws:rds:.*' priority: 30
# General AWS plugin for everything else - name: aws-public priority: 10Result:
aws:eks:Cluster→ eks-costs (pattern match)aws:rds:Instance→ rds-optimizer (pattern match)aws:ec2:Instance→ aws-public (provider match)
Pattern 4: Priority Chain with Fallback
Section titled “Pattern 4: Priority Chain with Fallback”Configure primary plugin with automatic fallback to backup:
routing: plugins: # Primary: Try AWS Cost Explorer first (most accurate) - name: aws-ce priority: 20 fallback: true
# Secondary: Try AWS Public as backup - name: aws-public priority: 10 fallback: true
# Tertiary: Local specs as last resort (automatic)Execution Flow:
- Try
aws-ce(priority 20) - If fails and
fallback: true→ tryaws-public(priority 10) - If fails and
fallback: true→ try local specs (built-in) - If no specs → return “no cost data available”
Note: Routing does not apply in analyzer/policy-pack mode
When finfocus runs as a Pulumi policy pack (
pulumi preview --policy-pack), routing configuration is not consulted. All plugins discovered in the plugin directory are loaded and queried for every resource.Additionally, global plugins (those with
supported_providers: ["*"]) cannot be excluded via routing even in standard CLI mode — they are always included for all resources.To exclude specific plugins when running as a policy pack, use
FINFOCUS_HOMEisolation. See Isolating plugins in analyzer mode.
Validation
Section titled “Validation”Eager Validation (Before Deployment)
Section titled “Eager Validation (Before Deployment)”Validate your routing configuration before using it:
finfocus config validate
# Success output:✓ Configuration valid
Discovered plugins: aws-ce: Recommendations, ActualCosts (priority: 20) aws-public: ProjectedCosts (priority: 10)
Routing rules: aws:eks:* → eks-costs (pattern, priority: 30) aws:* → aws-public (provider, priority: 10)
# Error output:✗ Configuration invalid
Errors: - aws-ce: plugin not found (install with: finfocus plugin install aws-ce) - patterns[0].pattern: invalid regex: missing closing bracket
Warnings: - aws-public: feature 'Carbon' not supported by pluginLazy Validation (At Runtime)
Section titled “Lazy Validation (At Runtime)”Validation happens automatically on first use. Invalid patterns are skipped with warnings logged.
Debugging Routing Decisions
Section titled “Debugging Routing Decisions”Enable Debug Logging
Section titled “Enable Debug Logging”See exactly which plugin was selected and why:
# Via flagfinfocus cost projected --debug --pulumi-json plan.json
# Via environmentexport FINFOCUS_LOG_LEVEL=debugfinfocus cost projected --pulumi-json plan.json
# Example debug output:DBG plugin routing decision resource_type=aws:ec2/instance:Instance provider=aws matched_plugins=[aws-public] selected_plugin=aws-public priority=10 reason=providerDBG plugin routing decision resource_type=aws:eks:Cluster provider=aws matched_plugins=[eks-costs, aws-public] selected_plugin=eks-costs priority=30 reason=patternView Plugin Capabilities
Section titled “View Plugin Capabilities”Check what each plugin supports:
finfocus plugin list --verbose
# Output:NAME VERSION PROVIDERS CAPABILITIES STATUSaws-public 1.0.0 aws ProjectedCosts, ActualCosts healthyaws-ce 1.0.0 aws Recommendations, ActualCosts healthygcp-public 1.0.0 gcp ProjectedCosts, ActualCosts healthyTroubleshooting
Section titled “Troubleshooting”Plugin Not Receiving Requests
Section titled “Plugin Not Receiving Requests”Symptoms: Plugin installed but never queried.
Solutions:
-
Check plugin is installed:
Terminal window finfocus plugin list -
Verify plugin reports correct providers:
Terminal window finfocus plugin list --verbose -
Check routing configuration:
Terminal window finfocus config validate -
Enable debug logging:
Terminal window finfocus cost projected --debug --pulumi-json plan.json
Fallback Not Working
Section titled “Fallback Not Working”Symptoms: Primary plugin fails but fallback doesn’t trigger.
Solutions:
-
Verify
fallback: truein config (default):- name: primary-pluginfallback: true # Must be true -
Check plugin is actually failing (not returning $0):
Terminal window finfocus cost projected --debug --pulumi-json plan.jsonLook for
ERRorWARNlogs indicating failure. -
Review fallback trigger reason:
Terminal window finfocus cost projected --debug --pulumi-json plan.json# Look for: "plugin failed, trying fallback"
Pattern Not Matching
Section titled “Pattern Not Matching”Symptoms: Resource pattern doesn’t route to expected plugin.
Solutions:
-
Validate pattern syntax:
Terminal window finfocus config validate -
For regex, ensure RE2 syntax (no backreferences):
# CORRECT (RE2 syntax)- type: regexpattern: 'aws:(ec2|rds)/.*'# INCORRECT (backreferences not supported)- type: regexpattern: "aws:(\\w+)/\\1" # \1 backreference fails -
For glob, use
*not**(single-level matching):# CORRECT- type: globpattern: 'aws:eks:*'# INCORRECT (** not supported by filepath.Match)- type: globpattern: 'aws:eks:**' -
Enable debug logging to see pattern matching:
Terminal window finfocus cost projected --debug --pulumi-json plan.json# Look for: "pattern match" events at TRACE level
All Plugins Failing
Section titled “All Plugins Failing”Symptoms: All plugins fail, falling back to specs or “no cost data”.
Solutions:
-
Check plugin health:
Terminal window finfocus plugin list --verbose -
Verify plugin logs for errors:
Terminal window # Check logs in ~/.finfocus/logs/ if logging enabled -
Test individual plugin:
Terminal window finfocus plugin inspect <plugin-name> <resource-type> -
Check network connectivity (for cloud API plugins).
Performance Considerations
Section titled “Performance Considerations”Routing Overhead
Section titled “Routing Overhead”Routing decisions are designed to be fast:
- Provider extraction: ~10ns per resource (simple string split)
- Glob pattern match: ~100ns per resource (filepath.Match)
- Regex pattern match: ~200ns per resource (compiled regex cache)
- Priority sorting: ~O(n log n) where n = matching plugins
Target: <10ms routing overhead per request (SC-002)
Typical: 100-200 microseconds for 10 patterns × 100 resources
Pattern Cache
Section titled “Pattern Cache”Regex patterns are compiled once at config load and cached:
// Compiled at config loadregex, err := regexp.Compile(pattern)
// Cached for subsequent matchescached[pattern] = regexBenefit: Avoids recompilation on each resource evaluation.
Migration from All-Plugin Querying
Section titled “Migration from All-Plugin Querying”Legacy Behavior (Pre-v0.3.0)
Section titled “Legacy Behavior (Pre-v0.3.0)”Before multi-plugin routing, FinFocus queried ALL plugins for ALL resources:
# Old behavior: queries aws-public, gcp-public, recorder for EVERY resourcefinfocus cost projected --pulumi-json plan.jsonNew Behavior (v0.3.0+)
Section titled “New Behavior (v0.3.0+)”With routing, only matching plugins are queried:
# New behavior: queries only matching pluginsfinfocus cost projected --pulumi-json plan.json# aws:ec2:Instance → queries only aws-public# gcp:compute:Instance → queries only gcp-publicBackward Compatibility
Section titled “Backward Compatibility”No configuration: Automatic provider-based routing (backward compatible).
Existing configs: Routing is additive - configs without routing: key work unchanged.
# Legacy config (still works)plugins: aws-public: region: us-east-1# No routing config = automatic routing based on providersAdvanced Topics
Section titled “Advanced Topics”Global Plugins (Wildcard Providers)
Section titled “Global Plugins (Wildcard Providers)”Plugins reporting ["*"] or empty providers match ALL resources:
# Example: recorder plugin for debuggingrouting: plugins: - name: recorder priority: 0 # Query alongside other pluginsUse Cases:
- Debugging/logging plugins
- Audit/compliance plugins
- Testing/validation plugins
Equal Priority Behavior
Section titled “Equal Priority Behavior”When multiple plugins have the same priority, ALL are queried in parallel:
routing: plugins: - name: aws-public priority: 10 - name: aws-ce priority: 10 # Same priorityResult: Both aws-public and aws-ce queried concurrently, results merged.
Source Attribution
Section titled “Source Attribution”Results include which plugin provided the data:
{ "resource": "aws:ec2/instance:Instance", "monthlyCost": 375.0, "source": "aws-public", // Attribution field "currency": "USD"}Use Cases:
- Debugging which plugin responded
- Comparing results from multiple plugins
- Audit trails for cost data sources
Best Practices
Section titled “Best Practices”-
Start Simple: Begin with automatic routing (zero config), add declarative rules only when needed.
-
Validate Early: Run
finfocus config validatebefore deploying routing changes. -
Use Priorities: Assign clear priority ordering to avoid ambiguity.
-
Enable Fallback: Keep
fallback: true(default) for resilience. -
Debug Liberally: Use
--debugflag to understand routing decisions. -
Pattern Specificity: Make patterns as specific as needed - general patterns can cause unexpected routing.
-
Monitor Performance: Ensure routing overhead stays <10ms per request.
Related Documentation
Section titled “Related Documentation”- Plugin Development Guide - How to build plugins with routing support
- CLI Commands Reference - All CLI commands with routing options
- Configuration Schema - Complete config.yaml schema
- Architecture Overview - How routing fits in the system
Changelog
Section titled “Changelog”- v0.3.1: Documented analyzer/policy-pack mode limitations
- Routing configuration is not applied when running as a Pulumi policy pack
- Global plugins (
supported_providers: ["*"]) cannot be excluded via routing - Added
FINFOCUS_HOMEisolation procedure in Analyzer Integration docs
- v0.3.0: Initial multi-plugin routing release
- Automatic provider-based routing
- Declarative pattern/feature/priority configuration
- Validation command and debug logging