Skip to content

Resource Lifecycle API Reference

Complete API reference for resource lifecycle methods and the ResourceContext object.

๐Ÿค– 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.


Base Resource Class

from pyvider.resources import BaseResource

Class Attributes

Attribute Type Required Description
config_class Type[attrs.define] Yes Configuration attrs class
state_class Type[attrs.define] Yes State attrs class

Lifecycle Methods

Required Methods

read()

async def read(self, ctx: ResourceContext) -> StateType | None:
    """Refresh state from remote system."""

Purpose: Check if the resource still exists and return its current state.

Parameters: - ctx: ResourceContext with current state

Returns: - StateType: Current state if resource exists - None: Resource no longer exists (deleted outside Terraform)

When Called: During terraform plan and terraform refresh

Example:

async def read(self, ctx: ResourceContext) -> ServerState | None:
    if not ctx.state:
        return None

    try:
        server = await api.get_server(ctx.state.id)
        return ServerState(
            id=server["id"],
            name=server["name"],
            status=server["status"],
        )
    except NotFoundError:
        return None  # Server deleted


_delete_apply()

async def _delete_apply(self, ctx: ResourceContext) -> None:
    """Delete the resource."""

Purpose: Remove the resource from the remote system.

Parameters: - ctx: ResourceContext with current state

Returns: None

When Called: During terraform destroy or when resource removed from config

Example:

async def _delete_apply(self, ctx: ResourceContext) -> None:
    if not ctx.state:
        return

    await api.delete_server(ctx.state.id)


Optional Methods

_create_apply()

async def _create_apply(
    self,
    ctx: ResourceContext
) -> tuple[StateType | None, PrivateData | None]:
    """Create the resource."""

Purpose: Create a new resource.

Parameters: - ctx: ResourceContext with configuration

Returns: - Tuple of (state, private_data) - state: New state to track - private_data: Sensitive data (not in state file)

When Called: During terraform apply when creating new resource

Default Behavior: Calls _update_apply() if not overridden

Example:

async def _create_apply(self, ctx: ResourceContext) -> tuple[ServerState | None, None]:
    if not ctx.config:
        return None, None

    server = await api.create_server(
        name=ctx.config.name,
        size=ctx.config.size,
    )

    return ServerState(
        id=server["id"],
        name=server["name"],
        size=server["size"],
        status=server["status"],
    ), None


_update_apply()

async def _update_apply(
    self,
    ctx: ResourceContext
) -> tuple[StateType | None, PrivateData | None]:
    """Update the resource."""

Purpose: Modify an existing resource.

Parameters: - ctx: ResourceContext with configuration and current state

Returns: - Tuple of (state, private_data) - state: Updated state - private_data: Sensitive data (not in state file)

When Called: During terraform apply when updating existing resource

Example:

async def _update_apply(self, ctx: ResourceContext) -> tuple[ServerState | None, None]:
    if not ctx.config or not ctx.state:
        return None, None

    server = await api.update_server(
        id=ctx.state.id,
        name=ctx.config.name,
        size=ctx.config.size,
    )

    return ServerState(
        id=ctx.state.id,
        name=server["name"],
        size=server["size"],
        status=server["status"],
    ), None


_validate_config()

async def _validate_config(self, config: ConfigType) -> list[str]:
    """Validate configuration."""

Purpose: Validate user configuration before applying.

Parameters: - config: Typed configuration object

Returns: - List of error messages (empty list = valid)

When Called: During terraform plan and terraform apply

Example:

async def _validate_config(self, config: ServerConfig) -> list[str]:
    errors = []

    if len(config.name) < 3:
        errors.append("Name must be at least 3 characters")

    if config.size not in ["small", "medium", "large"]:
        errors.append("Size must be small, medium, or large")

    return errors


ResourceContext API

Properties

config

ctx.config: ConfigType | None

Typed configuration attrs instance. None if configuration contains unknown values.

