ansible / terraform-provider-ansible

community terraform provider for ansible
https://registry.terraform.io/providers/ansible/ansible/latest
GNU General Public License v3.0
183 stars 42 forks source link

Support lists and maps in ansible_group and ansible_host variables #49

Open EugenFo opened 1 year ago

EugenFo commented 1 year ago

Hey there, we have found out that this provider only accepts strings in the variables field in ansible_group and ansible_host.

map example:

resource "ansible_group" "all" {
  name = "all"
  variables = {
    simple_map = {
      key = "value"
    }
  }
}

Error:

╷
│ Error: Incorrect attribute value type
│ 
│   on ansible_output.tf line 29, in resource "ansible_group" "all":
│   29:   variables = {
│   30:     simple_map = {
│   31:       key = "value"
│   32:     }
│   33:   }
│ 
│ Inappropriate value for attribute "variables": element "simple_map": string required.
╵

Our current workaround for this is using the jsonencode function in terraform.

resource "ansible_group" "all" {
  name = "all"
  variables = {
    simple_map = jsonencode({
      key = "value"
    })
  }
}

However this workaround has it's limitations eg. using the combine() function to merge some dicts together. Terraform saves simple_map as an string and combine() will fail as it can't combine/merge an dict/map with an string.

Another example for this issue: terraform:

resource "ansible_group" "all" {
  name = "all"
  variables = {
    patch_telegraf = jsonencode({
      inputs = "just_a_test"
    })
  }
}

ansible:

- name: TELEGRAF | Combine telegraf defaults with patched values
  ansible.builtin.set_fact:
    telegraf: "{{ default_telegraf | combine(patch_telegraf, recursive=True) }}"

Error:

fatal: [testvm]: FAILED! => {"msg": "failed to combine variables, expected dicts but got a 'dict' and a 'str': \n{\"global_tags\": {\"resource_type\": null, \"cloud\": null, \"project\": null}, \"version\": \"1.2*\", \"agent\": {\"interval\": \"10s\", \"round_interval\": true, \"metric_batch_size\": 1000, \"metric_buffer_limit\": 10000, \"collection_jitter\": \"0s\", \"flush_interval\": \"10s\", \"flush_jitter\": \"0s\", \"precision\": \"1s\", \"logfile_rotation_max_archives\": 5, \"hostname\": \"\", \"omit_hostname\": false}, \"outputs\": {\"thanos\": {\"enabled\": false, \"url\": null, \"insecure_skip_verify\": false}}, \"inputs\": {\"snmp\": {\"enabled\": false, \"cisco\": {\"enabled\": false}}, \"bind\": {\"enabled\": false}, \"docker\": {\"enabled\": false}, \"iptables\": {\"enabled\": false}, \"rabbitmq\": {\"enabled\": false}, \"postgres\": {\"enabled\": false}, \"net\": {\"enabled\": false}, \"openldap\": {\"enabled\": false}, \"bcache\": {\"enabled\": false}, \"ipvs\": {\"enabled\": false}, \"vmware\": {\"enabled\": false}, \"prometheus\": {\"enabled\": false}, \"ntpq\": {\"enabled\": false}, \"mdstat\": {\"enabled\": false}}}\n\"{\\\"inputs\\\":\\\"just_a_test\\\"}\""}

For this issue we have also an workaround. Using | from_json in the combine() function will convert the string into an dict/map again and the merge will work again.

- name: TELEGRAF | Combine telegraf defaults with patched values
  ansible.builtin.set_fact:
    telegraf: "{{ default_telegraf | combine(patch_telegraf | from_json, recursive=True) }}"

It is really sad that this provider doesn't support Maps or Lists in the variables field. It would be really helpful for us as we don't need to implement any of those workarounds to deal with different variable types.

Thanks!

rubencosta commented 11 months ago

I was running into the same issue, so I ended up forking this repo. If you're just looking for a way to run ansible from terraform check out https://registry.terraform.io/providers/rubencosta/ansible/