ansible / terraform-provider-ansible

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

ansible_playbook: unclear execution method #33

Open sean-freeman opened 1 year ago

sean-freeman commented 1 year ago

ansible_playbook: unclear execution method

Documentation:

[Required]
name (String) Name of the desired host on which the playbook will be executed.
playbook (String) Path to ansible playbook.

Clarity required:

Is name string referring to the Ansible Controller, the host on which the Ansible Playbook will be executed?

And the playbook string must be the path to the YAML file on the chosen Ansible Controller?

Therefore each Ansible Play hosts: will refer to groups of hosts which were dynamically created by the Terraform Resources ansible_group + ansible_host ?

If so, surely name should be replaced by ansible_controller_host to remove all doubt?

TL;DR

Clearer documentation required, and examples of different scenarios for executing Ansible Playbooks from where the Terraform execution is happening, from another host (i.e. Ansible Controller, which could be a bastion host or could be AWX etc etc).

tima commented 1 year ago

I'm having the engineers look at this.

Just to be clear this provisioner is only for local ansible-playbook execution. TF to AAP is not supported. AAP's containerized distributed architecture requires additional consideration and logic.

anazobec commented 1 year ago

Hi, in resource ansible_playbook, name does not refer a hostname dynamically created by ansible_host nor do groups refer to groups from ansible_group. Resource ansible_host and group are used separately to create a dynamic inventory which you then specify in your manually created inventory file with:

---
plugin: cloud.terraform.terraform_provider

Then you execute your ansible-playbook by providing this inventory file.

The name string is a hostname, which is used to create a basic temporary inventory ini file. If groups is also provided, then that hostnmae will be added to those groups. By default, there is only one group, named default. This temporary inventory can then be used upon executing the ansible playbook using ansible_playbook resource. (you must also set ansible_host to the same string as name (if that's the host you wish your playbook to be executed on).

For example, (in ansible_playbook resource), if you set name to my_hostname without also specifying groups, the temporary inventory created would then look like this:

[default]
my_hostname

If groups was also specified, for example ["my_group"], then the temporary inventory created would look like this:

[my_group]
my_hostname

If you do wish to use groups and hosts which were dynamically created by Terraform resources ansible_host and ansible_group, then (as explained at the top), you must create a custom inventory with the specified terraform_provider plugin and then pass that custom inventory into ansible_playbook resource using extra_vars.

For example: inventory.yml

---
plugin: cloud.terraform.terraform_provider

main.tf

resource "ansible_host" "my_host" {
  name = "my_host"
  groups = ["my_groups"]
  variables = {
     # ...
  }
}

resource "ansible_playbook" "my_playbook" {
  # ...
  extra_vars {
    ansible_host = ansible_host.my_host.name
    inventory_file = "path/to/inventory.yml"
  }
  # ...
}
sean-freeman commented 1 year ago

Hi @anazobec, thank you for a detailed explanation of the logic. This is good for documentation purposes.

However I would still strongly recommend that name variable for the Terraform Resource ansible_playbook is renamed.

See below a breakdown of the logical descriptors:

Perhaps ansible_playbook Terraform Resource for clarity purposes should use 3 non-overlapping variables for clarity:

See the documentation of binary ansible-playbook as an example:

-i INVENTORY, --inventory INVENTORY
        specify inventory host path or comma separated host list.
markfaine commented 1 year ago

This is very confusing. I've read it three times and I still don't think I understand it.

If someone could help me understand the intent of this provider I would appreciate it.

In my opinion, 99% (or probably 100%) of the use-case for ansible provider is to do the following:

  1. Allow for the generation of dynamic inventory from the hosts we have most likely just deployed.
  2. Newly created dynamic Inventory would also allow for the user to define groups and assign hosts to these groups
  3. Allow user to add arbitrary variables to hosts and/or groups
  4. Allow user to run an arbitrary playbook with at least the most common subset of ansible-playbook arguments specifying one or more hosts and/or groups.

From what I can tell this is not what this provider is meant for? If that's correct please explain further.

Thanks!

sean-freeman commented 1 year ago

@anazobec @tima

This needs to be addressed sooner than later. It heavily impacts initial user experience therefore limiting success, and has an exponential increase to technical debt as other code/projects or how-to guides/content are created based upon the initial releases (v1.0.0/v1.1.0).

It has been several months since this GH Issue was opened with no additional releases, this needs to be addressed urgently and trigger v1.2.0

msherman13 commented 1 year ago

if we use ansible_host and ansible_group resources, and then specify the inventory_file var in extra_vars under the ansible_playbook resource, what do we specify for the "name" argument which is required? the usage of this provider is not intuitive nor is the documentation sufficient on this topic

alleje02 commented 1 year ago

First off, thank you @anazobec for the time writing ansible_playbook, and taking the time to respond above.

Perhaps you could edit the above response or provide some clarity with an additional response?

Name is required as per the schema documentation. https://github.com/ansible/terraform-provider-ansible/blob/main/docs/resources/playbook.md

Can you please add what you would set "name =" to in this example since name is required?

resource "ansible_playbook" "my_playbook" {
  # ...
  extra_vars {
    ansible_host = ansible_host.my_host.name
    inventory_file = "path/to/inventory.yml"
  }
  # ...
}

In the other examples, I see simply:

name = "example"

Does this mean name within ansible_playbook resource is required but is just arbitrary text?

Is it the name terraform ties to the "playbook" construct when it writes it into the tfstate file?

For additional context, I am trying to run from GHA pipeline jobs/workflows from GH runners. So I want the GH runner to execute the ansible against the inventory generated from the cloud.terraform.terraform_provider inventory plugin.

Just need some clarity so everyone understands what "name" is here and how to use it correctly.

Thank you

dhilgarth commented 7 months ago

I don't think that this works as described by @anazobec The extra_vars will be passed as -e arguments to ansible-playbook.

So, given this resource:

resource "ansible_playbook" "install-docker-swarm" {
  extra_vars = {
    inventory_file     = "/src/constructs/AnsibleInventory.yaml"
    ansible_hostname   = "localhost"
    ansible_connection = "local"
  }
  ignore_playbook_failure = false
  name                    = "localhost"
  playbook                = "/src/constructs/DockerSwarmNodePlaybook.yaml"
}

will result in this call: ansible-playbook -e hostname=localhost -e ansible_hostname=localhost -e ansible_connection=local -e inventory_file=/src/constructs/AnsibleInventory.yaml /src/constructs/DockerSwarmNodePlaybook.yaml
Executing this doesn't use the specified inventory file. Instead, the inventory file should be specified with -i <inventory file>, but I see no way of making the provider actually do that. In fact, it creates a temporary inventory file which is totally useless when using our own dynamic inventory file.
My feeling is that the ansible_playbook is not meant to work together with the dynamic inventory created by ansible_host and ansible_group resources.

dhilgarth commented 7 months ago

Given these limitations, I've forked this repository. My fork introduces ansible_playbook2 which automatically generates and uses an inventory file as specified above, i.e. an inventory file with the cloud.terraform inventory plugin.

marshallford commented 5 months ago

I ran into this as well. It would seem this provider is best suited for defining an ansible inventory via ansible_host/ansible_group, but running Ansible outside of Terraform using the cloud.terraform.terraform_provider inventory plugin.

Given this issue and others I ended up writing a provider of my own, with a number of new features -- including the ability to run Ansible as a part of the Terraform lifecycle: https://github.com/marshallford/terraform-provider-ansible.