Example:

if ctx.config:
    print(f"Server name: {ctx.config.name}")


config_cty

ctx.config_cty: CtyValue

Raw CTY value from Terraform, always available even with unknown values.

Example:

raw_value = ctx.config_cty


state

ctx.state: StateType | None

Current state. None during create operations.

Example:

if ctx.state:
    existing_id = ctx.state.id


planned_state

ctx.planned_state: StateType | None

Planned state from plan phase.

Example:

planned_name = ctx.planned_state.name if ctx.planned_state else None


Methods

is_field_unknown()

ctx.is_field_unknown(field_name: str) -> bool

Check if a configuration field has an unknown value (e.g., depends on another resource).

Parameters: - field_name: Name of the configuration field

Returns: True if value is unknown

Example:

if ctx.is_field_unknown("api_key"):
    # Can't create yet, api_key not known
    return None, None


add_error()

ctx.add_error(message: str) -> None

Add an error diagnostic to show in Terraform output.

Parameters: - message: Error message

Example:

ctx.add_error("Failed to create server: API returned 500")


add_warning()

ctx.add_warning(message: str) -> None

Add a warning diagnostic to show in Terraform output.

Parameters: - message: Warning message

Example:

ctx.add_warning("This configuration is deprecated, use new_config instead")


Schema Definition

get_schema()

@classmethod
def get_schema(cls) -> PvsSchema:
    """Define Terraform schema."""

Returns: PvsSchema object defining the resource schema

Example:

from pyvider.schema import s_resource, a_str, a_num, a_bool

@classmethod
def get_schema(cls) -> PvsSchema:
    return s_resource({
        # User inputs
        "name": a_str(required=True, description="Server name"),
        "size": a_str(default="small", description="Server size"),
        "enabled": a_bool(default=True, description="Enabled status"),

        # Provider outputs
        "id": a_str(computed=True, description="Server ID"),
        "status": a_str(computed=True, description="Server status"),
        "created_at": a_num(computed=True, description="Creation timestamp"),
    })


Type Signatures

Configuration Class

import attrs

@attrs.define
class ServerConfig:
    """User-provided configuration."""
    name: str
    size: str = "small"
    enabled: bool = True

State Class

import attrs

@attrs.define
class ServerState:
    """Provider-managed state."""
    id: str
    name: str
    size: str
    enabled: bool
    status: str
    created_at: int

Private Data

Sensitive data that shouldn't be stored in state:

async def _create_apply(self, ctx: ResourceContext) -> tuple[State, dict]:
    server = await api.create_server(...)

    state = ServerState(
        id=server["id"],
        name=server["name"],
    )

    private_data = {
        "api_key": server["api_key"],  # Not in state
        "password": server["password"],  # Not in state
    }

    return state, private_data

Access private data:

async def _update_apply(self, ctx: ResourceContext):
    if hasattr(ctx, "private"):
        api_key = ctx.private.get("api_key")


Lifecycle Sequence

Create Resource

  1. User adds resource to Terraform config
  2. terraform plan:
  3. Calls _validate_config() with configuration
  4. Calls get_schema() to validate schema
  5. terraform apply:
  6. Calls _create_apply() with ctx.config
  7. Stores returned state

Update Resource

  1. User modifies resource in Terraform config
  2. terraform plan:
  3. Calls read() to get current state
  4. Calls _validate_config() with new configuration
  5. Compares current state with planned state
  6. terraform apply:
  7. Calls _update_apply() with ctx.config and ctx.state
  8. Stores returned state

Delete Resource

  1. User removes resource from Terraform config
  2. terraform plan:
  3. Shows resource will be deleted
  4. terraform apply:
  5. Calls _delete_apply() with ctx.state
  6. Removes resource from state

Refresh State

  1. terraform refresh or terraform plan:
  2. Calls read() with ctx.state
  3. Updates state if changed
  4. Removes from state if read() returns None

See Also