Skip to content

Building Your First Resource

Alpha Status

๐Ÿค– AI-Generated Content

This documentation was generated with AI assistance and is still being audited. Some, or potentially a lot, of this information may be inaccurate. Learn more.

pyvider is in alpha. This tutorial covers **stable** functionality.
See [project status](../#project-status) for details.

Welcome! In this tutorial, you'll build your first Terraform resource using pyvider. By the end, you'll have a working file resource that creates, reads, updates, and deletes local files through Terraform.

What You'll Learn:

  • How resources work in Terraform
  • Creating a resource class with pyvider
  • Defining schemas for user configuration
  • Implementing lifecycle methods (CRUD operations)
  • Testing your resource with Terraform

Time to Complete: 15-20 minutes

Prerequisites:

  • Python 3.11+ installed
  • pyvider installed (installation guide)
  • Basic Python knowledge
  • Basic Terraform knowledge

What is a Resource?

A resource in Terraform represents a piece of infrastructure that can be managed (created, updated, deleted). Think of resources as the things you want to manage:

  • A file on disk
  • A server in the cloud
  • A database record
  • An API object

Resources have a lifecycle:

  1. Create - Make something new
  2. Read - Check current state
  3. Update - Modify existing thing
  4. Delete - Remove it

Terraform handles this lifecycle automatically. You just implement the operations!


Step 1: Create Your Provider Package

First, let's create a simple provider package structure:

mkdir -p my_provider/resources
touch my_provider/__init__.py
touch my_provider/resources/__init__.py
touch my_provider/resources/file.py

Your structure should look like:

my_provider/
โ”œโ”€โ”€ __init__.py
โ””โ”€โ”€ resources/
    โ”œโ”€โ”€ __init__.py
    โ””โ”€โ”€ file.py      # We'll work in this file


Step 2: Define Runtime Types

Open my_provider/resources/file.py and start by defining the data structures.

Resources work with two types of data:

  • Configuration - What the user provides in their Terraform code
  • State - What actually exists (tracked by Terraform)

Let's define these using attrs:


Why separate Config and State?

  • Config = what user wants
  • State = what currently exists
  • Terraform compares them to know when to update

Step 3: Create the Resource Class

Now let's create the resource class itself:


What's happening here?

  • @register_resource("file") - Registers this as a Terraform resource
  • config_class / state_class - Links our attrs classes
  • get_schema() - Defines what users configure in Terraform HCL

Step 4: Implement Read (Check State)

The read() method checks if the resource still exists and returns its current state:


Why return None?

  • None tells Terraform "this resource doesn't exist anymore"
  • Terraform will then know to recreate it

Step 5: Implement Create

The _create_apply() method creates a new file:


Return value explained:

  • First element: New state to track
  • Second element: Private data (advanced, we don't need it)

Step 6: Implement Update

The _update_apply() method modifies an existing file:



Step 7: Implement Delete

The _delete_apply() method removes the file:



Let's add configuration validation to prevent bad inputs:



Complete Code

Here's your complete file.py:



Step 9: Test with Terraform

Create a Terraform configuration file test.tf:

terraform {
  required_providers {
    local = {
      source = "mycompany/local"
    }
  }
}

resource "local_file" "greeting" {
  path    = "hello.txt"
  content = "Hello from Terraform!"
  mode    = "644"
}

output "file_size" {
  value = local_file.greeting.size
}

Run it:

terraform init
terraform plan
terraform apply

You should see:

  • terraform plan shows the file will be created
  • terraform apply creates hello.txt
  • The output shows the file size

Try modifying the content and running terraform apply again to see updates!


What You've Learned

Congratulations! You've built your first pyvider resource. You now understand:

โœ… Resource Lifecycle - Create, read, update, delete operations โœ… Schema Definition - Defining what users configure โœ… Runtime Types - Separating config from state โœ… Validation - Preventing bad configurations โœ… Testing - Using Terraform to test your resource


Next Steps

Now that you understand the basics, explore:


Troubleshooting

Q: My resource isn't being registered

Make sure you're calling register_resource() as a decorator and importing the module.

Q: Validation errors aren't showing

Check that _validate_config() is async and returns a list of strings.

Q: State isn't being tracked

Ensure you're returning FileState objects from _create_apply() and _update_apply().

For more help, see Troubleshooting Guide.