Skip to content

Frequently Asked Questions (FAQ)

Common questions and answers about Pyvider.

General Questions

What is Pyvider?

Pyvider is a Python framework for building Terraform providers. It implements the Terraform Plugin Protocol v6, allowing you to create infrastructure providers using pure Python instead of Go.

Why use Pyvider instead of the Go SDK?

Use Pyvider when: - You're more comfortable with Python than Go - You want to leverage Python's rich ecosystem (httpx, pydantic, etc.) - Your team already has Python expertise - You're building internal tooling or prototypes - You prefer Python's async/await over Go's goroutines

Use Go SDK when: - You need absolute maximum performance - You're building a high-traffic public provider - Your team has Go expertise - You want the most mature, battle-tested framework

Is Pyvider production-ready?

Pyvider is currently in alpha (v0.0.x). While it implements the full Terraform Plugin Protocol v6 and is well-tested, APIs may change before 1.0. It's best suited for:

  • Internal tooling and automation
  • Rapid prototyping
  • Learning and experimentation
  • Custom providers for specific needs

See the Roadmap for the path to 1.0.

What Python version is required?

Python 3.11 or higher is required. Pyvider uses modern Python features like: - Native async/await - Type hints and | union syntax - Structured pattern matching (in some areas)

Can I use existing Python libraries?

Yes! One of Pyvider's main benefits is access to Python's ecosystem: - HTTP clients: httpx, aiohttp - Cloud SDKs: boto3, azure-sdk, google-cloud - Data: pandas, polars - Utilities: arrow (dates), pydantic (validation)

Just ensure they support async/await if you're using them in async contexts.

Architecture Questions

How does Pyvider work?

Pyvider acts as a bridge between Terraform and your Python code:

  1. Terraform calls your provider via gRPC
  2. Pyvider handles the protocol communication
  3. Your Python code handles the business logic
  4. Pyvider translates responses back to Terraform

See Architecture for details.

What is the Component Hub?

The Component Hub is Pyvider's auto-discovery system. When you use decorators like @register_provider or @register_resource, components automatically register themselves with the hub. Terraform can then discover and use them.

See Component Model.

Do I need to understand the Terraform Plugin Protocol?

No! Pyvider abstracts away the protocol details. You just implement: - Provider configuration - Resource CRUD operations - Data source reads - Function calls

Pyvider handles all the gRPC, message serialization, and protocol compliance.

Development Questions

How do I start building a provider?

Follow these steps:

  1. Read the Quick Start - Build your first provider in 5 minutes
  2. Try the Tutorial - Build a real HTTP API provider
  3. Study Examples - 100+ working examples
  4. Read the Guides - Creating Providers, Creating Resources

What's the difference between a resource and a data source?

Resources manage infrastructure lifecycle (create, update, delete):

@register_resource("server")
class Server(BaseResource):
    async def _create_apply(self, ctx):
        # Create the server
        pass

Data Sources fetch read-only data:

@register_data_source("user")
class User(BaseDataSource):
    async def read(self, ctx):
        # Fetch user data
        pass

See Core Concepts.

How do I handle secrets and credentials?

  1. Mark as sensitive in schema:

    "api_key": a_str(required=True, sensitive=True)
    

  2. Use private state for encrypted storage:

    return state, {"password": db.password}  # Encrypted
    

  3. Never hardcode secrets in code

  4. Never log sensitive data

See Security Best Practices.

How do I test my provider?

Use pytest with async support:

import pytest

@pytest.mark.asyncio
async def test_resource_create():
    resource = MyResource()
    ctx = ResourceContext(config=MyConfig(...))
    state, _ = await resource._create_apply(ctx)
    assert state.id

See Testing Providers.

How do I debug my provider?

Enable debug logging:

export TF_LOG=DEBUG
export PYVIDER_LOG_LEVEL=DEBUG
terraform apply

Use the Python debugger:

import pdb; pdb.set_trace()
# Or use breakpoint()

See Debugging Guide.

Schema Questions

What are the available attribute types?

Pyvider provides comprehensive type support:

  • Primitives: a_str(), a_num(), a_bool()
  • Collections: a_list(), a_map(), a_set()
  • Complex: a_obj(), a_tuple()
  • Special: a_dyn() (any type)

See Schema Types.

How do I make an attribute required?

"name": a_str(required=True)

How do I add a default value?

"size": a_str(default="medium")

How do I make an attribute computed?

"id": a_str(computed=True)  # Provider sets this

How do I validate attribute values?

Use validators:

"port": a_num(
    validators=[
        lambda x: 1 <= x <= 65535 or "Invalid port",
    ]
)

See Schema Validators.

Can I have nested blocks?

Yes! Use block factories:

schema = s_resource({
    "name": a_str(required=True),
    "config": b_single("config"),  # Single nested block
    "rule": b_list("rule"),         # Multiple blocks
})

See Schema Blocks.

Performance Questions

Is Python fast enough for a Terraform provider?

Yes, for most use cases. Terraform providers are typically I/O bound (API calls, network), not CPU bound. Python's async/await handles I/O efficiently.

Tips for performance: - Use async/await properly - Implement connection pooling - Cache expensive lookups - Batch API calls

See Performance Optimization.

How do I make my provider faster?

  1. Use async properly - Never block the event loop
  2. Cache data - Cache expensive API calls
  3. Batch operations - Avoid N+1 queries
  4. Connection pooling - Reuse HTTP connections
  5. Profile - Use py-spy to find bottlenecks

See Performance Optimization.

Should I use caching?

Cache data that: - Changes infrequently (region info, image catalogs) - Is expensive to fetch - Is accessed multiple times

Don't cache: - Resource state (must be fresh) - User credentials - Frequently changing data

Deployment Questions

How do I distribute my provider?

Options:

  1. Development - Use pyvider install for local testing
  2. Internal - Package with Flavor and distribute binary
  3. Public - Publish to Terraform Registry (after 1.0)

See Installation Guide.

Does my provider need to be compiled?

No! Pyvider providers run as Python scripts. However, you can package them into standalone binaries using Flavor for easier distribution.

Can I publish to the Terraform Registry?

Not yet. Public registry support is planned for post-1.0. For now, use: - Local dev provider file - Private distribution - Internal package repository

Troubleshooting

Why isn't Terraform finding my provider?

Check: 1. Provider is installed (pyvider install) 2. Terraform is initialized (terraform init) 3. Provider name matches in Terraform config 4. Provider is in the correct directory

See Troubleshooting.

Why isn't my resource updating?

Ensure you implemented _update_apply():

async def _update_apply(self, ctx):
    # Actually update the resource
    await self.api.update_resource(ctx.state.id, ctx.config)
    return updated_state, None

See Troubleshooting.

Why isn't drift being detected?

Implement read() correctly - it must fetch current state, not return cached state:

async def read(self, ctx):
    # Fetch CURRENT state from API
    current = await self.api.get_resource(ctx.state.id)
    return State(**current)  # Return current, not ctx.state!

See Troubleshooting.

Why is my provider crashing?

Common causes: 1. Unhandled exceptions 2. Blocking I/O in async code 3. Missing await on async calls 4. Type mismatches

Enable debug logging and check for stack traces:

export TF_LOG=DEBUG
export PYVIDER_LOG_LEVEL=DEBUG
terraform apply 2>&1 | tee debug.log

See Troubleshooting.

Advanced Questions

Can I use capabilities?

Capabilities are experimental. For production, use: - Inheritance (base classes) - Composition (helper classes) - Utility modules

See Capabilities Overview.

How do I handle provider-specific state?

Use instance variables in your provider:

@register_provider("mycloud")
class MyCloudProvider(BaseProvider):
    async def configure(self, config):
        await super().configure(config)
        self.api_client = APIClient(config["api_key"])
        self.cache = {}

Resources can access the provider via the hub:

from pyvider.hub import hub
provider = hub.get_component("singleton", "provider")
await provider.api_client.create(...)

Can I have multiple providers in one package?

Yes! Register multiple providers:

@register_provider("aws")
class AWSProvider(BaseProvider):
    pass

@register_provider("gcp")
class GCPProvider(BaseProvider):
    pass

Each will be available as a separate Terraform provider.

How do I handle pagination?

Fetch all pages before returning:

async def read(self, ctx):
    all_items = []
    page_token = None

    while True:
        response = await provider.api.list_items(
            page_token=page_token,
            page_size=100
        )

        all_items.extend(response.items)

        if not response.next_page_token:
            break

        page_token = response.next_page_token

    return ItemsData(items=all_items, count=len(all_items))

How do I implement resource timeouts?

Use asyncio.wait_for:

import asyncio

async def _create_apply(self, ctx):
    try:
        # Timeout after 5 minutes
        result = await asyncio.wait_for(
            self.api.create_resource(ctx.config),
            timeout=300
        )
        return State(**result), None

    except asyncio.TimeoutError:
        raise ResourceError("Resource creation timed out after 5 minutes")

Getting Help

Where can I get help?

How do I report a bug?

Open an issue with: - Clear description - Steps to reproduce - Environment details (Pyvider version, Python version, OS) - Relevant logs

See Contributing Guidelines.

How can I contribute?

We welcome contributions!

  1. Read Contributing Guidelines
  2. Find a good first issue
  3. Submit a pull request

Additional Resources


Don't see your question? Ask in GitHub Discussions!