Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions examples/workspace_resources.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
"""Example script for working with workspace resources in Terraform Enterprise.

This script demonstrates how to list resources within a workspace.
"""

import argparse
import sys

from pytfe import TFEClient
from pytfe.models import WorkspaceResourceListOptions


def list_workspace_resources(
client: TFEClient,
workspace_id: str,
page_number: int | None = None,
page_size: int | None = None,
) -> None:
"""List all resources in a workspace."""
try:
print(f"Listing resources for workspace: {workspace_id}")

# Prepare list options
options = None
if page_number or page_size:
options = WorkspaceResourceListOptions()
if page_number:
options.page_number = page_number
if page_size:
options.page_size = page_size

# List workspace resources (returns an iterator)
resources = list(client.workspace_resources.list(workspace_id, options))

if not resources:
print("No resources found in this workspace.")
return

print(f"\nFound {len(resources)} resource(s):")
print("-" * 80)

for resource in resources:
print(f"ID: {resource.id}")
print(f"Address: {resource.address}")
print(f"Name: {resource.name}")
print(f"Module: {resource.module}")
print(f"Provider: {resource.provider}")
print(f"Provider Type: {resource.provider_type}")
print(f"Created At: {resource.created_at}")
print(f"Updated At: {resource.updated_at}")
print(f"Modified By State Version: {resource.modified_by_state_version_id}")
if resource.name_index:
print(f"Name Index: {resource.name_index}")
print("-" * 80)

except Exception as e:
print(f"Error listing workspace resources: {e}", file=sys.stderr)
sys.exit(1)


def main():
"""Main function to handle command line arguments and execute operations."""
parser = argparse.ArgumentParser(
description="Manage workspace resources in Terraform Enterprise",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
# List all resources in a workspace
python workspace_resources.py --list --workspace-id ws-abc123

# List with pagination
python workspace_resources.py --list --workspace-id ws-abc123 --page-number 2 --page-size 50

Environment variables:
TFE_TOKEN: Your Terraform Enterprise API token
TFE_URL: Your Terraform Enterprise URL (default: https://app.terraform.io)
TFE_ORG: Your Terraform Enterprise organization name
""",
)

# Add command flags
parser.add_argument("--list", action="store_true", help="List workspace resources")
parser.add_argument(
"--workspace-id",
required=True,
help="ID of the workspace (required, e.g., ws-abc123)",
)
parser.add_argument("--page-number", type=int, help="Page number for pagination")
parser.add_argument("--page-size", type=int, help="Page size for pagination")

args = parser.parse_args()

if not args.list:
parser.print_help()
sys.exit(1)

# Initialize TFE client
try:
client = TFEClient()
except Exception as e:
print(f"Error initializing TFE client: {e}", file=sys.stderr)
print(
"Make sure TFE_TOKEN and TFE_URL environment variables are set.",
file=sys.stderr,
)
sys.exit(1)

# Execute the list command
list_workspace_resources(
client,
args.workspace_id,
args.page_number,
args.page_size,
)


if __name__ == "__main__":
main()
2 changes: 2 additions & 0 deletions src/pytfe/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from .resources.state_versions import StateVersions
from .resources.variable import Variables
from .resources.variable_sets import VariableSets, VariableSetVariables
from .resources.workspace_resources import WorkspaceResourcesService
from .resources.workspaces import Workspaces


Expand Down Expand Up @@ -72,6 +73,7 @@ def __init__(self, config: TFEConfig | None = None):
self.variable_sets = VariableSets(self._transport)
self.variable_set_variables = VariableSetVariables(self._transport)
self.workspaces = Workspaces(self._transport)
self.workspace_resources = WorkspaceResourcesService(self._transport)
self.registry_modules = RegistryModules(self._transport)
self.registry_providers = RegistryProviders(self._transport)

Expand Down
9 changes: 9 additions & 0 deletions src/pytfe/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,12 @@
WorkspaceUpdateRemoteStateConsumersOptions,
)

# ── Workspace Resources ───────────────────────────────────────────────────────
from .workspace_resource import (
WorkspaceResource,
WorkspaceResourceListOptions,
)

# ── Public surface ────────────────────────────────────────────────────────────
__all__ = [
# OAuth
Expand Down Expand Up @@ -524,6 +530,9 @@
"WorkspaceTagListOptions",
"WorkspaceUpdateOptions",
"WorkspaceUpdateRemoteStateConsumersOptions",
# Workspace Resources
"WorkspaceResource",
"WorkspaceResourceListOptions",
"RunQueue",
"ReadRunQueueOptions",
# Runs
Expand Down
29 changes: 29 additions & 0 deletions src/pytfe/models/workspace_resource.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""Workspace resources models for Terraform Enterprise."""

from pydantic import BaseModel


class WorkspaceResource(BaseModel):
"""Represents a Terraform Enterprise workspace resource.

These are resources managed by Terraform in a workspace's state.
"""

id: str
address: str
name: str
created_at: str
updated_at: str
module: str
provider: str
provider_type: str
modified_by_state_version_id: str
name_index: str | None = None


class WorkspaceResourceListOptions(BaseModel):
"""Options for listing workspace resources."""

# Pagination
page_number: int | None = None
page_size: int | None = None
66 changes: 66 additions & 0 deletions src/pytfe/resources/workspace_resources.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"""Workspace resources service for Terraform Enterprise."""

from collections.abc import Iterator
from typing import Any

from pytfe.models import (
WorkspaceResource,
WorkspaceResourceListOptions,
)

from ._base import _Service


def _workspace_resource_from(data: dict[str, Any]) -> WorkspaceResource:
"""Convert API response data to WorkspaceResource model."""
attributes = data.get("attributes", {})

return WorkspaceResource(
id=data.get("id", ""),
address=attributes.get("address", ""),
name=attributes.get("name", ""),
created_at=attributes.get("created-at", ""),
updated_at=attributes.get("updated-at", ""),
module=attributes.get("module", ""),
provider=attributes.get("provider", ""),
provider_type=attributes.get("provider-type", ""),
modified_by_state_version_id=attributes.get("modified-by-state-version-id", ""),
name_index=attributes.get("name-index"),
)


class WorkspaceResourcesService(_Service):
"""Service for managing workspace resources in Terraform Enterprise.

Workspace resources represent the infrastructure resources
managed by Terraform in a workspace's state file.
"""

def list(
self, workspace_id: str, options: WorkspaceResourceListOptions | None = None
) -> Iterator[WorkspaceResource]:
"""List workspace resources for a given workspace.

Args:
workspace_id: The ID of the workspace to list resources for
options: Optional query parameters for filtering and pagination

Yields:
WorkspaceResource objects
"""
if not workspace_id or not workspace_id.strip():
raise ValueError("workspace_id is required")

url = f"/api/v2/workspaces/{workspace_id}/resources"

# Handle parameters
params: dict[str, int] = {}
if options:
if options.page_number is not None:
params["page[number]"] = options.page_number
if options.page_size is not None:
params["page[size]"] = options.page_size

# Use the _list method from base service to handle pagination
for item in self._list(url, params=params):
yield _workspace_resource_from(item)
Loading
Loading