For what seems like forever now, every Terraform repo has carried a stray shell step: a cache purge after deploy, a webhook ping, an Ansible playbook to finish configuration and while useful, ultimately grafted on with provisioners or CI glue that Terraform can’t see. Actions give those steps a much needed home: provider defined operations you can declare in HCL and invoke on demand or at specific lifecycle moments. They’re purpose-built for “make something happen” without pretending to be resources.
Think of your terraform operations in three layers:
action "webhook_post" "deploy_notice" {
config {
url = var.slack_webhook_url
message = "New app version deployed to ${var.env}"
}
}
action "ansible_playbook" "configure_vm" {
config {
playbook_path = "${path.module}/playbooks/app.yml"
host = azurerm_linux_virtual_machine.app.public_ip_address
ssh_public_key = azurerm_ssh_public_key.app.public_key
}
}
resource "azurerm_linux_virtual_machine" "app" {
# ...vm config...
lifecycle {
action_trigger {
events = [after_create, after_update]
actions = [
action.ansible_playbook.configure_vm,
action.webhook_post.deploy_notice
]
condition = var.enable_post_deploy_actions
}
}
}
In certain situations, if you would like to just run an action you can use the new -invoke flag to just invoke one action: terraform apply -invoke action.ansible_playbook.configure_vm just invokes the action that runs the Ansible Playbook