logo
HomeWorkBlog

Terraform Actions with Ansible Automation Platform

Terraform continues to evolve beyond plan/apply into an event-driven workflow engine. With Terraform Actions, we can declaratively bind provider-specific actions to lifecycle events like after_create and after_update. In this post, I'll cover what Terraform Actions are and introduce the new AAP provider features. Released in v1.4.0, aap_job_launch can trigger job templates, and coming in a future release, aap_workflow_job_launch, will trigger workflow job templates directly from Terraform.

What are Terraform Actions?

Terraform Actions let you register operations that run when resources change state. This allows clean orchestration patterns: provision infrastructure first, then call downstream APIs to perform post-provision configuration, registrations, or notifications.

sequenceDiagram
    participant TF as Terraform
    participant Prov as Provider Action
    participant AAP as AAP
    participant Infra as Cloud Resource

    TF->>Infra: Create resource (apply)
    TF->>Prov: Lifecycle event: after_create
    Prov->>AAP: Launch Job/Workflow
    AAP-->>Prov: Job ID / Workflow ID
    loop Poll until final state
        Prov->>AAP: Get status
        AAP-->>Prov: running | successful | failed
    end
    Prov-->>TF: Completion (success/failure)

Why pair Terraform with AAP?

AAP centralizes automation with RBAC, audit trails, execution environments, and logging. Many teams want infrastructure to be provisioned by Terraform, then configured by Ansible. Actions provide a clean bridge: Terraform creates infrastructure; AAP performs the operational configuration.

New AAP Actions

Along with the maintainers, I contributed two new actions:

Trigger a notification for host creation

Bind an AAP job to the instance's after_create event and pass instance attributes into extra_vars. The extra_vars parameter allows you to pass dynamic data from your Terraform resources to your Ansible playbooks, enabling your playbooks to access infrastructure details like instance IDs, IP addresses, and other resource attributes.

terraform {
  required_providers {
    aap = {
      source = "ansible/aap"
    }
  }
}

provider "aap" {
  host  = "https://myaap.example.com"
  token = "aap-token" # or set AAP_TOKEN
}

action "aap_job_launch" "notify_host_creation" {
  config {
    job_template_id = var.notification_job
    extra_vars = jsonencode({
      instance_id    = aws_instance.web.id
      private_ip     = aws_instance.web.private_ip
    })
    wait_for_completion                 = true
    wait_for_completion_timeout_seconds = 300
  }
}

resource "aws_instance" "web" {
  ami           = "ami-02029c87fa31fb148"
  instance_type = "t3.micro"
  subnet_id     = "subnet-0b6f49a6b1e635b18"
  lifecycle {
    action_trigger {
      events  = [after_create]
      actions = [action.aap_job_launch.notify_host_creation]
    }
  }
}

AAP UI Showing Actions

Workflow Based Configuration

Alternatively, after the instance is provisioned, you can trigger an Ansible Automation Platform (AAP) Workflow Job to apply multiple tasks such as applying final security settings, registering the instance with monitoring tools, or deploying application-specific dependencies. Workflows are ideal when you need to orchestrate multiple job templates in sequence or parallel.

action "aap_workflow_job_launch" "last_mile" {
  config {
    workflow_job_template_id = var.workflow_template_id
    extra_vars = jsonencode({
      instance_id     = aws_instance.web.id
      monitoring_tier = "production"
    })
    wait_for_completion                 = true
    wait_for_completion_timeout_seconds = 900
  }
}

resource "aws_instance" "web" {
  ami           = "ami-0123456789abcdef0"
  instance_type = "t3.micro"
  lifecycle {
    action_trigger {
      events  = [after_create]
      actions = [action.aap_workflow_job_launch.last_mile]
    }
  }
}

Utilization Tips

  • Inventory scoping: Set inventory_id or encode target selection in extra_vars consumed by your templates. This allows your playbooks to dynamically target the newly created infrastructure.

  • Fire-and-forget notifications: Set wait_for_completion = false to launch jobs asynchronously without blocking Terraform execution. For notifications that shouldn't block your apply, this prevents timeouts on long-running jobs.

  • Error handling: When wait_for_completion = true, failed jobs will cause Terraform to fail. Use ignore_job_results = true if you want Terraform to proceed even if the job fails (useful for non-critical notifications).

  • Choosing jobs vs workflows: Use aap_job_launch for single playbook execution. Use aap_workflow_job_launch when you need to orchestrate multiple job templates, handle conditional logic, or run tasks in parallel.