diff --git a/docs/data-sources/navigator_run.md b/docs/data-sources/navigator_run.md index bd11c4f..44f93df 100644 --- a/docs/data-sources/navigator_run.md +++ b/docs/data-sources/navigator_run.md @@ -3,16 +3,16 @@ page_title: "ansible_navigator_run Data Source - terraform-provider-ansible" subcategory: "" description: |- - Run an Ansible playbook. Recommended to only run playbooks without observable side-effects. Requires ansible-navigator and a container engine to run within an execution environment (EE). + Run an Ansible playbook as a means to gather information. It is recommended to only run playbooks without observable side-effects. Requires ansible-navigator and a container engine to run within an execution environment (EE). --- # ansible_navigator_run (Data Source) -Run an Ansible playbook. Recommended to only run playbooks without observable side-effects. Requires `ansible-navigator` and a container engine to run within an execution environment (EE). +Run an Ansible playbook as a means to gather information. It is recommended to only run playbooks without observable side-effects. Requires `ansible-navigator` and a container engine to run within an execution environment (EE). ## Example Usage -Additional examples available in `ansible_navigator_run` **resource** docs given the overlap in features/attributes. -That said, keep in mind the differences between a *data source* and *resource* when deciding which to use. +Additional examples available in the `ansible_navigator_run` **resource** docs given the overlap in available features. +That said, keep in mind the differences between *data sources* and *resources* when deciding which to use. ```terraform # 1. inline playbook and inventory @@ -92,7 +92,7 @@ output "resolv_conf" { Optional: - `force_handlers` (Boolean) Run handlers even if a task fails. -- `known_hosts` (List of String) SSH known host entries. Effectively a list of host public keys. Can help protect against man-in-the-middle attacks by verifying the identity of hosts. Ansible variable `ansible_ssh_known_hosts_file` set to path of `known_hosts` file. +- `known_hosts` (List of String) SSH known host entries. Can help protect against man-in-the-middle attacks by verifying the identity of hosts. Ansible variable `ansible_ssh_known_hosts_file` set to path of `known_hosts` file. If unspecified will be set to contents of `known_hosts` file after run. - `limit` (List of String) Further limit selected hosts to an additional pattern. - `private_keys` (Attributes List) SSH private keys used for authentication in addition to the [automatically mounted](https://ansible.readthedocs.io/projects/navigator/faq/#how-do-i-use-my-ssh-keys-with-an-execution-environment) default named keys and SSH agent socket path. (see [below for nested schema](#nestedatt--ansible_options--private_keys)) - `skip_tags` (List of String) Only run plays and tasks whose tags do not match these values. diff --git a/docs/index.md b/docs/index.md index 1b241cf..251ba77 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,16 +1,65 @@ --- # tfplugindocs generate --website-temp-dir /tmp/docs # generated by https://github.com/hashicorp/terraform-plugin-docs -page_title: "ansible Provider" +page_title: Ansible Provider description: |- - Run Ansible https://github.com/ansible/ansible playbooks using Terraform. + Run Ansible https://github.com/ansible/ansible playbooks. --- -# ansible Provider +# Ansible Provider -Run [Ansible](https://github.com/ansible/ansible) playbooks using Terraform. +Run [Ansible](https://github.com/ansible/ansible) playbooks. -## Example Usage +```terraform +resource "ansible_navigator_run" "webservers_example" { + playbook = <<-EOT + - name: Example + hosts: webservers + tasks: + - name: Install nginx + ansible.builtin.package: + name: nginx + EOT + inventory = yamlencode({ + webservers = { + hosts = { + a = { ansible_host = "webserver-a.example.com" } + } + } + }) +} + +data "ansible_navigator_run" "uptime_example" { + playbook = <<-EOT + - name: Example + hosts: all + EOT + inventory = yamlencode({}) + artifact_queries = { + "uptimes" = { + jq_filter = <<-EOT + [.plays[] | select(.name=="Example") | .tasks[] | select(.task=="Gathering Facts") | + {host: .host, uptime_seconds: .res.ansible_facts.ansible_uptime_seconds }] + EOT + } + } +} + +output "uptimes" { + value = jsondecode(data.ansible_navigator_run.uptime_example.artifact_queries.uptimes.results[0]) +} +``` + +## Features + +1. Run Ansible playbooks against Terraform managed infrastructure (without the `local-exec` provisioner). Eliminates the need for additional scripting or pipeline steps. +2. Construct Ansible inventories using other data sources and resources. Set Ansible host and group variables to values and secrets from other providers. +3. Utilize Ansible [execution environments](https://ansible.readthedocs.io/en/latest/getting_started_ee/index.html) (containers images) to customize and run the Ansible software stack. Isolate Ansible and its related dependencies (Python/System packages, collections, etc) to simplify pipeline and workstation setup. +4. Write [`jq`](https://jqlang.github.io/jq/) queries against [playbook artifacts](https://access.redhat.com/documentation/en-us/red_hat_ansible_automation_platform/2.0-ea/html/ansible_navigator_creator_guide/assembly-troubleshooting-navigator_ansible-navigator#proc-review-artifact_troubleshooting-navigator). Extract values from the playbook run for use elsewhere in the Terraform configuration. Examples include: Ansible facts, remote file contents, task results -- the possibilities are endless! +5. Control playbook re-run behavior using several "lifecycle" options, including an attribute for running the playbook on resource destruction. Implement conditional plays/tasks with the environment variable `ANSIBLE_TF_OPERATION`. +6. Connect to hosts securely by specifying SSH private keys and known host entries. No need manage `~/.ssh` files or setup `ssh-agent` in the environment which Terraform runs. + +## Example Provider Usage ```terraform # defaults diff --git a/docs/resources/navigator_run.md b/docs/resources/navigator_run.md index 7fc6b62..ebad78d 100644 --- a/docs/resources/navigator_run.md +++ b/docs/resources/navigator_run.md @@ -215,7 +215,7 @@ pipelining=True Optional: - `force_handlers` (Boolean) Run handlers even if a task fails. -- `known_hosts` (List of String) SSH known host entries. Effectively a list of host public keys. Can help protect against man-in-the-middle attacks by verifying the identity of hosts. Ansible variable `ansible_ssh_known_hosts_file` set to path of `known_hosts` file. +- `known_hosts` (List of String) SSH known host entries. Can help protect against man-in-the-middle attacks by verifying the identity of hosts. Ansible variable `ansible_ssh_known_hosts_file` set to path of `known_hosts` file. If unspecified will be set to contents of `known_hosts` file after run. - `limit` (List of String) Further limit selected hosts to an additional pattern. - `private_keys` (Attributes List) SSH private keys used for authentication in addition to the [automatically mounted](https://ansible.readthedocs.io/projects/navigator/faq/#how-do-i-use-my-ssh-keys-with-an-execution-environment) default named keys and SSH agent socket path. (see [below for nested schema](#nestedatt--ansible_options--private_keys)) - `skip_tags` (List of String) Only run plays and tasks whose tags do not match these values. diff --git a/internal/provider/navigator_run_data_source.go b/internal/provider/navigator_run_data_source.go index a1d4442..8717ee4 100644 --- a/internal/provider/navigator_run_data_source.go +++ b/internal/provider/navigator_run_data_source.go @@ -193,8 +193,8 @@ func (d *NavigatorRunDataSource) Metadata(ctx context.Context, req datasource.Me func (d *NavigatorRunDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { resp.Schema = schema.Schema{ - Description: fmt.Sprintf("Run an Ansible playbook. Recommended to only run playbooks without observable side-effects. Requires '%s' and a container engine to run within an execution environment (EE).", ansible.NavigatorProgram), - MarkdownDescription: fmt.Sprintf("Run an Ansible playbook. Recommended to only run playbooks without observable side-effects. Requires `%s` and a container engine to run within an execution environment (EE).", ansible.NavigatorProgram), + Description: fmt.Sprintf("Run an Ansible playbook as a means to gather information. It is recommended to only run playbooks without observable side-effects. Requires '%s' and a container engine to run within an execution environment (EE).", ansible.NavigatorProgram), + MarkdownDescription: fmt.Sprintf("Run an Ansible playbook as a means to gather information. It is recommended to only run playbooks without observable side-effects. Requires `%s` and a container engine to run within an execution environment (EE).", ansible.NavigatorProgram), Attributes: map[string]schema.Attribute{ // required "playbook": schema.StringAttribute{ @@ -378,8 +378,8 @@ func (d *NavigatorRunDataSource) Schema(ctx context.Context, req datasource.Sche }, }, "known_hosts": schema.ListAttribute{ - Description: fmt.Sprintf("SSH known host entries. Effectively a list of host public keys. Can help protect against man-in-the-middle attacks by verifying the identity of hosts. Ansible variable '%s' set to path of 'known_hosts' file.", ansible.SSHKnownHostsFileVar), - MarkdownDescription: fmt.Sprintf("SSH known host entries. Effectively a list of host public keys. Can help protect against man-in-the-middle attacks by verifying the identity of hosts. Ansible variable `%s` set to path of `known_hosts` file.", ansible.SSHKnownHostsFileVar), + Description: fmt.Sprintf("SSH known host entries. Can help protect against man-in-the-middle attacks by verifying the identity of hosts. Ansible variable '%s' set to path of 'known_hosts' file. If unspecified will be set to contents of 'known_hosts' file after run.", ansible.SSHKnownHostsFileVar), + MarkdownDescription: fmt.Sprintf("SSH known host entries. Can help protect against man-in-the-middle attacks by verifying the identity of hosts. Ansible variable `%s` set to path of `known_hosts` file. If unspecified will be set to contents of `known_hosts` file after run.", ansible.SSHKnownHostsFileVar), Optional: true, Computed: true, ElementType: types.StringType, diff --git a/internal/provider/navigator_run_resource.go b/internal/provider/navigator_run_resource.go index f2178a6..348531d 100644 --- a/internal/provider/navigator_run_resource.go +++ b/internal/provider/navigator_run_resource.go @@ -341,8 +341,8 @@ func (r *NavigatorRunResource) Schema(ctx context.Context, req resource.SchemaRe }, }, "known_hosts": schema.ListAttribute{ - Description: fmt.Sprintf("SSH known host entries. Effectively a list of host public keys. Can help protect against man-in-the-middle attacks by verifying the identity of hosts. Ansible variable '%s' set to path of 'known_hosts' file.", ansible.SSHKnownHostsFileVar), - MarkdownDescription: fmt.Sprintf("SSH known host entries. Effectively a list of host public keys. Can help protect against man-in-the-middle attacks by verifying the identity of hosts. Ansible variable `%s` set to path of `known_hosts` file.", ansible.SSHKnownHostsFileVar), + Description: fmt.Sprintf("SSH known host entries. Can help protect against man-in-the-middle attacks by verifying the identity of hosts. Ansible variable '%s' set to path of 'known_hosts' file. If unspecified will be set to contents of 'known_hosts' file after run.", ansible.SSHKnownHostsFileVar), + MarkdownDescription: fmt.Sprintf("SSH known host entries. Can help protect against man-in-the-middle attacks by verifying the identity of hosts. Ansible variable `%s` set to path of `known_hosts` file. If unspecified will be set to contents of `known_hosts` file after run.", ansible.SSHKnownHostsFileVar), Optional: true, Computed: true, ElementType: types.StringType, diff --git a/internal/provider/provider.go b/internal/provider/provider.go index a3626ec..9f31d3c 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -36,8 +36,8 @@ func (p *AnsibleProvider) Metadata(ctx context.Context, req provider.MetadataReq func (p *AnsibleProvider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) { resp.Schema = schema.Schema{ - Description: "Run Ansible playbooks using Terraform.", - MarkdownDescription: "Run [Ansible](https://github.com/ansible/ansible) playbooks using Terraform.", + Description: "Run Ansible playbooks.", + MarkdownDescription: "Run [Ansible](https://github.com/ansible/ansible) playbooks.", Attributes: map[string]schema.Attribute{ "base_run_directory": schema.StringAttribute{ Description: "Base directory in which to create run directories. On Unix systems this defaults to '$TMPDIR' if non-empty, else '/tmp'.", diff --git a/requirements.txt b/requirements.txt index a267c92..885cd0a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ ansible-builder==3.1.0 -ansible-navigator==24.7.0 +ansible-navigator==24.8.0 ansible-lint==24.7.0 diff --git a/templates/data-sources/navigator_run.md.tmpl b/templates/data-sources/navigator_run.md.tmpl index fb31aa7..2466cdd 100644 --- a/templates/data-sources/navigator_run.md.tmpl +++ b/templates/data-sources/navigator_run.md.tmpl @@ -12,8 +12,8 @@ description: |- {{ if .HasExample -}} ## Example Usage -Additional examples available in `ansible_navigator_run` **resource** docs given the overlap in features/attributes. -That said, keep in mind the differences between a *data source* and *resource* when deciding which to use. +Additional examples available in the `ansible_navigator_run` **resource** docs given the overlap in available features. +That said, keep in mind the differences between *data sources* and *resources* when deciding which to use. {{tffile .ExampleFile }} {{- end }} diff --git a/templates/index.md.tmpl b/templates/index.md.tmpl index c51c642..5552406 100644 --- a/templates/index.md.tmpl +++ b/templates/index.md.tmpl @@ -1,17 +1,66 @@ --- # tfplugindocs generate --website-temp-dir /tmp/docs # generated by https://github.com/hashicorp/terraform-plugin-docs -page_title: "{{.ProviderShortName}} Provider" +page_title: Ansible Provider description: |- {{ .Description | plainmarkdown | trimspace | prefixlines " " }} --- -# {{.ProviderShortName}} Provider +# Ansible Provider {{ .Description | trimspace }} +```terraform +resource "ansible_navigator_run" "webservers_example" { + playbook = <<-EOT + - name: Example + hosts: webservers + tasks: + - name: Install nginx + ansible.builtin.package: + name: nginx + EOT + inventory = yamlencode({ + webservers = { + hosts = { + a = { ansible_host = "webserver-a.example.com" } + } + } + }) +} + +data "ansible_navigator_run" "uptime_example" { + playbook = <<-EOT + - name: Example + hosts: all + EOT + inventory = yamlencode({}) + artifact_queries = { + "uptimes" = { + jq_filter = <<-EOT + [.plays[] | select(.name=="Example") | .tasks[] | select(.task=="Gathering Facts") | + {host: .host, uptime_seconds: .res.ansible_facts.ansible_uptime_seconds }] + EOT + } + } +} + +output "uptimes" { + value = jsondecode(data.ansible_navigator_run.uptime_example.artifact_queries.uptimes.results[0]) +} +``` + +## Features + +1. Run Ansible playbooks against Terraform managed infrastructure (without the `local-exec` provisioner). Eliminates the need for additional scripting or pipeline steps. +2. Construct Ansible inventories using other data sources and resources. Set Ansible host and group variables to values and secrets from other providers. +3. Utilize Ansible [execution environments](https://ansible.readthedocs.io/en/latest/getting_started_ee/index.html) (containers images) to customize and run the Ansible software stack. Isolate Ansible and its related dependencies (Python/System packages, collections, etc) to simplify pipeline and workstation setup. +4. Write [`jq`](https://jqlang.github.io/jq/) queries against [playbook artifacts](https://access.redhat.com/documentation/en-us/red_hat_ansible_automation_platform/2.0-ea/html/ansible_navigator_creator_guide/assembly-troubleshooting-navigator_ansible-navigator#proc-review-artifact_troubleshooting-navigator). Extract values from the playbook run for use elsewhere in the Terraform configuration. Examples include: Ansible facts, remote file contents, task results -- the possibilities are endless! +5. Control playbook re-run behavior using several "lifecycle" options, including an attribute for running the playbook on resource destruction. Implement conditional plays/tasks with the environment variable `ANSIBLE_TF_OPERATION`. +6. Connect to hosts securely by specifying SSH private keys and known host entries. No need manage `~/.ssh` files or setup `ssh-agent` in the environment which Terraform runs. + {{ if .HasExample -}} -## Example Usage +## Example Provider Usage {{tffile .ExampleFile }} {{- end }}