-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat request: Ansible Playbook constructs should equal Terraform Template constructs #26
Comments
Workaround, download Terraform Modules from GitHub, add Terraform Provider declaration file and executeThis requires downloading the Terraform Module from GitHub source code instead of the versions released via the Terraform Registry; no difference in the code but not following Terraform best practices. Thereafter each Terraform Module is executed per Ansible Task, and JSON output from Ansible Task for Terraform Module 1 will be passed using Ansible to the Ansible Task for Terraform Module 2. This means individual Terraform state files, and Terraform will be unaware of the relationship between each Terraform Module and unable to resolve dependencies in the future. NOTE: Use static region definition, workaround does not work with variable insertion into AWS Availability Zones due to Ansible Module for Terraform performing incorrect parsing, see Issue #27 ..... Workaround code: ---
- name: "Ansible Playbook"
hosts: localhost
gather_facts: false
vars_prompt:
- name: ansible_var_aws_access_key
prompt: Please enter AWS Access Key
private: no
- name: ansible_var_aws_secret_access_key
prompt: Please enter AWS Secret Access Key
private: yes
- name: ansible_var_aws_region
prompt: Please enter AWS Region
private: no
- name: ansible_var_aws_resources_prefix
prompt: Please enter prefix for AWS resources
private: no
tasks:
- name: Terraform Module for AWS VPC - Git clone
ansible.builtin.git:
repo: 'https://github.com/terraform-aws-modules/terraform-aws-vpc.git'
dest: "{{ playbook_dir }}/tmp/terraform-aws-vpc"
version: master
# Providers within Terraform Modules - https://developer.hashicorp.com/terraform/language/modules/develop/providers
- name: Terraform Module for AWS VPC - Create Terraform providers information inside of each Terraform Module
ansible.builtin.copy:
dest: "{{ playbook_dir }}/tmp/terraform-aws-vpc/tf_provider.tf"
content: |
# Terraform Provider declaration
provider "aws" {
}
- name: Terraform Module for AWS VPC - Terraform init and Terraform apply
register: terraform_result
environment:
AWS_ACCESS_KEY_ID: "{{ ansible_var_aws_access_key }}"
AWS_SECRET_ACCESS_KEY: "{{ ansible_var_aws_secret_access_key }}"
AWS_REGION: "{{ ansible_var_aws_region }}"
cloud.terraform.terraform:
project_path: "{{ playbook_dir }}/tmp/terraform-aws-vpc"
state: present
force_init: true
variables:
name: "{{ ansible_var_aws_resources_prefix }}"
cidr: "10.0.0.0/16"
azs: '["us-west-2a", "us-west-2b", "us-west-2c"]'
private_subnets: '["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]'
public_subnets: '["10.0.11.0/24", "10.0.12.0/24", "10.0.13.0/24"]'
database_subnets: '["10.0.21.0/24", "10.0.22.0/24", "10.0.23.0/24"]'
elasticache_subnets: '["10.0.31.0/24", "10.0.32.0/24", "10.0.33.0/24"]'
redshift_subnets: '["10.0.41.0/24", "10.0.42.0/24", "10.0.43.0/24"]'
intra_subnets: '["10.0.51.0/24", "10.0.52.0/24", "10.0.53.0/24"]'
private_subnet_names: '["Private Subnet One", "Private Subnet Two"]'
database_subnet_names: '["DB Subnet One"]'
elasticache_subnet_names: '["Elasticache Subnet One", "Elasticache Subnet Two"]'
redshift_subnet_names: '["Redshift Subnet One", "Redshift Subnet Two", "Redshift Subnet Three"]'
intra_subnet_names: []
create_database_subnet_group: 'false'
manage_default_network_acl: 'true'
default_network_acl_tags: '{ Name = "{{ ansible_var_aws_resources_prefix }}-default" }'
manage_default_route_table: 'true'
default_route_table_tags: '{ Name = "{{ ansible_var_aws_resources_prefix }}-default" }'
manage_default_security_group: 'true'
default_security_group_tags: '{ Name = "{{ ansible_var_aws_resources_prefix }}-default" }'
enable_dns_hostnames: 'true'
enable_dns_support: 'true'
enable_nat_gateway: 'true'
single_nat_gateway: 'true'
customer_gateways: |
{
IP1 = {
bgp_asn = 65112
ip_address = "1.2.3.4"
device_name = "some_name"
},
IP2 = {
bgp_asn = 65112
ip_address = "5.6.7.8"
}
}
enable_vpn_gateway: 'true'
enable_dhcp_options: 'true'
dhcp_options_domain_name: "service.consul"
dhcp_options_domain_name_servers: '["127.0.0.1", "10.10.0.2"]'
enable_flow_log: 'true'
create_flow_log_cloudwatch_log_group: 'true'
create_flow_log_cloudwatch_iam_role: 'true'
flow_log_max_aggregation_interval: 60 Workaround addendum, Terraform Modules with sensitive outputsBy design, any Terraform Module will include For more information, see documentation: When an Ansible Task attempts to execute a Terraform Module with one of these sensitive output, it will fail with the (expected by design) following Terraform error:
The only crude workaround to this, would be to on-the-fly alter all output declarations for the known Terraform Resource that is creating the error, for example: tasks:
....
....
- name: Terraform Module for AWS VPC - Find any subdirectory
ansible.builtin.find:
paths: "{{ playbook_dir }}/tmp/terraform-aws-vpc"
file_type: directory
register: searched_aws_vpc_module_directories
- name: Terraform Module for AWS VPC - Find all output files
ansible.builtin.find:
paths: "{{ item.path }}/"
patterns: 'outputs.tf'
use_regex: true
file_type: file
register: searched_aws_vpc_module_files_outputs
loop: "{{ searched_aws_vpc_module_directories.files }}"
# Workaround for...
# "To reduce the risk of accidentally exporting sensitive data that was intended to be only internal,
# Terraform requires that any root module output containing sensitive data be explicitly marked as sensitive, to confirm your intent."
- name: Terraform Module for AWS VPC - Workaround for Terraform Outputs that are sensitive
ansible.builtin.shell: awk '$0 ~ /private_key_pem/ { print " " $1 " " $2 " nonsensitive(" $3 ")";getline}1' {{ item.files[0].path }} > $PWD/tmp.tf && mv $PWD/tmp.tf {{ item.files[0].path }}
# ansible.builtin.shell: awk '$0 ~ /private_key_pem/ { print $1;$0=" sensitive = false\n}" }1' {{ item.files[0].path }} > $PWD/tmp.tf && mv $PWD/tmp.tf {{ item.files[0].path }}
loop: "{{ searched_aws_vpc_module_files_outputs.results }}"
when: item.files | length > 0 |
Thanks for your effort on this @sean-freeman. What you are describing is something we considered while scoping out this collection. In the end we deemed it out of scope and stand by that decision. There were a number of reasons contributing to our decision. The focus of this offering was to support users who had existing Terraform plans they wanted to integrate into the Ansible workflows. We modeled this solution to be consistent with how we approach other cloud provisioning tools such as AWS CloudFormation. For doing some dynamic cloud provisioning we recommend using Ansible itself starting with collections such as amazon.aws rather than trying to dynamically generate a valid plan for Terraform and hope it works as intended. We are not retiring native cloud provisioning and management in Ansible with the publishing of this collection. In fact, we are committed to doing more to enhance and improve what is offered. If you really wanted to do something dynamic with native Terraform functions, an easier and safer means of dynamism driven by Ansible using Terraform is to dynamically generate Terraform variables using the template module and then apply your plan. I realize there are limits to that approach which leads me to another consideration. What I would recommend avoiding is complicated integration and interactions in whatever you dynamically generate for Terraform. In our experience, the stability and maintenance of an implementation like that will suffer without providing adequate value for the burden and risk. This is not something we intend to put into the project roadmap, but I'm going to leave this issue open for now. |
SUMMARY
At present, the Ansible Module
terraform
should be renamed asterraform_template_apply
which more appropriately describes the current capabilities. The Ansible Module within this Ansible Collection is a static execution of a pre-defined Terraform Template, it does not allow for any dynamic control by Ansiblefeat request: Ansible Playbook constructs should equal Terraform Template constructs
ISSUE TYPE
ADDITIONAL INFORMATION
By each Ansible Task acting as a construct for a Terraform Module, the Ansible Playbook achieves a level of parity with a Terraform Template. This allows Ansible to programatically/dynamically alter the desired infrastructure state being provisioned by Terraform.
By way of example, an Ansible Task might request
count
of a Terraform Module to provision equally OR might loop to re-use the same Terraform Module but executed each time with different inputs.It is not currently possible to treat each Ansible Task (within the Ansible Playbook) as if it were a Terraform Module Block call (within the Terraform Template).
See below as pseudocode example....
Terraform Template high-level design:
Ansible Playbook for executing Terraform Modules high-level proposed design:
The text was updated successfully, but these errors were encountered: