public/SKILLS/Infrastructure & Cloud/provider-actions/SKILL.md
Implement Terraform Provider actions using the Plugin Framework. Use when developing imperative operations that execute at lifecycle events (before/after create, update, destroy).
npx skillsauth add eric861129/skills_all-in-one provider-actionsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
4 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Terraform Actions enable imperative operations during the Terraform lifecycle. Actions are experimental features that allow performing provider operations at specific lifecycle events (before/after create, update, destroy).
References:
Actions follow the standard service package structure:
internal/service/<service>/
├── <action_name>_action.go # Action implementation
├── <action_name>_action_test.go # Action tests
└── service_package_gen.go # Auto-generated service registration
Documentation structure:
website/docs/actions/
└── <service>_<action_name>.html.markdown # User-facing documentation
Changelog entry:
.changelog/
└── <pr_number_or_description>.txt # Release note entry
Actions use the Terraform Plugin Framework with a standard schema pattern:
func (a *actionType) Schema(ctx context.Context, req action.SchemaRequest, resp *action.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
// Required configuration parameters
"resource_id": schema.StringAttribute{
Required: true,
Description: "ID of the resource to operate on",
},
// Optional parameters with defaults
"timeout": schema.Int64Attribute{
Optional: true,
Description: "Operation timeout in seconds",
Default: int64default.StaticInt64(1800),
Computed: true,
},
},
}
}
Pay special attention to the schema definition - common issues after a first draft:
Type Mismatches
types.String instead of fwtypes.String in model structstypes.StringType instead of fwtypes.StringType in schemaList/Map Element Types
// WRONG - missing ElementType
"items": schema.ListAttribute{
Optional: true,
}
// CORRECT
"items": schema.ListAttribute{
Optional: true,
ElementType: fwtypes.StringType,
}
Computed vs Optional
Optional: true and Computed: trueComputed unless they have defaultsValidator Imports
// Ensure proper imports
"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
Region/Provider Attribute
Nested Attributes
Before submitting, verify:
go build to catch type mismatchesThe Invoke method contains the action logic:
func (a *actionType) Invoke(ctx context.Context, req action.InvokeRequest, resp *action.InvokeResponse) {
var data actionModel
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
// Create provider client
conn := a.Meta().Client(ctx)
// Progress updates for long-running operations
resp.Progress.Set(ctx, "Starting operation...")
// Implement action logic with error handling
// Use context for timeout management
// Poll for completion if async operation
resp.Progress.Set(ctx, "Operation completed")
}
resp.SendProgress(action.InvokeProgressEvent{...}) for real-time updatescontext.WithTimeout() for API callsresp.Diagnostics.AddError()Example error handling:
// Handle specific errors
var notFound *types.ResourceNotFoundException
if errors.As(err, ¬Found) {
resp.Diagnostics.AddError(
"Resource Not Found",
fmt.Sprintf("Resource %s was not found", resourceID),
)
return
}
// Generic error handling
resp.Diagnostics.AddError(
"Operation Failed",
fmt.Sprintf("Could not complete operation for %s: %s", resourceID, err),
)
a.Meta().<Service>Client(ctx)For operations that require waiting for completion:
result, err := wait.WaitForStatus(ctx,
func(ctx context.Context) (wait.FetchResult[*ResourceType], error) {
// Fetch current status
resource, err := findResource(ctx, conn, id)
if err != nil {
return wait.FetchResult[*ResourceType]{}, err
}
return wait.FetchResult[*ResourceType]{
Status: wait.Status(resource.Status),
Value: resource,
}, nil
},
wait.Options[*ResourceType]{
Timeout: timeout,
Interval: wait.FixedInterval(5 * time.Second),
SuccessStates: []wait.Status{"AVAILABLE", "COMPLETED"},
TransitionalStates: []wait.Status{"CREATING", "PENDING"},
ProgressInterval: 30 * time.Second,
ProgressSink: func(fr wait.FetchResult[any], meta wait.ProgressMeta) {
resp.SendProgress(action.InvokeProgressEvent{
Message: fmt.Sprintf("Status: %s, Elapsed: %v", fr.Status, meta.Elapsed.Round(time.Second)),
})
},
},
)
Actions are invoked via action_trigger lifecycle blocks in Terraform configurations:
action "provider_service_action" "name" {
config {
parameter = value
}
}
resource "terraform_data" "trigger" {
lifecycle {
action_trigger {
events = [after_create]
actions = [action.provider_service_action.name]
}
}
}
Terraform 1.14.0 Supported Events:
before_create - Before resource creationafter_create - After resource creationbefore_update - Before resource updateafter_update - After resource updateNot Supported in Terraform 1.14.0:
before_destroy - Not available (will cause validation error)after_destroy - Not available (will cause validation error)func TestAccServiceAction_basic(t *testing.T) {
ctx := acctest.Context(t)
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
tfversion.SkipBelow(tfversion.Version1_14_0),
},
Steps: []resource.TestStep{
{
Config: testAccActionConfig_basic(),
Check: resource.ComposeTestCheckFunc(
testAccCheckResourceExists(ctx, "provider_resource.test"),
),
},
},
})
}
Add sweep functions to clean up test resources:
func sweepResources(region string) error {
ctx := context.Background()
client := /* get client for region */
input := &service.ListInput{
// Filter for test resources
}
var sweeperErrs *multierror.Error
pages := service.NewListPaginator(client, input)
for pages.HasMorePages() {
page, err := pages.NextPage(ctx)
if err != nil {
sweeperErrs = multierror.Append(sweeperErrs, err)
continue
}
for _, item := range page.Items {
id := item.Id
// Skip non-test resources
if !strings.HasPrefix(id, "tf-acc-test") {
continue
}
_, err := client.Delete(ctx, &service.DeleteInput{
Id: id,
})
if err != nil {
sweeperErrs = multierror.Append(sweeperErrs, err)
}
}
}
return sweeperErrs.ErrorOrNil()
}
Service-Specific Prerequisites
Error Pattern Matching
regexache.MustCompile(\(?s)Error Title.*key phrase`)`Test Patterns Not Applicable to Actions
Compile test to check for errors:
go test -c -o /dev/null ./internal/service/<service>
Run specific action tests:
TF_ACC=1 go test ./internal/service/<service> -run TestAccServiceAction_ -v
Run sweep to clean up test resources:
TF_ACC=1 go test ./internal/service/<service> -sweep=<region> -v
Each action documentation file must include:
Front Matter
---
subcategory: "Service Name"
layout: "provider"
page_title: "Provider: provider_service_action"
description: |-
Brief description of what the action does.
---
Header with Warnings
Example Usage
terraform_dataArgument Reference
Documentation Linting
terrafmt fmt before submissionterrafmt diffCreate a changelog entry in .changelog/ directory:
.changelog/<pr_number_or_description>.txt
Content format:
action/provider_service_action: Brief description of the action
Before submitting your action implementation:
go build -o /dev/null .go test -c -o /dev/null ./internal/service/<service>make fmtterrafmt fmt website/docs/actions/<action>.html.markdowndevelopment
Run structured What-If scenario analysis with multi-branch possibility exploration. Use this skill when the user asks speculative questions like "what if...", "what would happen if...", "what are the possibilities", "explore scenarios", "scenario analysis", "possibility space", "what could go wrong", "best case / worst case", "risk analysis", "contingency planning", "strategic options", or any question about uncertain futures. Also trigger when the user faces a fork-in-the-road decision, wants to stress-test an idea, or needs to think through consequences before committing.
development
Access comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
development
Use when challenging ideas, plans, decisions, or proposals using structured critical reasoning. Invoke to play devil's advocate, run a pre-mortem, red team, or audit evidence and assumptions.
tools
Core skill for the deep research and writing tool. Write scientific manuscripts in full paragraphs (never bullet points). Use two-stage process with (1) section outlines with key points using research-lookup then (2) convert to flowing prose. IMRAD structure, citations (APA/AMA/Vancouver), figures/tables, reporting guidelines (CONSORT/STROBE/PRISMA), for research papers and journal submissions.